diff options
author | Marco Pesenti Gritti <mpgritti@gmail.com> | 2008-09-17 02:31:06 (GMT) |
---|---|---|
committer | Marco Pesenti Gritti <mpgritti@gmail.com> | 2008-09-17 02:31:06 (GMT) |
commit | 1f95a1575d8b4508683109dc0e1cf4d782bf4fcd (patch) | |
tree | 17352f5c71288c859f1e959128622309999220c5 /src | |
parent | efad564146a8b70c834b4bc128ad729144006f71 (diff) | |
parent | a2db7381f0f82c271565ab221da8dcfd3c0e4b4b (diff) |
Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar
Diffstat (limited to 'src')
-rw-r--r-- | src/intro/Makefile.am | 1 | ||||
-rw-r--r-- | src/intro/glive.py | 200 | ||||
-rw-r--r-- | src/journal/palettes.py | 4 | ||||
-rw-r--r-- | src/model/Makefile.am | 2 | ||||
-rw-r--r-- | src/model/clipboard.py | 149 | ||||
-rw-r--r-- | src/model/clipboardobject.py | 117 | ||||
-rw-r--r-- | src/view/Shell.py | 25 | ||||
-rw-r--r-- | src/view/clipboardicon.py | 85 | ||||
-rw-r--r-- | src/view/clipboardmenu.py | 109 | ||||
-rw-r--r-- | src/view/frame/clipboardpanelwindow.py | 13 | ||||
-rw-r--r-- | src/view/frame/clipboardtray.py | 28 | ||||
-rw-r--r-- | src/view/home/favoritesview.py | 8 |
12 files changed, 388 insertions, 353 deletions
diff --git a/src/intro/Makefile.am b/src/intro/Makefile.am index 025f4e6..089c84a 100644 --- a/src/intro/Makefile.am +++ b/src/intro/Makefile.am @@ -6,5 +6,4 @@ sugardir = $(pkgdatadir)/shell/intro sugar_PYTHON = \ __init__.py \ colorpicker.py \ - glive.py \ window.py diff --git a/src/intro/glive.py b/src/intro/glive.py deleted file mode 100644 index a2ddbae..0000000 --- a/src/intro/glive.py +++ /dev/null @@ -1,200 +0,0 @@ -# -*- Mode: Python -*- -# vi:si:et:sw=4:sts=4:ts=4 - -import gtk -import pygtk -pygtk.require('2.0') - -import pygst -pygst.require('0.10') -import gst -import gst.interfaces - -import gobject -gobject.threads_init() - -class Glive(gobject.GObject): - __gsignals__ = { - 'new-picture': (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, - ([gobject.TYPE_PYOBJECT])), - 'sink' : (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, - ([gobject.TYPE_PYOBJECT])) - } - - def __init__(self, parent, width, height): - gobject.GObject.__init__(self) - self._parent = parent - - #check out the halfpipe, d00d. - self.pipeline = gst.Pipeline() - - self.v4l2src = gst.element_factory_make("v4l2src", "v4l2src") - self.t = gst.element_factory_make("tee", "tee") - self.t_src_pad = self.t.get_request_pad( "src%d" ) - self.vscale = gst.element_factory_make("videoscale", "videoscale") - self.ximagesink = gst.element_factory_make("ximagesink", "ximagesink") - - self.pipeline.add(self.v4l2src) - self.pipeline.add(self.t) - self.pipeline.add(self.vscale) - self.pipeline.add(self.ximagesink) - - self.v4l2src.link(self.t) - - videoscale_structure = gst.Structure("video/x-raw-rgb") - videoscale_structure['width'] = width - videoscale_structure['height'] = height - videoscale_structure['bpp'] = 16 - videoscale_structure['depth'] = 16 - videoscale_caps = gst.Caps(videoscale_structure) - self.t_src_pad.link(self.vscale.get_pad("sink")) - self.vscale.link(self.ximagesink, videoscale_caps) - #self.vscale.link(self.ximagesink) - - self.queue = gst.element_factory_make("queue", "queue") - self.queue.set_property("leaky", True) - self.queue.set_property("max-size-buffers", 1) - self.qsrc = self.queue.get_pad( "src" ) - self.qsink = self.queue.get_pad("sink") - self.ffmpeg = gst.element_factory_make( \ - "ffmpegcolorspace", "ffmpegcolorspace") - self.jpgenc = gst.element_factory_make("jpegenc", "jpegenc") - self.filesink = gst.element_factory_make("fakesink", "fakesink") - self.filesink.connect( "handoff", self.copyframe ) - self.filesink.set_property("signal-handoffs", True) - self.pipeline.add(self.queue, self.ffmpeg, self.jpgenc, self.filesink) - - #only link at snapshot time - #self.t.link(self.queue) - self.queue.link(self.ffmpeg) - self.ffmpeg.link(self.jpgenc) - self.jpgenc.link(self.filesink) - self.exposureOpen = False - - self._bus = self.pipeline.get_bus() - self._CONNECT_SYNC = -1 - self._CONNECT_MSG = -1 - self.doPostBusStuff() - - def copyframe(self, fsink, buf, pad, user_data=None): - #for some reason, we get two back to back buffers, even though we - #ask for only one. - if (self.exposureOpen): - self.exposureOpen = False - piccy = gtk.gdk.pixbuf_loader_new_with_mime_type("image/jpeg") - piccy.write(buf) - piccy.close() - pixbuf = piccy.get_pixbuf() - del piccy - - self.t.unlink(self.queue) - self.queue.set_property("leaky", True) - - gobject.idle_add(self.loadPic, pixbuf) - - def loadPic( self, pixbuf ): - self.emit('new-picture', pixbuf) - - def takeSnapshot( self ): - if (self.exposureOpen): - return - else: - self.exposureOpen = True - self.t.link(self.queue) - - def doPostBusStuff(self): - self._bus.enable_sync_message_emission() - self._bus.add_signal_watch() - self._CONNECT_SYNC = self._bus.connect('sync-message::element', - self.on_sync_message) - self._CONNECT_MSG = self._bus.connect('message', self.on_message) - - def on_sync_message(self, bus, message): - if message.structure is None: - return - if message.structure.get_name() == 'prepare-xwindow-id': - self.emit('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): - if (self.on_eos): - self.on_eos() - elif (t == gst.MESSAGE_EOS): - if (self.on_eos): - self.on_eos() - - def on_eos( self ): - pass - - def stop(self): - self.pipeline.set_state(gst.STATE_NULL) - - def play(self): - self.pipeline.set_state(gst.STATE_PLAYING) - - def pause(self): - self.pipeline.set_state(gst.STATE_PAUSED) - - -class LiveVideoSlot(gtk.EventBox): - __gsignals__ = { - 'pixbuf': (gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, - ([gobject.TYPE_PYOBJECT])) - } - - def __init__(self, width, height): - gtk.EventBox.__init__(self) - - self.imagesink = None - self.playa = None - self._width = width - self._height = height - - self.unset_flags(gtk.DOUBLE_BUFFERED) - self.connect('focus-in-event', self.focus_in) - self.connect('focus-out-event', self.focus_out) - self.connect("button-press-event", self._button_press_event_cb) - self.connect("expose-event", self._expose_event_cb) - - def _expose_event_cb(self, widget, event): - if not self.playa: - self.playa = Glive(self, self._width, self._height) - self.playa.connect('new-picture', self._new_picture_cb) - self.playa.connect('sink', self._new_sink_cb) - - def _new_picture_cb(self, playa, pixbuf): - self.emit('pixbuf', pixbuf) - - def _new_sink_cb(self, playa, sink): - if (self.imagesink != None): - assert self.window.xid - self.imagesink = None - del self.imagesink - self.imagesink = sink - self.imagesink.set_xwindow_id(self.window.xid) - - def _button_press_event_cb(self, widget, event): - self.takeSnapshot() - - def focus_in(self, widget, event, args=None): - self.play() - - def focus_out(self, widget, event, args=None): - self.stop() - - def play( self ): - self.playa.play() - - def pause( self ): - self.playa.pause() - - def stop( self ): - self.playa.stop() - - def takeSnapshot( self ): - self.playa.takeSnapshot() diff --git a/src/journal/palettes.py b/src/journal/palettes.py index f186c68..81efc03 100644 --- a/src/journal/palettes.py +++ b/src/journal/palettes.py @@ -15,7 +15,8 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA from gettext import gettext as _ - +import logging + import gtk from sugar import profile @@ -86,6 +87,7 @@ class ObjectPalette(Palette): self.__clipboard_clear_func_cb) def __clipboard_get_func_cb(self, clipboard, selection_data, info, data): + logging.debug('__clipboard_get_func_cb %r' % self._jobject.file_path) selection_data.set_uris(['file://' + self._jobject.file_path]) def __clipboard_clear_func_cb(self, clipboard, data): diff --git a/src/model/Makefile.am b/src/model/Makefile.am index 0b7d14c..9447b03 100644 --- a/src/model/Makefile.am +++ b/src/model/Makefile.am @@ -5,6 +5,8 @@ sugar_PYTHON = \ __init__.py \ accesspointmodel.py \ BuddyModel.py \ + clipboard.py \ + clipboardobject.py \ Friends.py \ Invites.py \ Owner.py \ diff --git a/src/model/clipboard.py b/src/model/clipboard.py new file mode 100644 index 0000000..bde6535 --- /dev/null +++ b/src/model/clipboard.py @@ -0,0 +1,149 @@ +# 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 + +import logging +import os +import shutil +import urlparse +import tempfile + +import gobject + +from sugar import mime + +from model.clipboardobject import ClipboardObject, Format + +class Clipboard(gobject.GObject): + + __gsignals__ = { + 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([object])), + 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([int])), + 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([object])), + } + + def __init__(self): + gobject.GObject.__init__(self) + + self._objects = {} + self._next_id = 0 + + def _get_next_object_id(self): + self._next_id += 1 + return self._next_id + + def add_object(self, name): + logging.debug('Clipboard.add_object') + object_id = self._get_next_object_id() + self._objects[object_id] = ClipboardObject(object_id, name) + self.emit('object-added', self._objects[object_id]) + return object_id + + def add_object_format(self, object_id, format_type, data, on_disk): + logging.debug('Clipboard.add_object_format') + cb_object = self._objects[object_id] + + if format_type == 'XdndDirectSave0': + format = Format('text/uri-list', data + '\r\n', on_disk) + format.owns_disk_data = True + cb_object.add_format(format) + elif on_disk and cb_object.get_percent() == 100: + new_uri = self._copy_file(data) + cb_object.add_format(Format(format_type, new_uri, on_disk)) + logging.debug('Added format of type ' + format_type + + ' with path at ' + new_uri) + else: + cb_object.add_format(Format(format_type, data, on_disk)) + logging.debug('Added in-memory format of type ' + format_type + '.') + + self.emit('object-state-changed', cb_object) + + def delete_object(self, object_id): + cb_object = self._objects.pop(object_id) + cb_object.destroy() + self.emit('object-deleted', object_id) + logging.debug('Deleted object with object_id %r' % object_id) + + def set_object_percent(self, object_id, percent): + cb_object = self._objects[object_id] + if percent < 0 or percent > 100: + raise ValueError("invalid percentage") + if cb_object.get_percent() > percent: + raise ValueError("invalid percentage; less than current percent") + if cb_object.get_percent() == percent: + # ignore setting same percentage + return + + cb_object.set_percent(percent) + + if percent == 100: + self._process_object(cb_object) + + self.emit('object-state-changed', cb_object) + + def _process_object(self, cb_object): + formats = cb_object.get_formats() + for format_name, format in formats.iteritems(): + if format.is_on_disk() and not format.owns_disk_data: + new_uri = self._copy_file(format.get_data()) + format.set_data(new_uri) + + # Add a text/plain format to objects that are text but lack it + if 'text/plain' not in formats.keys(): + if 'UTF8_STRING' in formats.keys(): + self.add_object_format( + cb_object.get_id(), 'text/plain', + data=formats['UTF8_STRING'].get_data(), on_disk=False) + elif 'text/unicode' in formats.keys(): + self.add_object_format( + cb_object.get_id(), 'text/plain', + data=formats['UTF8_STRING'].get_data(), on_disk=False) + + def get_object(self, object_id): + logging.debug('Clipboard.get_object') + return self._objects[object_id] + + def get_object_data(self, object_id, format_type): + logging.debug('Clipboard.get_object_data') + cb_object = self._objects[object_id] + format = cb_object.get_formats()[format_type] + return format + + def _copy_file(self, original_uri): + uri = urlparse.urlparse(original_uri) + path_, file_name = os.path.split(uri.path) + + root, ext = os.path.splitext(file_name) + if not ext or ext == '.': + mime_type = mime.get_for_file(uri.path) + ext = '.' + mime.get_primary_extension(mime_type) + + f_, new_file_path = tempfile.mkstemp(ext, root) + del f_ + shutil.copyfile(uri.path, new_file_path) + os.chmod(new_file_path, 0644) + + return 'file://' + new_file_path + +_instance = None + +def get_instance(): + global _instance + if not _instance: + _instance = Clipboard() + return _instance diff --git a/src/model/clipboardobject.py b/src/model/clipboardobject.py new file mode 100644 index 0000000..a4cd388 --- /dev/null +++ b/src/model/clipboardobject.py @@ -0,0 +1,117 @@ +# Copyright (C) 2007, One Laptop Per Child +# +# 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 urlparse + +from sugar import mime +from sugar.bundle.activitybundle import ActivityBundle + +class ClipboardObject(object): + + def __init__(self, object_path, name): + self._id = object_path + self._name = name + self._percent = 0 + self._formats = {} + + def destroy(self): + for format in self._formats.itervalues(): + format.destroy() + + def get_id(self): + return self._id + + def get_name(self): + name = self._name + if not name: + name = mime.get_mime_description(self.get_mime_type()) + if not name: + name = '' + return name + + def get_icon(self): + return mime.get_mime_icon(self.get_mime_type()) + + def get_preview(self): + # TODO: should previews really be here? + #return self._get_type_info().get_preview() + return '' + + def is_bundle(self): + # A bundle will have only one format. + if not self._formats: + return False + else: + return self._formats.keys()[0] in [ActivityBundle.MIME_TYPE, + ActivityBundle.DEPRECATED_MIME_TYPE] + + def get_percent(self): + return self._percent + + def set_percent(self, percent): + self._percent = percent + + def add_format(self, format): + self._formats[format.get_type()] = format + + def get_formats(self): + return self._formats + + def get_mime_type(self): + if not self._formats: + return '' + + format = mime.choose_most_significant(self._formats.keys()) + if format == 'text/uri-list': + data = self._formats['text/uri-list'].get_data() + uri = urlparse.urlparse(mime.split_uri_list(data)[0], 'file') + if uri.scheme == 'file': + if os.path.exists(uri.path): + format = mime.get_for_file(uri.path) + else: + format = mime.get_from_file_name(uri.path) + logging.debug('Choosed %r!' % format) + + return format + +class Format(object): + + def __init__(self, mime_type, data, on_disk): + self.owns_disk_data = False + + self._type = mime_type + self._data = data + self._on_disk = on_disk + + def destroy(self): + if self._on_disk: + uri = urlparse.urlparse(self._data) + if os.path.isfile(uri.path): + os.remove(uri.path) + + def get_type(self): + return self._type + + def get_data(self): + return self._data + + def set_data(self, data): + self._data = data + + def is_on_disk(self): + return self._on_disk diff --git a/src/view/Shell.py b/src/view/Shell.py index 33dcbc0..26a66e6 100644 --- a/src/view/Shell.py +++ b/src/view/Shell.py @@ -251,22 +251,19 @@ class Shell(gobject.GObject): screenshot.get_from_drawable(window, window.get_colormap(), x_orig, y_orig, 0, 0, width, height) screenshot.save(file_path, "png") + jobject = datastore.create() try: - jobject = datastore.create() - try: - jobject.metadata['title'] = _('Screenshot') - jobject.metadata['keep'] = '0' - jobject.metadata['buddies'] = '' - jobject.metadata['preview'] = '' - jobject.metadata['icon-color'] = profile.get_color().to_string() - jobject.metadata['mime_type'] = 'image/png' - jobject.file_path = file_path - datastore.write(jobject) - finally: - jobject.destroy() - del jobject + jobject.metadata['title'] = _('Screenshot') + jobject.metadata['keep'] = '0' + jobject.metadata['buddies'] = '' + jobject.metadata['preview'] = '' + jobject.metadata['icon-color'] = profile.get_color().to_string() + jobject.metadata['mime_type'] = 'image/png' + jobject.file_path = file_path + datastore.write(jobject, transfer_ownership=True) finally: - os.remove(file_path) + jobject.destroy() + del jobject _instance = None diff --git a/src/view/clipboardicon.py b/src/view/clipboardicon.py index 729b97d..c5b6ae7 100644 --- a/src/view/clipboardicon.py +++ b/src/view/clipboardicon.py @@ -21,10 +21,9 @@ import gtk from sugar.graphics.radiotoolbutton import RadioToolButton from sugar.graphics.icon import Icon from sugar.graphics.xocolor import XoColor -from sugar.clipboard import clipboardservice -from sugar.bundle.activitybundle import ActivityBundle from sugar import profile +from model import clipboard from view.clipboardmenu import ClipboardMenu from view.frame.frameinvoker import FrameWidgetInvoker from view.frame.notification import NotificationIcon @@ -33,66 +32,51 @@ import view.frame.frame class ClipboardIcon(RadioToolButton): __gtype_name__ = 'SugarClipboardIcon' - def __init__(self, object_id, name, group): + def __init__(self, cb_object, group): RadioToolButton.__init__(self, group=group) - self._object_id = object_id - self._name = name - self._percent = 0 - self._preview = None - self._activity = None + self._cb_object = cb_object self.owns_clipboard = False self.props.sensitive = False self.props.active = False self._notif_icon = None + self._current_percent = None self._icon = Icon() self._icon.props.xo_color = profile.get_color() self.set_icon_widget(self._icon) self._icon.show() - cb_service = clipboardservice.get_instance() + cb_service = clipboard.get_instance() cb_service.connect('object-state-changed', self._object_state_changed_cb) - obj = cb_service.get_object(self._object_id) - self.palette = ClipboardMenu(self._object_id, self._name, self._percent, - self._preview, self._activity, - self._is_bundle(obj['FORMATS'])) + self.palette = ClipboardMenu(cb_object) self.palette.props.invoker = FrameWidgetInvoker(self) child = self.get_child() child.connect('drag_data_get', self._drag_data_get_cb) self.connect('notify::active', self._notify_active_cb) - def _is_bundle(self, formats): - # A bundle will have only one format. - return formats and formats[0] in [ActivityBundle.MIME_TYPE, - ActivityBundle.DEPRECATED_MIME_TYPE] - def get_object_id(self): - return self._object_id + return self._cb_object.get_id() - def _drag_data_get_cb(self, widget, context, selection, - targetType, eventTime): + def _drag_data_get_cb(self, widget, context, selection, target_type, + event_time): logging.debug('_drag_data_get_cb: requested target ' + selection.target) - - cb_service = clipboardservice.get_instance() - data = cb_service.get_object_data(self._object_id, - selection.target)['DATA'] - + data = self._cb_object.get_formats()[selection.target].get_data() selection.set(selection.target, 8, data) def _put_in_clipboard(self): logging.debug('ClipboardIcon._put_in_clipboard') - if self._percent < 100: + if self._cb_object.get_percent() < 100: raise ValueError('Object is not complete,' \ ' cannot be put into the clipboard.') targets = self._get_targets() if targets: - clipboard = gtk.Clipboard() - if not clipboard.set_with_data(targets, + x_clipboard = gtk.Clipboard() + if not x_clipboard.set_with_data(targets, self._clipboard_data_get_cb, self._clipboard_clear_cb, targets): @@ -100,32 +84,24 @@ class ClipboardIcon(RadioToolButton): else: self.owns_clipboard = True - def _clipboard_data_get_cb(self, clipboard, selection, info, targets): + def _clipboard_data_get_cb(self, x_clipboard, selection, info, targets): if not selection.target in [target[0] for target in targets]: logging.warning('ClipboardIcon._clipboard_data_get_cb: asked %s' \ ' but only have %r.' % (selection.target, targets)) return - cb_service = clipboardservice.get_instance() - data = cb_service.get_object_data(self._object_id, - selection.target)['DATA'] - + data = self._cb_object.get_formats()[selection.target].get_data() selection.set(selection.target, 8, data) - def _clipboard_clear_cb(self, clipboard, targets): + def _clipboard_clear_cb(self, x_clipboard, targets): logging.debug('ClipboardIcon._clipboard_clear_cb') self.owns_clipboard = False - def _object_state_changed_cb(self, cb_service, object_id, name, percent, - icon_name, preview, activity): - - if object_id != self._object_id: + def _object_state_changed_cb(self, cb_service, cb_object): + if cb_object != self._cb_object: return - cb_service = clipboardservice.get_instance() - obj = cb_service.get_object(self._object_id) - - if icon_name: - self._icon.props.icon_name = icon_name + if cb_object.get_icon(): + self._icon.props.icon_name = cb_object.get_icon() else: self._icon.props.icon_name = 'application-octet-stream' @@ -135,19 +111,11 @@ class ClipboardIcon(RadioToolButton): gtk.gdk.ACTION_COPY) child.drag_source_set_icon_name(self._icon.props.icon_name) - self._name = name - self._preview = preview - self._activity = activity - self.palette.update_state(name, percent, preview, activity, - self._is_bundle(obj['FORMATS'])) - - old_percent = self._percent - self._percent = percent - if self._percent == 100: + if cb_object.get_percent() == 100: self.props.sensitive = True # Clipboard object became complete. Make it the active one. - if old_percent < 100 and self._percent == 100: + if self._current_percent < 100 and cb_object.get_percent() == 100: self.props.active = True self._notif_icon = NotificationIcon() @@ -158,6 +126,7 @@ class ClipboardIcon(RadioToolButton): frame = view.frame.frame.get_instance() frame.add_notification(self._notif_icon, view.frame.frame.BOTTOM_LEFT) + self._current_percent = cb_object.get_percent() def _notify_active_cb(self, widget, pspec): if self.props.active: @@ -166,14 +135,8 @@ class ClipboardIcon(RadioToolButton): self.owns_clipboard = False def _get_targets(self): - cb_service = clipboardservice.get_instance() - - attrs = cb_service.get_object(self._object_id) - format_types = attrs[clipboardservice.FORMATS_KEY] - targets = [] - for format_type in format_types: + for format_type in self._cb_object.get_formats().keys(): targets.append((format_type, 0, 0)) - return targets diff --git a/src/view/clipboardmenu.py b/src/view/clipboardmenu.py index f036aeb..c5e4cef 100644 --- a/src/view/clipboardmenu.py +++ b/src/view/clipboardmenu.py @@ -25,24 +25,26 @@ import gtk from sugar.graphics.palette import Palette from sugar.graphics.menuitem import MenuItem from sugar.graphics.icon import Icon -from sugar.clipboard import clipboardservice from sugar.datastore import datastore from sugar import mime from sugar import profile from sugar import activity +from model import clipboard + class ClipboardMenu(Palette): - def __init__(self, object_id, name, percent, preview, - activities, installable): - Palette.__init__(self, name) + def __init__(self, cb_object): + Palette.__init__(self, cb_object.get_name()) - self._object_id = object_id - self._percent = percent - self._activities = activities + self._cb_object = cb_object self.set_group_id('frame') + cb_service = clipboard.get_instance() + cb_service.connect('object-state-changed', + self._object_state_changed_cb) + self._progress_bar = None self._remove_item = MenuItem(_('Remove'), 'list-remove') @@ -55,11 +57,6 @@ class ClipboardMenu(Palette): self.menu.append(self._open_item) self._open_item.show() - #self._stop_item = MenuItem(_('Stop download'), 'stock-close') - # TODO: Implement stopping downloads - #self._stop_item.connect('activate', self._stop_item_activate_cb) - #self.append_menu_item(self._stop_item) - self._journal_item = MenuItem(_('Keep')) icon = Icon(icon_name='document-save', icon_size=gtk.ICON_SIZE_MENU, xo_color=profile.get_color()) @@ -69,13 +66,14 @@ class ClipboardMenu(Palette): self.menu.append(self._journal_item) self._journal_item.show() - self._update_items_visibility(installable) + self._update_items_visibility() self._update_open_submenu() def _update_open_submenu(self): - logging.debug('_update_open_submenu: %r' % self._activities) + activities = self._get_activities() + logging.debug('_update_open_submenu: %r' % activities) child = self._open_item.get_child() - if self._activities is None or len(self._activities) <= 1: + if activities is None or len(activities) <= 1: child.set_text(_('Open')) if self._open_item.get_submenu() is not None: self._open_item.remove_submenu() @@ -91,7 +89,7 @@ class ClipboardMenu(Palette): for item in submenu.get_children(): submenu.remove(item) - for service_name in self._activities: + for service_name in activities: registry = activity.get_registry() activity_info = registry.get_activity(service_name) @@ -104,29 +102,41 @@ class ClipboardMenu(Palette): submenu.append(item) item.show() - def _update_items_visibility(self, installable): - if self._percent == 100 and (self._activities or installable): + def _update_items_visibility(self): + activities = self._get_activities() + installable = self._cb_object.is_bundle() + percent = self._cb_object.get_percent() + + if percent == 100 and (activities or installable): self._remove_item.props.sensitive = True self._open_item.props.sensitive = True - #self._stop_item.props.sensitive = False self._journal_item.props.sensitive = True - elif self._percent == 100 and \ - (not self._activities and not installable): + elif percent == 100 and (not activities and not installable): self._remove_item.props.sensitive = True self._open_item.props.sensitive = False - #self._stop_item.props.sensitive = False self._journal_item.props.sensitive = True else: self._remove_item.props.sensitive = True self._open_item.props.sensitive = False - # TODO: reenable the stop item when we implement stoping downloads. - #self._stop_item.props.sensitive = True self._journal_item.props.sensitive = False self._update_progress_bar() + def _get_activities(self): + mime_type = self._cb_object.get_mime_type() + if not mime_type: + return '' + + registry = activity.get_registry() + activities = registry.get_activities_for_type(mime_type) + if activities: + return [activity_info.bundle_id for activity_info in activities] + else: + return '' + def _update_progress_bar(self): - if self._percent == 100.0: + percent = self._cb_object.get_percent() + if percent == 100.0: if self._progress_bar: self._progress_bar = None self.set_content(None) @@ -136,20 +146,21 @@ class ClipboardMenu(Palette): self._progress_bar.show() self.set_content(self._progress_bar) - self._progress_bar.props.fraction = self._percent / 100.0 - self._progress_bar.props.text = '%.2f %%' % self._percent + self._progress_bar.props.fraction = percent / 100.0 + self._progress_bar.props.text = '%.2f %%' % percent - def update_state(self, name, percent, preview, activities, installable): - self.set_primary_text(name) - self._percent = percent - self._activities = activities + def _object_state_changed_cb(self, cb_service, cb_object): + if cb_object != self._cb_object: + return + self.set_primary_text(cb_object.get_name()) self._update_progress_bar() - self._update_items_visibility(installable) + self._update_items_visibility() self._update_open_submenu() def _open_item_activate_cb(self, menu_item): logging.debug('_open_item_activate_cb') - if self._percent < 100 or menu_item.get_submenu() is not None: + percent = self._cb_object.get_percent() + if percent < 100 or menu_item.get_submenu() is not None: return jobject = self._copy_to_journal() jobject.resume(self._activities[0]) @@ -157,15 +168,16 @@ class ClipboardMenu(Palette): def _open_submenu_item_activate_cb(self, menu_item, service_name): logging.debug('_open_submenu_item_activate_cb') - if self._percent < 100: + percent = self._cb_object.get_percent() + if percent < 100: return jobject = self._copy_to_journal() jobject.resume(service_name) jobject.destroy() def _remove_item_activate_cb(self, menu_item): - cb_service = clipboardservice.get_instance() - cb_service.delete_object(self._object_id) + cb_service = clipboard.get_instance() + cb_service.delete_object(self._cb_object.get_id()) def _journal_item_activate_cb(self, menu_item): logging.debug('_journal_item_activate_cb') @@ -181,39 +193,38 @@ class ClipboardMenu(Palette): return file_path def _copy_to_journal(self): - cb_service = clipboardservice.get_instance() - obj = cb_service.get_object(self._object_id) - - format = mime.choose_most_significant(obj['FORMATS']) - data = cb_service.get_object_data(self._object_id, format) + formats = self._cb_object.get_formats().keys() + most_significant_mime_type = mime.choose_most_significant(formats) + format = self._cb_object.get_formats()[most_significant_mime_type] transfer_ownership = False - if format == 'text/uri-list': - uris = mime.split_uri_list(data['DATA']) + if most_significant_mime_type == 'text/uri-list': + uris = mime.split_uri_list(format.get_data()) if len(uris) == 1 and uris[0].startswith('file://'): file_path = urlparse.urlparse(uris[0]).path transfer_ownership = False mime_type = mime.get_for_file(file_path) else: - file_path = self._write_to_temp_file(data['DATA']) + file_path = self._write_to_temp_file(format.get_data()) transfer_ownership = True mime_type = 'text/uri-list' else: - if data['ON_DISK']: - file_path = urlparse.urlparse(data['DATA']).path + if format.is_on_disk(): + file_path = urlparse.urlparse(format.get_data()).path transfer_ownership = False mime_type = mime.get_for_file(file_path) else: - file_path = self._write_to_temp_file(data['DATA']) + file_path = self._write_to_temp_file(format.get_data()) transfer_ownership = True sniffed_mime_type = mime.get_for_file(file_path) if sniffed_mime_type == 'application/octet-stream': - mime_type = format + mime_type = most_significant_mime_type else: mime_type = sniffed_mime_type + name = self._cb_object.get_name() jobject = datastore.create() - jobject.metadata['title'] = _('Clipboard object: %s.') % obj['NAME'] + jobject.metadata['title'] = _('%s clipping') % name jobject.metadata['keep'] = '0' jobject.metadata['buddies'] = '' jobject.metadata['preview'] = '' diff --git a/src/view/frame/clipboardpanelwindow.py b/src/view/frame/clipboardpanelwindow.py index 10b234b..08794b8 100644 --- a/src/view/frame/clipboardpanelwindow.py +++ b/src/view/frame/clipboardpanelwindow.py @@ -22,7 +22,8 @@ import hippo from view.frame.framewindow import FrameWindow from view.frame.clipboardtray import ClipboardTray -from sugar.clipboard import clipboardservice + +from model import clipboard class ClipboardPanelWindow(FrameWindow): def __init__(self, frame, orientation): @@ -47,22 +48,22 @@ class ClipboardPanelWindow(FrameWindow): self.connect("drag_data_received", self._clipboard_tray.drag_data_received_cb) - def _owner_change_cb(self, clipboard, event): + def _owner_change_cb(self, x_clipboard, event): logging.debug("owner_change_cb") if self._clipboard_tray.owns_clipboard(): return - cb_service = clipboardservice.get_instance() + cb_service = clipboard.get_instance() key = cb_service.add_object(name="") cb_service.set_object_percent(key, percent=0) - targets = clipboard.wait_for_targets() + targets = x_clipboard.wait_for_targets() for target in targets: if target not in ('TIMESTAMP', 'TARGETS', 'MULTIPLE', 'SAVE_TARGETS'): logging.debug('Asking for target %s.' % target) - selection = clipboard.wait_for_contents(target) + selection = x_clipboard.wait_for_contents(target) if not selection: logging.warning('no data for selection target %s.' % target) continue @@ -77,7 +78,7 @@ class ClipboardPanelWindow(FrameWindow): logging.debug('adding type ' + selection.type + '.') - cb_service = clipboardservice.get_instance() + cb_service = clipboard.get_instance() if selection.type == 'text/uri-list': uris = selection.get_uris() diff --git a/src/view/frame/clipboardtray.py b/src/view/frame/clipboardtray.py index b5ba093..8c3939f 100644 --- a/src/view/frame/clipboardtray.py +++ b/src/view/frame/clipboardtray.py @@ -21,13 +21,13 @@ import tempfile import gtk from sugar import util -from sugar.clipboard import clipboardservice from sugar.graphics import tray from sugar.graphics import style +from model import clipboard from view.clipboardicon import ClipboardIcon -class _ContextMap: +class _ContextMap(object): """Maps a drag context to the clipboard object involved in the dragging.""" def __init__(self): self._context_map = {} @@ -65,7 +65,7 @@ class ClipboardTray(tray.VTray): self._icons = {} self._context_map = _ContextMap() - cb_service = clipboardservice.get_instance() + cb_service = clipboard.get_instance() cb_service.connect('object-added', self._object_added_cb) cb_service.connect('object-deleted', self._object_deleted_cb) @@ -79,9 +79,9 @@ class ClipboardTray(tray.VTray): if not selection.data: return - logging.debug('ClipboardTray: adding type ' + selection.type) + logging.debug('ClipboardTray: adding type %r' % selection.type) - cb_service = clipboardservice.get_instance() + cb_service = clipboard.get_instance() if selection.type == 'text/uri-list': uris = selection.data.split('\n') if len(uris) > 1: @@ -98,30 +98,30 @@ class ClipboardTray(tray.VTray): selection.data, on_disk=False) - def _object_added_cb(self, cb_service, object_id, name): + def _object_added_cb(self, cb_service, cb_object): if self._icons: group = self._icons.values()[0] else: group = None - icon = ClipboardIcon(object_id, name, group) + icon = ClipboardIcon(cb_object, group) self.add_item(icon) icon.show() - self._icons[object_id] = icon + self._icons[cb_object.get_id()] = icon objects_to_delete = self.get_children()[:-self.MAX_ITEMS] for icon in objects_to_delete: logging.debug('ClipboardTray: deleting surplus object') - cb_service = clipboardservice.get_instance() + cb_service = clipboard.get_instance() cb_service.delete_object(icon.get_object_id()) - logging.debug('ClipboardTray: ' + object_id + ' was added.') + logging.debug('ClipboardTray: %r was added' % cb_object.get_id()) def _object_deleted_cb(self, cb_service, object_id): icon = self._icons[object_id] self.remove_item(icon) del self._icons[object_id] - logging.debug('ClipboardTray: ' + object_id + ' was deleted.') + logging.debug('ClipboardTray: %r was deleted' % object_id) def drag_motion_cb(self, widget, context, x, y, time): logging.debug('ClipboardTray._drag_motion_cb') @@ -130,7 +130,7 @@ class ClipboardTray(tray.VTray): def drag_drop_cb(self, widget, context, x, y, time): logging.debug('ClipboardTray._drag_drop_cb') - cb_service = clipboardservice.get_instance() + cb_service = clipboard.get_instance() object_id = cb_service.add_object(name="") self._context_map.add_context(context, object_id, len(context.targets)) @@ -179,8 +179,8 @@ class ClipboardTray(tray.VTray): prop_type, format_, dest = \ window.property_get('XdndDirectSave0', 'text/plain') - clipboard = clipboardservice.get_instance() - clipboard.add_object_format( \ + clipboardservice = clipboard.get_instance() + clipboardservice.add_object_format( \ object_id, 'XdndDirectSave0', dest, on_disk=True) else: self._add_selection(object_id, selection) diff --git a/src/view/home/favoritesview.py b/src/view/home/favoritesview.py index 409504c..d66649f 100644 --- a/src/view/home/favoritesview.py +++ b/src/view/home/favoritesview.py @@ -404,13 +404,7 @@ class _MyIcon(MyIcon): #secondary_text='Sample secondary label', icon=palette_icon) - item = MenuItem(_('Control Panel')) - - icon = Icon(icon_name='computer-xo', icon_size=gtk.ICON_SIZE_MENU, - xo_color=self._profile.color) - item.set_image(icon) - icon.show() - + item = MenuItem(_('Settings'), 'preferences-system') item.connect('activate', self.__controlpanel_activate_cb) palette.menu.append(item) item.show() |