Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar
This commit is contained in:
commit
8a9bc3b702
4
NEWS
4
NEWS
@ -1,3 +1,7 @@
|
||||
* Don't allow removing system-installed activities. (tomeu)
|
||||
* #3063: Make the 'Keep' button in the activity toolbar create a copy of the
|
||||
activity in the journal. Add a copy() method for activities to use. (tomeu)
|
||||
* #3045: Fix issues with the clipboard icons and palettes. (tomeu)
|
||||
* Get invites back to work in the UI. (marco)
|
||||
* Get the title on activity palette in the mesh to work. (marco)
|
||||
|
||||
|
@ -134,7 +134,7 @@ class Network(gobject.GObject):
|
||||
|
||||
fav_nets = []
|
||||
if self._client.nminfo:
|
||||
fav_nets = self._client.nminfo.get_networks()
|
||||
fav_nets = self._client.nminfo.get_networks(nminfo.NETWORK_TYPE_ALLOWED)
|
||||
if self._ssid in fav_nets:
|
||||
self._favorite = True
|
||||
|
||||
|
@ -19,65 +19,95 @@ import logging
|
||||
from gettext import gettext as _
|
||||
|
||||
import gobject
|
||||
import gtk
|
||||
|
||||
from sugar.graphics.icon import CanvasIcon
|
||||
from view.clipboardmenu import ClipboardMenu
|
||||
from sugar.graphics.radiotoolbutton import RadioToolButton
|
||||
from sugar.graphics.xocolor import XoColor
|
||||
from sugar.graphics.icon import Icon
|
||||
from sugar.graphics import style
|
||||
from sugar.clipboard import clipboardservice
|
||||
from sugar import util
|
||||
from sugar import profile
|
||||
|
||||
class ClipboardIcon(CanvasIcon):
|
||||
from view.clipboardmenu import ClipboardMenu
|
||||
from view.frame.frameinvoker import FrameWidgetInvoker
|
||||
|
||||
class ClipboardIcon(RadioToolButton):
|
||||
__gtype_name__ = 'SugarClipboardIcon'
|
||||
|
||||
__gproperties__ = {
|
||||
'selected' : (bool, None, None, False,
|
||||
gobject.PARAM_READWRITE)
|
||||
}
|
||||
|
||||
def __init__(self, object_id, name):
|
||||
CanvasIcon.__init__(self)
|
||||
def __init__(self, object_id, name, group):
|
||||
RadioToolButton.__init__(self, group=group)
|
||||
self._object_id = object_id
|
||||
self._name = name
|
||||
self._percent = 0
|
||||
self._preview = None
|
||||
self._activity = None
|
||||
self._selected = False
|
||||
self._hover = False
|
||||
self.props.size = style.STANDARD_ICON_SIZE
|
||||
self.props.xo_color = XoColor(profile.get_color().to_string())
|
||||
self.owns_clipboard = False
|
||||
|
||||
self._icon = Icon()
|
||||
self._icon.props.xo_color = profile.get_color()
|
||||
self.set_icon_widget(self._icon)
|
||||
self._icon.show()
|
||||
|
||||
self.props.sensitive = False
|
||||
|
||||
cb_service = clipboardservice.get_instance()
|
||||
cb_service.connect('object-state-changed', self._object_state_changed_cb)
|
||||
obj = cb_service.get_object(self._object_id)
|
||||
formats = obj['FORMATS']
|
||||
|
||||
self.palette = ClipboardMenu(self._object_id, self._name, self._percent,
|
||||
self._preview, self._activity,
|
||||
formats and formats[0] == 'application/vnd.olpc-sugar')
|
||||
self.palette.props.invoker = FrameWidgetInvoker(self)
|
||||
|
||||
self.child.connect('drag_data_get', self._drag_data_get_cb)
|
||||
self.connect('notify::active', self._notify_active_cb)
|
||||
|
||||
def do_set_property(self, pspec, value):
|
||||
if pspec.name == 'selected':
|
||||
self._set_selected(value)
|
||||
self.emit_paint_needed(0, 0, -1, -1)
|
||||
else:
|
||||
CanvasIcon.do_set_property(self, pspec, value)
|
||||
def get_object_id(self):
|
||||
return self._object_id
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
if pspec.name == 'selected':
|
||||
return self._selected
|
||||
else:
|
||||
return CanvasIcon.do_get_property(self, pspec)
|
||||
def _drag_data_get_cb(self, widget, context, selection, targetType, eventTime):
|
||||
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']
|
||||
|
||||
selection.set(selection.target, 8, data)
|
||||
|
||||
def _set_selected(self, selected):
|
||||
self._selected = selected
|
||||
if selected:
|
||||
if not self._hover:
|
||||
self.props.background_color = style.COLOR_SELECTION_GREY.get_int()
|
||||
else:
|
||||
self.props.background_color = style.COLOR_PANEL_GREY.get_int()
|
||||
def _put_in_clipboard(self):
|
||||
logging.debug('ClipboardIcon._put_in_clipboard')
|
||||
targets = self._get_targets()
|
||||
if targets:
|
||||
clipboard = gtk.Clipboard()
|
||||
if not clipboard.set_with_data(targets,
|
||||
self._clipboard_data_get_cb,
|
||||
self._clipboard_clear_cb,
|
||||
targets):
|
||||
logging.error('GtkClipboard.set_with_data failed!')
|
||||
else:
|
||||
self.owns_clipboard = True
|
||||
|
||||
def _clipboard_data_get_cb(self, 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']
|
||||
|
||||
selection.set(selection.target, 8, data)
|
||||
|
||||
def _clipboard_clear_cb(self, 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:
|
||||
return
|
||||
|
||||
def set_state(self, name, percent, icon_name, preview, activity):
|
||||
cb_service = clipboardservice.get_instance()
|
||||
obj = cb_service.get_object(self._object_id)
|
||||
if obj['FORMATS'] and obj['FORMATS'][0] == 'application/vnd.olpc-sugar':
|
||||
@ -86,32 +116,41 @@ class ClipboardIcon(CanvasIcon):
|
||||
installable = False
|
||||
|
||||
if icon_name:
|
||||
self.props.icon_name = icon_name
|
||||
self._icon.props.icon_name = icon_name
|
||||
else:
|
||||
self.props.icon_name = 'application-octet-stream'
|
||||
self._icon.props.icon_name = 'application-octet-stream'
|
||||
|
||||
self.child.drag_source_set(gtk.gdk.BUTTON1_MASK,
|
||||
self._get_targets(),
|
||||
gtk.gdk.ACTION_COPY)
|
||||
self.child.drag_source_set_icon_name(self._icon.props.icon_name)
|
||||
|
||||
self._name = name
|
||||
self._percent = percent
|
||||
self._preview = preview
|
||||
self._activity = activity
|
||||
self.palette.set_state(name, percent, preview, activity, installable)
|
||||
|
||||
if (activity or installable) and percent < 100:
|
||||
self.props.xo_color = XoColor("#000000,#424242")
|
||||
self.props.sensitive = (percent == 100)
|
||||
|
||||
if self.props.active:
|
||||
self._put_in_clipboard()
|
||||
|
||||
def _notify_active_cb(self, widget, pspec):
|
||||
if self.props.active:
|
||||
self._put_in_clipboard()
|
||||
else:
|
||||
self.props.xo_color = XoColor(profile.get_color().to_string())
|
||||
self.owns_clipboard = False
|
||||
|
||||
def get_object_id(self):
|
||||
return self._object_id
|
||||
def _get_targets(self):
|
||||
cb_service = clipboardservice.get_instance()
|
||||
|
||||
def prelight(self, enter):
|
||||
if enter:
|
||||
self._hover = True
|
||||
self.props.background_color = style.COLOR_BLACK.get_int()
|
||||
else:
|
||||
self._hover = False
|
||||
if self._selected:
|
||||
self.props.background_color = style.COLOR_SELECTION_GREY.get_int()
|
||||
else:
|
||||
self.props.background_color = style.COLOR_PANEL_GREY.get_int()
|
||||
attrs = cb_service.get_object(self._object_id)
|
||||
format_types = attrs[clipboardservice.FORMATS_KEY]
|
||||
|
||||
targets = []
|
||||
for format_type in format_types:
|
||||
targets.append((format_type, 0, 0))
|
||||
|
||||
return targets
|
||||
|
||||
|
@ -37,7 +37,6 @@ class ClipboardMenu(Palette):
|
||||
def __init__(self, object_id, name, percent, preview, activities, installable):
|
||||
Palette.__init__(self, name)
|
||||
|
||||
self.props.position = Palette.RIGHT
|
||||
self._object_id = object_id
|
||||
self._percent = percent
|
||||
self._activities = activities
|
||||
|
@ -54,10 +54,11 @@ class ActivityButton(TrayButton, gobject.GObject):
|
||||
self.set_palette(palette)
|
||||
palette.props.invoker = FrameWidgetInvoker(self)
|
||||
|
||||
menu_item = gtk.MenuItem(_('Remove'))
|
||||
menu_item.connect('activate', self.item_remove_cb)
|
||||
palette.menu.append(menu_item)
|
||||
menu_item.show()
|
||||
if os.path.dirname(self._activity_info.path) == os.path.expanduser('~/Activities'):
|
||||
menu_item = gtk.MenuItem(_('Remove'))
|
||||
menu_item.connect('activate', self.item_remove_cb)
|
||||
palette.menu.append(menu_item)
|
||||
menu_item.show()
|
||||
|
||||
def item_remove_cb(self, widget):
|
||||
self.emit('remove_activity')
|
||||
|
@ -21,8 +21,10 @@ import hippo
|
||||
import gtk
|
||||
|
||||
from sugar import util
|
||||
from view.clipboardicon import ClipboardIcon
|
||||
from sugar.clipboard import clipboardservice
|
||||
from sugar.graphics.tray import VTray
|
||||
|
||||
from view.clipboardicon import ClipboardIcon
|
||||
|
||||
class _ContextMap:
|
||||
"""Maps a drag context to the clipboard object involved in the dragging."""
|
||||
@ -60,33 +62,20 @@ class ClipboardBox(hippo.CanvasBox):
|
||||
self._icons = {}
|
||||
self._context_map = _ContextMap()
|
||||
self._selected_icon = None
|
||||
self._owns_clipboard = False
|
||||
|
||||
self._pressed_button = None
|
||||
self._press_start_x = None
|
||||
self._press_start_y = None
|
||||
self._tray = VTray()
|
||||
self.append(hippo.CanvasWidget(widget=self._tray), hippo.PACK_EXPAND)
|
||||
self._tray.show()
|
||||
|
||||
cb_service = clipboardservice.get_instance()
|
||||
cb_service.connect('object-added', self._object_added_cb)
|
||||
cb_service.connect('object-deleted', self._object_deleted_cb)
|
||||
cb_service.connect('object-state-changed', self._object_state_changed_cb)
|
||||
|
||||
def owns_clipboard(self):
|
||||
return self._owns_clipboard
|
||||
|
||||
def _get_icon_at_coords(self, x, y):
|
||||
box_x, box_y = self.get_context().translate_to_widget(self)
|
||||
x -= box_x
|
||||
y -= box_y
|
||||
for object_id, icon in self._icons.iteritems():
|
||||
icon_x, icon_y = self.get_position(icon)
|
||||
icon_width, icon_height = icon.get_allocation()
|
||||
|
||||
if (x >= icon_x ) and (x <= icon_x + icon_width) and \
|
||||
(y >= icon_y ) and (y <= icon_y + icon_height):
|
||||
return icon
|
||||
|
||||
return None
|
||||
for icon in self._icons.values():
|
||||
if icon.owns_clipboard:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _add_selection(self, object_id, selection):
|
||||
if not selection.data:
|
||||
@ -111,73 +100,33 @@ class ClipboardBox(hippo.CanvasBox):
|
||||
on_disk=False)
|
||||
|
||||
def _object_added_cb(self, cb_service, object_id, name):
|
||||
icon = ClipboardIcon(object_id, name)
|
||||
icon.connect('button-release-event', self._icon_button_release_event_cb)
|
||||
self._set_icon_selected(icon)
|
||||
if self._icons:
|
||||
group = self._icons.values()[0]
|
||||
else:
|
||||
group = None
|
||||
|
||||
self.prepend(icon)
|
||||
icon = ClipboardIcon(object_id, name, group)
|
||||
self._tray.add_item(icon, 0)
|
||||
icon.show()
|
||||
|
||||
self._set_icon_selected(icon)
|
||||
self._icons[object_id] = icon
|
||||
|
||||
logging.debug('ClipboardBox: ' + object_id + ' was added.')
|
||||
|
||||
def _set_icon_selected(self, icon):
|
||||
logging.debug('_set_icon_selected')
|
||||
icon.props.selected = True
|
||||
if self._selected_icon:
|
||||
self._selected_icon.props.selected = False
|
||||
icon.props.active = True
|
||||
self._selected_icon = icon
|
||||
|
||||
def _put_in_clipboard(self, object_id):
|
||||
logging.debug('ClipboardBox._put_in_clipboard')
|
||||
targets = self._get_object_targets(object_id)
|
||||
if targets:
|
||||
clipboard = gtk.Clipboard()
|
||||
if not clipboard.set_with_data(targets,
|
||||
self._clipboard_data_get_cb,
|
||||
self._clipboard_clear_cb,
|
||||
targets):
|
||||
logging.error('GtkClipboard.set_with_data failed!')
|
||||
else:
|
||||
self._owns_clipboard = True
|
||||
|
||||
def _clipboard_data_get_cb(self, clipboard, selection, info, targets):
|
||||
if not selection.target in [target[0] for target in targets]:
|
||||
logging.warning('ClipboardBox._clipboard_data_get_cb: asked %s but' \
|
||||
' only have %r.' % (selection.target, targets))
|
||||
return
|
||||
object_id = self._selected_icon.get_object_id()
|
||||
cb_service = clipboardservice.get_instance()
|
||||
data = cb_service.get_object_data(object_id, selection.target)['DATA']
|
||||
|
||||
selection.set(selection.target, 8, data)
|
||||
|
||||
def _clipboard_clear_cb(self, clipboard, targets):
|
||||
logging.debug('ClipboardBox._clipboard_clear_cb')
|
||||
self._owns_clipboard = False
|
||||
|
||||
def _icon_button_release_event_cb(self, icon, event):
|
||||
logging.debug('ClipboardBox._icon_button_release_event_cb: %r' % icon.props.selected)
|
||||
if not icon.props.selected:
|
||||
self._set_icon_selected(icon)
|
||||
|
||||
def _object_deleted_cb(self, cb_service, object_id):
|
||||
icon = self._icons[object_id]
|
||||
position = self.get_children().index(icon)
|
||||
self.remove(icon)
|
||||
|
||||
if icon.props.selected and self.get_children():
|
||||
self._set_icon_selected(self.get_children()[position])
|
||||
|
||||
del self._icons[object_id]
|
||||
logging.debug('ClipboardBox: ' + object_id + ' was deleted.')
|
||||
|
||||
def _object_state_changed_cb(self, cb_service, object_id, name, percent,
|
||||
icon_name, preview, activity):
|
||||
icon = self._icons[object_id]
|
||||
icon.set_state(name, percent, icon_name, preview, activity)
|
||||
if icon.props.selected and percent == 100:
|
||||
self._put_in_clipboard(object_id)
|
||||
|
||||
def drag_motion_cb(self, widget, context, x, y, time):
|
||||
logging.debug('ClipboardBox._drag_motion_cb')
|
||||
context.drag_status(gtk.gdk.ACTION_COPY, time)
|
||||
@ -211,72 +160,3 @@ class ClipboardBox(hippo.CanvasBox):
|
||||
if not self._context_map.has_context(context):
|
||||
context.drop_finish(True, gtk.get_current_event_time())
|
||||
|
||||
def drag_data_get_cb(self, widget, context, selection, targetType, eventTime):
|
||||
logging.debug("drag_data_get_cb: requested target " + selection.target)
|
||||
|
||||
object_id = self._last_clicked_icon.get_object_id()
|
||||
cb_service = clipboardservice.get_instance()
|
||||
data = cb_service.get_object_data(object_id, selection.target)['DATA']
|
||||
|
||||
selection.set(selection.target, 8, data)
|
||||
|
||||
def button_press_event_cb(self, widget, event):
|
||||
logging.debug("button_press_event_cb")
|
||||
|
||||
if event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS:
|
||||
self._last_clicked_icon = self._get_icon_at_coords(event.x, event.y)
|
||||
if self._last_clicked_icon:
|
||||
self._pressed_button = event.button
|
||||
self._press_start_x = event.x
|
||||
self._press_start_y = event.y
|
||||
|
||||
return False
|
||||
|
||||
def motion_notify_event_cb(self, widget, event):
|
||||
|
||||
if not self._pressed_button:
|
||||
return True
|
||||
|
||||
# if the mouse button is not pressed, no drag should occurr
|
||||
if not event.state & gtk.gdk.BUTTON1_MASK:
|
||||
self._pressed_button = None
|
||||
return True
|
||||
|
||||
logging.debug("motion_notify_event_cb")
|
||||
|
||||
if event.is_hint:
|
||||
x, y, state = event.window.get_pointer()
|
||||
else:
|
||||
x = event.x
|
||||
y = event.y
|
||||
state = event.state
|
||||
|
||||
if widget.drag_check_threshold(int(self._press_start_x),
|
||||
int(self._press_start_y),
|
||||
int(x),
|
||||
int(y)):
|
||||
targets = self._get_object_targets(
|
||||
self._last_clicked_icon.get_object_id())
|
||||
|
||||
context = widget.drag_begin(targets,
|
||||
gtk.gdk.ACTION_COPY,
|
||||
1,
|
||||
event);
|
||||
|
||||
return True
|
||||
|
||||
def drag_end_cb(self, widget, drag_context):
|
||||
logging.debug("drag_end_cb")
|
||||
self._pressed_button = None
|
||||
|
||||
def _get_object_targets(self, object_id):
|
||||
cb_service = clipboardservice.get_instance()
|
||||
|
||||
attrs = cb_service.get_object(object_id)
|
||||
format_types = attrs[clipboardservice.FORMATS_KEY]
|
||||
|
||||
targets = []
|
||||
for format_type in format_types:
|
||||
targets.append((format_type, 0, 0))
|
||||
|
||||
return targets
|
||||
|
@ -37,7 +37,7 @@ class ClipboardPanelWindow(FrameWindow):
|
||||
self._clipboard.connect("owner-change", self._owner_change_cb)
|
||||
|
||||
self._clipboard_box = ClipboardBox()
|
||||
self.append(self._clipboard_box)
|
||||
self.append(self._clipboard_box, hippo.PACK_EXPAND)
|
||||
|
||||
# Receiving dnd drops
|
||||
self.drag_dest_set(0, [], 0)
|
||||
@ -45,20 +45,6 @@ class ClipboardPanelWindow(FrameWindow):
|
||||
self.connect("drag_drop", self._clipboard_box.drag_drop_cb)
|
||||
self.connect("drag_data_received",
|
||||
self._clipboard_box.drag_data_received_cb)
|
||||
|
||||
# Offering dnd drags
|
||||
self.drag_source_set(0, [], 0)
|
||||
self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
|
||||
gtk.gdk.POINTER_MOTION_HINT_MASK)
|
||||
self.connect("motion_notify_event",
|
||||
self._clipboard_box.motion_notify_event_cb)
|
||||
|
||||
# FIXME I'm not sure we should expose the canvas in the Window API
|
||||
self._canvas.connect("button_press_event",
|
||||
self._clipboard_box.button_press_event_cb)
|
||||
|
||||
self.connect("drag_end", self._clipboard_box.drag_end_cb)
|
||||
self.connect("drag_data_get", self._clipboard_box.drag_data_get_cb)
|
||||
|
||||
def _owner_change_cb(self, clipboard, event):
|
||||
logging.debug("owner_change_cb")
|
||||
|
@ -43,7 +43,7 @@ _ICON_NAME = 'network-wireless'
|
||||
|
||||
class AccessPointView(PulsingIcon):
|
||||
def __init__(self, model):
|
||||
PulsingIcon.__init__(self)
|
||||
PulsingIcon.__init__(self, size=style.SMALL_ICON_SIZE)
|
||||
self._model = model
|
||||
|
||||
self.connect('activated', self._activate_cb)
|
||||
|
@ -123,7 +123,7 @@ class ActivityToolbar(gtk.Toolbar):
|
||||
self._activity.share(private=True)
|
||||
|
||||
def _keep_clicked_cb(self, button):
|
||||
self._activity.save()
|
||||
self._activity.copy()
|
||||
|
||||
def _stop_clicked_cb(self, button):
|
||||
self._activity.close()
|
||||
@ -305,7 +305,7 @@ class Activity(Window, gtk.Container):
|
||||
elif scope == SHARE_NEIGHBORHOOD:
|
||||
self.share(private=False)
|
||||
else:
|
||||
logging.debug("Unknown share scope %d" % scope)
|
||||
logging.debug("Unknown share scope %r" % scope)
|
||||
except KeyError:
|
||||
pass
|
||||
elif create_jobject:
|
||||
@ -455,6 +455,8 @@ class Activity(Window, gtk.Container):
|
||||
def save(self):
|
||||
"""Request that the activity is saved to the Journal."""
|
||||
|
||||
logging.debug('Activity.save: %r' % self._jobject.object_id)
|
||||
|
||||
if self._updating_jobject:
|
||||
return
|
||||
|
||||
@ -483,6 +485,11 @@ class Activity(Window, gtk.Container):
|
||||
reply_handler=self._internal_save_cb,
|
||||
error_handler=self._internal_save_error_cb)
|
||||
|
||||
def copy(self):
|
||||
logging.debug('Activity.copy: %r' % self._jobject.object_id)
|
||||
self.save()
|
||||
self._jobject.object_id = None
|
||||
|
||||
def _internal_joined_cb(self, activity, success, err):
|
||||
"""Callback when join has finished"""
|
||||
self._shared_activity.disconnect(self._join_id)
|
||||
|
@ -219,11 +219,9 @@ class Bundle:
|
||||
file_names = zip_file.namelist()
|
||||
root_dir = self._get_bundle_root_dir(file_names)
|
||||
icon_path = os.path.join(root_dir, 'activity', self._icon + '.svg')
|
||||
print icon_path
|
||||
print file_names
|
||||
if icon_path in file_names:
|
||||
icon_data = zip_file.read(icon_path)
|
||||
temp_file, temp_file_path = tempfile.mkstemp(self._icon)
|
||||
temp_file, temp_file_path = tempfile.mkstemp(suffix='.svg', prefix=self._icon)
|
||||
os.write(temp_file, icon_data)
|
||||
os.close(temp_file)
|
||||
return temp_file_path
|
||||
|
@ -144,6 +144,10 @@ class ChunkedGlibHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
** [dcbw] modified to send Content-disposition filename too
|
||||
"""
|
||||
path = self.translate_path(self.path)
|
||||
if not path or not os.path.exists(path):
|
||||
self.send_error(404, "File not found")
|
||||
return None
|
||||
|
||||
f = None
|
||||
if os.path.isdir(path):
|
||||
for index in "index.html", "index.htm":
|
||||
|
Loading…
Reference in New Issue
Block a user