Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrés Ambrois <andresambrois@gmail.com>2010-05-11 16:45:18 (GMT)
committer Andrés Ambrois <andresambrois@gmail.com>2010-05-11 16:45:18 (GMT)
commite434d5d7ecde8db0e24fd7284769509edff835f2 (patch)
treef51964e654e5ff5390abc1a36bb139a98b5b74b5
Initial commitHEADmaster
-rw-r--r--activity/activity-secuencia.svg103
-rw-r--r--activity/activity.info9
-rwxr-xr-xmultimedia.py252
-rw-r--r--secuencia.py147
-rwxr-xr-xsetup.py22
5 files changed, 533 insertions, 0 deletions
diff --git a/activity/activity-secuencia.svg b/activity/activity-secuencia.svg
new file mode 100644
index 0000000..ec0bcdd
--- /dev/null
+++ b/activity/activity-secuencia.svg
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY ns_svg "http://www.w3.org/2000/svg">
+ <!ENTITY ns_xlink " http://www.w3.org/1999/xlink">
+ <!ENTITY stroke_color "#010101">
+ <!ENTITY fill_color "#FFFFFF">
+ ]>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ enable-background="new 0 0 55 55"
+ height="55px"
+ version="1.1"
+ viewBox="0 0 55 55"
+ width="55px"
+ x="0px"
+ xml:space="preserve"
+ y="0px"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ sodipodi:docname="activity-go.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ sodipodi:docbase="/home/gjpc/PlayGo/PlayGo/src/activity"><metadata
+ id="metadata26"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs24" /><sodipodi:namedview
+ inkscape:window-height="619"
+ inkscape:window-width="872"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#ffffff"
+ pagecolor="#ffffff"
+ id="base"
+ inkscape:zoom="7.3818182"
+ inkscape:cx="27.5"
+ inkscape:cy="27.5"
+ inkscape:window-x="26"
+ inkscape:window-y="59"
+ inkscape:current-layer="svg2" /><g
+ display="block"
+ id="activity-connect"
+ transform="translate(-0.5418719,-1.2192118)"
+ style="display:block">
+ <g
+ display="inline"
+ id="g5"
+ style="display:inline">
+ <path
+ d="M 14.118,9.535 C 14.119,11.967 12.148,13.94 9.716,13.941 C 7.283,13.942 5.311,11.971 5.31,9.539 C 5.31,9.538 5.31,9.536 5.31,9.535 C 5.308,7.103 7.279,5.13 9.711,5.128 C 12.143,5.127 14.116,7.098 14.117,9.53 C 14.118,9.532 14.118,9.534 14.118,9.535 z "
+ id="path2160" fill="&fill_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 51.188,9.535 C 51.19,11.967 49.219,13.94 46.786,13.941 C 44.354,13.942 42.382,11.971 42.38,9.539 C 42.38,9.538 42.38,9.536 42.38,9.535 C 42.38,7.102 44.351,5.13 46.782,5.128 C 49.216,5.127 51.188,7.098 51.188,9.53 C 51.188,9.532 51.188,9.534 51.188,9.535 z "
+ id="path2162" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 26.475,9.535 C 26.475,11.967 24.504,13.94 22.072,13.941 C 19.639,13.942 17.667,11.971 17.665,9.539 C 17.665,9.538 17.665,9.536 17.665,9.535 C 17.664,7.102 19.635,5.13 22.067,5.128 C 24.5,5.127 26.472,7.098 26.474,9.53 C 26.475,9.532 26.475,9.534 26.475,9.535 z "
+ id="path3134" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 38.832,9.535 C 38.832,11.967 36.861,13.94 34.43,13.941 C 31.996,13.942 30.024,11.971 30.022,9.539 C 30.022,9.538 30.022,9.536 30.022,9.535 C 30.022,7.102 31.993,5.13 34.424,5.128 C 36.858,5.127 38.83,7.098 38.832,9.53 C 38.832,9.532 38.832,9.534 38.832,9.535 z "
+ id="path3136" fill="&fill_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 26.475,21.892 C 26.475,24.325 24.504,26.297 22.072,26.298 C 19.639,26.299 17.667,24.328 17.665,21.896 C 17.665,21.895 17.665,21.893 17.665,21.892 C 17.664,19.459 19.635,17.487 22.067,17.485 C 24.5,17.484 26.472,19.455 26.474,21.887 C 26.475,21.889 26.475,21.891 26.475,21.892 z "
+ id="path3138" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 38.832,21.892 C 38.832,24.325 36.861,26.297 34.43,26.298 C 31.996,26.299 30.024,24.328 30.022,21.896 C 30.022,21.895 30.022,21.893 30.022,21.892 C 30.022,19.459 31.993,17.487 34.424,17.485 C 36.858,17.484 38.83,19.455 38.832,21.887 C 38.832,21.889 38.832,21.891 38.832,21.892 z "
+ id="path3140" fill="&fill_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 14.118,21.892 C 14.119,24.325 12.148,26.297 9.716,26.298 C 7.284,26.299 5.311,24.328 5.31,21.896 C 5.31,21.895 5.31,21.893 5.31,21.892 C 5.309,19.459 7.28,17.487 9.712,17.485 C 12.144,17.484 14.117,19.455 14.118,21.887 C 14.118,21.889 14.118,21.891 14.118,21.892 z "
+ id="path3142" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 51.188,21.892 C 51.19,24.325 49.219,26.297 46.786,26.298 C 44.354,26.299 42.382,24.328 42.38,21.896 C 42.38,21.895 42.38,21.893 42.38,21.892 C 42.38,19.459 44.351,17.487 46.782,17.485 C 49.216,17.484 51.188,19.455 51.188,21.887 C 51.188,21.889 51.188,21.891 51.188,21.892 z "
+ id="path3144" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 14.118,34.248 C 14.119,36.68 12.148,38.652 9.716,38.654 C 7.283,38.655 5.311,36.684 5.31,34.252 C 5.31,34.25 5.31,34.249 5.31,34.248 C 5.309,31.815 7.28,29.843 9.712,29.842 C 12.144,29.84 14.117,31.811 14.118,34.244 C 14.118,34.245 14.118,34.246 14.118,34.248 z "
+ id="path3146" fill="&fill_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 38.832,34.248 C 38.832,36.68 36.861,38.652 34.43,38.654 C 31.996,38.655 30.024,36.684 30.022,34.252 C 30.022,34.25 30.022,34.249 30.022,34.248 C 30.022,31.815 31.993,29.843 34.424,29.842 C 36.858,29.84 38.83,31.811 38.832,34.244 C 38.832,34.245 38.832,34.246 38.832,34.248 z "
+ id="path3152" fill="&fill_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 38.832,46.604 C 38.832,49.038 36.861,51.01 34.43,51.011 C 31.996,51.012 30.024,49.041 30.022,46.609 C 30.022,46.608 30.022,46.606 30.022,46.604 C 30.022,44.172 31.993,42.2 34.424,42.198 C 36.858,42.198 38.83,44.169 38.832,46.6 C 38.832,46.602 38.832,46.603 38.832,46.604 z "
+ id="path3154" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 14.118,46.604 C 14.119,49.038 12.148,51.01 9.716,51.011 C 7.284,51.012 5.311,49.041 5.31,46.609 C 5.31,46.608 5.31,46.606 5.31,46.604 C 5.309,44.172 7.28,42.2 9.712,42.198 C 12.144,42.198 14.117,44.169 14.118,46.6 C 14.118,46.602 14.118,46.603 14.118,46.604 z "
+ id="path3156" fill="&fill_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 26.475,46.604 C 26.475,49.038 24.504,51.01 22.072,51.011 C 19.639,51.012 17.667,49.041 17.665,46.609 C 17.665,46.608 17.665,46.606 17.665,46.604 C 17.664,44.172 19.635,42.2 22.067,42.198 C 24.5,42.198 26.472,44.169 26.474,46.6 C 26.475,46.602 26.475,46.603 26.475,46.604 z "
+ id="path3158" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ <path
+ d="M 51.188,46.604 C 51.19,49.038 49.219,51.01 46.786,51.011 C 44.354,51.012 42.382,49.041 42.38,46.609 C 42.38,46.608 42.38,46.606 42.38,46.604 C 42.38,44.172 44.351,42.2 46.782,42.198 C 49.216,42.198 51.188,44.169 51.188,46.6 C 51.188,46.602 51.188,46.603 51.188,46.604 z "
+ id="path3160" fill="&stroke_color;" stroke="&stroke_color;" stroke-width="2.25;" />
+ </g>
+</g></svg>
diff --git a/activity/activity.info b/activity/activity.info
new file mode 100644
index 0000000..f39b4c4
--- /dev/null
+++ b/activity/activity.info
@@ -0,0 +1,9 @@
+[Activity]
+name = Secuencia
+license = GPLv2+
+bundle_id = org.ceibaljam.Secuencia
+exec = sugar-activity secuencia.Secuencia
+icon = activity-secuencia
+activity_version = 1
+host_version = 1
+show_launcher = no
diff --git a/multimedia.py b/multimedia.py
new file mode 100755
index 0000000..34ab734
--- /dev/null
+++ b/multimedia.py
@@ -0,0 +1,252 @@
+#!/usr/bin/python
+# Copyright (c) 2010, CeibalJam!
+# 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 gst
+import gobject
+import gtk
+
+import logging
+logger = logging.getLogger('secuencia: ' + __file__)
+
+class AudioPlayer(object):
+ def __init__(self):
+ self.player = gst.element_factory_make('playbin')
+ fakesink = gst.element_factory_make('fakesink')
+ self.player.set_property("video-sink", fakesink)
+
+ bus = self.player.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', self._gstmessage_cb)
+
+ self.playing = False
+
+ def play(self, file):
+ self.player.set_state(gst.STATE_NULL)
+ self.player.props.uri = 'file://' + file
+ self.player.set_state(gst.STATE_PLAYING)
+ self.playing = True
+
+ def _gstmessage_cb(self, bus, message):
+ if message.type == gst.MESSAGE_EOS:
+ self.player.set_state(gst.STATE_NULL)
+ self.playing = False
+ elif message.type == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logger.error('play_pipe: %s %s' % (err, debug))
+ self.player.set_state(gst.STATE_NULL)
+ self.playing = False
+
+class GstPlayer(gobject.GObject):
+ __gsignals__ = {
+ 'error': (gobject.SIGNAL_RUN_FIRST, None, [str, str]),
+ 'eos' : (gobject.SIGNAL_RUN_FIRST, None, []),
+ 'tag' : (gobject.SIGNAL_RUN_FIRST, None, [str, str]),
+ 'stream-info' : (gobject.SIGNAL_RUN_FIRST, None, [object])
+ }
+
+ def __init__(self, videowidget):
+ gobject.GObject.__init__(self)
+
+ self.playing = False
+ self.error = False
+
+ self.player = gst.element_factory_make("playbin", "player")
+
+ r = gst.registry_get_default()
+ l = [x for x in r.get_feature_list(gst.ElementFactory) if (gst.ElementFactory.get_klass(x) == "Visualization")]
+ if len(l):
+ e = l.pop() # take latest plugin in the list
+ vis_plug = gst.element_factory_make(e.get_name())
+ self.player.set_property('vis-plugin', vis_plug)
+
+ self.overlay = None
+ self.videowidget = videowidget
+ self._init_video_sink()
+
+ bus = self.player.get_bus()
+ bus.enable_sync_message_emission()
+ bus.add_signal_watch()
+ bus.connect('sync-message::element', self.on_sync_message)
+ bus.connect('message', self.on_message)
+
+ def set_uri(self, uri):
+ self.player.set_property('uri', uri)
+
+ def on_sync_message(self, bus, message):
+ if message.structure is None:
+ return
+ if message.structure.get_name() == 'prepare-xwindow-id':
+ self.videowidget.set_sink(message.src)
+ message.src.set_property('force-aspect-ratio', True)
+
+ def on_message(self, bus, message):
+ t = message.type
+ if t == gst.MESSAGE_ERROR:
+ err, debug = message.parse_error()
+ logging.debug("Error: %s - %s" % (err, debug))
+ self.error = True
+ self.emit("eos")
+ self.playing = False
+ self.emit("error", str(err), str(debug))
+ elif t == gst.MESSAGE_EOS:
+ self.emit("eos")
+ self.playing = False
+ elif t == gst.MESSAGE_TAG:
+ tags = message.parse_tag()
+ for tag in tags.keys():
+ self.emit('tag', str(tag), str(tags[tag]))
+ elif t == gst.MESSAGE_STATE_CHANGED:
+ old, new, pen = message.parse_state_changed()
+ if old == gst.STATE_READY and new == gst.STATE_PAUSED:
+ self.emit('stream-info', self.player.props.stream_info_value_array)
+
+ def _init_video_sink(self):
+ self.bin = gst.Bin()
+ videoscale = gst.element_factory_make('videoscale')
+ self.bin.add(videoscale)
+ pad = videoscale.get_pad("sink")
+ ghostpad = gst.GhostPad("sink", pad)
+ self.bin.add_pad(ghostpad)
+ videoscale.set_property("method", 0)
+
+ caps_string = "video/x-raw-yuv, "
+ r = self.videowidget.get_allocation()
+ if r.width > 500 and r.height > 500:
+ # Sigh... xvimagesink on the XOs will scale the video to fit
+ # but ximagesink in Xephyr does not. So we live with unscaled
+ # video in Xephyr so that the XO can work right.
+ w = 480
+ h = float(w) / float(float(r.width) / float(r.height))
+ caps_string += "width=%d, height=%d" % (w, h)
+ else:
+ caps_string += "width=480, height=360"
+ caps = gst.Caps(caps_string)
+ self.filter = gst.element_factory_make("capsfilter", "filter")
+ self.bin.add(self.filter)
+ self.filter.set_property("caps", caps)
+
+ textoverlay = gst.element_factory_make('textoverlay')
+ self.overlay = textoverlay
+ self.bin.add(textoverlay)
+ conv = gst.element_factory_make ("ffmpegcolorspace", "conv");
+ self.bin.add(conv)
+ videosink = gst.element_factory_make('autovideosink')
+ self.bin.add(videosink)
+ gst.element_link_many(videoscale, self.filter, textoverlay, conv, videosink)
+ self.player.set_property("video-sink", self.bin)
+
+ def set_overlay(self, title, artist, album):
+ text = "%s\n%s" % (title, artist)
+ if album and len(album):
+ text += "\n%s" % album
+ self.overlay.set_property("text", text)
+ self.overlay.set_property("font-desc", "sans bold 14")
+ self.overlay.set_property("halignment", "right")
+ self.overlay.set_property("valignment", "bottom")
+ try:
+ # Only in OLPC versions of gstreamer-plugins-base for now
+ self.overlay.set_property("line-align", "left")
+ except:
+ pass
+
+ def query_position(self):
+ "Returns a (position, duration) tuple"
+ try:
+ position, format = self.player.query_position(gst.FORMAT_TIME)
+ except:
+ position = gst.CLOCK_TIME_NONE
+
+ try:
+ duration, format = self.player.query_duration(gst.FORMAT_TIME)
+ except:
+ duration = gst.CLOCK_TIME_NONE
+
+ return (position, duration)
+
+ def seek(self, location):
+ """
+ @param location: time to seek to, in nanoseconds
+ """
+ event = gst.event_new_seek(1.0, gst.FORMAT_TIME,
+ gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
+ gst.SEEK_TYPE_SET, location,
+ gst.SEEK_TYPE_NONE, 0)
+
+ res = self.player.send_event(event)
+ if res:
+ self.player.set_new_stream_time(0L)
+ else:
+ logging.debug("seek to %r failed" % location)
+
+ def pause(self):
+ logging.debug("pausing player")
+ self.player.set_state(gst.STATE_PAUSED)
+ self.playing = False
+
+ def play(self):
+ logging.debug("playing player")
+ self.player.set_state(gst.STATE_PLAYING)
+ self.playing = True
+ self.error = False
+
+ def stop(self):
+ self.player.set_state(gst.STATE_NULL)
+ logging.debug("stopped player")
+
+ def get_state(self, timeout=1):
+ return self.player.get_state(timeout=timeout)
+
+ def is_playing(self):
+ return self.playing
+
+class VideoWidget(gtk.DrawingArea):
+ def __init__(self):
+ gtk.DrawingArea.__init__(self)
+ self.set_events(gtk.gdk.POINTER_MOTION_MASK |
+ gtk.gdk.POINTER_MOTION_HINT_MASK |
+ gtk.gdk.EXPOSURE_MASK |
+ gtk.gdk.KEY_PRESS_MASK |
+ gtk.gdk.KEY_RELEASE_MASK)
+ self.imagesink = None
+ self.unset_flags(gtk.DOUBLE_BUFFERED)
+ self.set_flags(gtk.APP_PAINTABLE)
+
+ def do_expose_event(self, event):
+ if self.imagesink:
+ self.imagesink.expose()
+ return False
+ else:
+ return True
+
+ def set_sink(self, sink):
+ assert self.window.xid
+ self.imagesink = sink
+ self.imagesink.set_xwindow_id(self.window.xid)
+
+if __name__ == '__main__':
+ import sys
+ w = gtk.Window()
+ w.set_size_request(800,600)
+ view = VideoWidget()
+
+ player = GstPlayer(view)
+ w.add(view)
+ w.connect('destroy', lambda w: gtk.main_quit())
+ w.show_all()
+ print "Playing " + sys.argv[1]
+ player.set_uri(sys.argv[1])
+ player.play()
+ gtk.main()
diff --git a/secuencia.py b/secuencia.py
new file mode 100644
index 0000000..04fdc7c
--- /dev/null
+++ b/secuencia.py
@@ -0,0 +1,147 @@
+from sugar.activity import activity
+from sugar.graphics.toolbarbox import ToolbarBox
+from sugar.graphics.objectchooser import ObjectChooser
+from sugar.datastore import datastore
+from sugar import mime
+from sugar.logger import logging
+from gettext import gettext as _
+import gtk
+import os
+import statvfs
+import zipfile
+import gio
+
+
+ACTION_ICONS = {
+ 'sound' : gtk.STOCK_MEDIA_PLAY,
+ 'video' : gtk.STOCK_MEDIA_PLAY,
+ 'next' : gtk.STOCK_GO_FORWARD,
+}
+
+class Secuencia(activity.Activity):
+ def __init__(self, handle):
+ activity.Activity.__init__(self, handle)
+
+ self.toolbox = activity.ActivityToolbox(self)
+ self.set_toolbox(self.toolbox)
+ self.toolbox.show()
+
+ main_box = gtk.VBox()
+
+ frame = gtk.Frame()
+ main_box.pack_start(frame)
+ frame.show()
+
+ frame_vbox = gtk.VBox()
+ frame.add(frame_vbox)
+ frame_vbox.show()
+
+ self.text = gtk.Label()
+ frame_vbox.pack_start(self.text)
+ self.text.show()
+
+ self.image = gtk.Image()
+ frame_vbox.pack_start(self.image)
+ self.image.show()
+
+ self.action_icon = gtk.Image()
+ main_box.pack_start(self.action_icon, False)
+ self.action_icon.show()
+
+ self.set_canvas(main_box)
+ main_box.show()
+
+ # A list of (filename, mimetype) tuples
+ self.list = []
+ self.current_pos = -1
+ self.executed_action = True
+
+ if self.shared_activity:
+ pass
+ elif handle.object_id is not None:
+ self.list = self.metadata['files']
+ else:
+ self._show_journal_object_picker()
+
+ self.connect('button-press-event', lambda w, e: self._next())
+ self.show_all()
+ self._next()
+
+ def _next(self):
+ if not self.executed_action:
+ card = self.list[self.current_pos]
+ self._execute(card)
+ self.executed_action = True
+ else:
+ self.current_pos += 1
+ try:
+ card = self.list[self.current_pos]
+ except IndexError:
+ self.current_pos = -1
+ self._next()
+ else:
+ self._show_card(card)
+ self.executed_action = False
+
+ def _execute(self, card):
+ if 'sound' in card:
+ # Play sound
+ pass
+ elif 'video' in card:
+ # Play video
+ pass
+
+ def _show_card(self, card):
+ if 'image' in card:
+ self.image.set_from_file(os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'tmp', card['image']))
+ else:
+ self.image.set_from_stock(gtk.STOCK_MISSING_IMAGE)
+
+ if 'action' in card:
+ self.action_icon.set_from_stock(ACTION_ICONS[card['action']], gtk.ICON_SIZE_LARGE_TOOLBAR)
+ else:
+ self.action_icon.set_from_stock(ACTION_ICONS['next'], gtk.ICON_SIZE_LARGE_TOOLBAR)
+
+ self.text.set_text(card['title'])
+
+ def _show_journal_object_picker(self):
+ """Show the journal object picker to load a document.
+
+ This is for if Read is launched without a document.
+ """
+ chooser = ObjectChooser(_('Choose document'), self,
+ gtk.DIALOG_MODAL |
+ gtk.DIALOG_DESTROY_WITH_PARENT,
+ what_filter=mime.GENERIC_TYPE_TEXT) #FIXME: Filter by this activity's type
+ try:
+ result = chooser.run()
+ if result == gtk.RESPONSE_ACCEPT:
+ logging.debug('ObjectChooser: %r' %
+ chooser.get_selected_object())
+ jobject = chooser.get_selected_object()
+ if jobject and jobject.file_path:
+ self.list = jobject.metadata['files']
+ self.read_file(jobject.file_path)
+ finally:
+ chooser.destroy()
+ del chooser
+
+ def read_file(self, path):
+ zip = zipfile.ZipFile(path)
+ info = zip.infolist()
+ size = reduce(lambda s, i: s+i.file_size, info, 0)
+ stat = os.stavfs(os.environ['SUGAR_ACTIVITY_ROOT'])
+ if stat[statvfs.F_BSIZE]*stat[statvfs.F_BAVAIL] < size:
+ #TODO: Alert: Not enough free space
+ for member in zip.infolist():
+ try:
+ data = member.read()
+ self.list.append((member.filename, gio.content_type_guess(None, data))
+ f = open(os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'tmp', member.filename), 'w')
+ f.write(data)
+ del data
+ finally:
+ f.close()
+
+ def write_file(self, path):
+ pass
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..382f317
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# 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
+
+from sugar.activity import bundlebuilder
+
+if __name__ == "__main__":
+ bundlebuilder.start()