diff --git a/NEWS b/NEWS index c2206648..beabf43e 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,26 @@ +* #1984 Fix removing items from the clipboard. (tomeu) + +Snapshot b83a9ec27d + +* Fix font size on the XO. (marco) +* Make developer console work again. (marco) +* #2020 Use the new activity-stop icon. (marco) +* #2002 Tooltips for the zoom levels. (marco) +* #2018 Rename Save to Keep. (marco) +* #2020 Rename Close to Stop. (marco) + +Snapshot 42f0bcc48d + +* Fix broken import which was preventing startup. (marco) + +Snapshot 757b2b8ce6 + +* #2031: Do not die if battery properties are unavailable. (marco) +* #1953: Retrieve friends' nicks from the profile. (tomeu) +* #1720: Show the owner's buddy menu in the Groups view. (tomeu) + +Snapshot aa6a024368 + * #1825: Fix tab label padding. (marco) * #1823: Margin at the toolbar tabs bottom. (marco) * #1872, #1934: Hide palettes when closing activities or switching views. (tomeu) diff --git a/bin/sugar-install-bundle b/bin/sugar-install-bundle index 883dbfb6..3cce4cb1 100755 --- a/bin/sugar-install-bundle +++ b/bin/sugar-install-bundle @@ -3,6 +3,9 @@ import sys from sugar.activity.bundle import Bundle +from dbus.mainloop.glib import DBusGMainLoop +DBusGMainLoop(set_as_default=True) + bundle = Bundle(sys.argv[1]) bundle.install() diff --git a/maint-helper.py b/maint-helper.py index 9b76d519..8c64ca2d 100755 --- a/maint-helper.py +++ b/maint-helper.py @@ -83,8 +83,8 @@ def cmd_build_snapshot(): sugar_news += '%s - %s - %s\n\n' % (name, version, alphatag) f = open('NEWS', 'r') - for line in f.readline(): - if len(line) > 0: + for line in f.readlines(): + if len(line.strip()) > 0: sugar_news += line else: break diff --git a/po/POTFILES.in b/po/POTFILES.in index 2b6d5a09..2c034d81 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -7,4 +7,5 @@ shell/view/Shell.py shell/view/clipboardicon.py shell/view/home/HomeBox.py shell/view/home/MeshBox.py +shell/view/devices/battery.py sugar/activity/activity.py diff --git a/services/clipboard/clipboardobject.py b/services/clipboard/clipboardobject.py index 133e667d..c2ce339d 100644 --- a/services/clipboard/clipboardobject.py +++ b/services/clipboard/clipboardobject.py @@ -141,7 +141,7 @@ class Format: def get_data(self): return self._data - def _set_data(self, data): + def set_data(self, data): self._data = data def is_on_disk(self): diff --git a/services/clipboard/clipboardservice.py b/services/clipboard/clipboardservice.py index 73552c4f..569ed6b4 100644 --- a/services/clipboard/clipboardservice.py +++ b/services/clipboard/clipboardservice.py @@ -17,10 +17,16 @@ import logging import os import shutil +import urlparse +import tempfile + import dbus import dbus.service + from sugar import env from sugar import util +from sugar.objects import mime + from clipboardobject import ClipboardObject, Format NAME_KEY = 'NAME' @@ -52,34 +58,6 @@ class ClipboardService(dbus.service.Object): self._next_id += 1 return self._next_id - def _handle_file_completed(self, cb_object): - """If the object is an on-disk file, and it's at 100%, and we care about - it's file type, copy that file to $HOME and upate the clipboard object's - data to point to the new location""" - formats = cb_object.get_formats() - if not len(formats) or len(formats) > 1: - return - - format = formats.values()[0] - if not format.is_on_disk(): - return - - if not len(cb_object.get_activity()): - # no activity to handle this, don't autosave it - return - - # copy to homedir - src = format.get_data() - if not os.path.exists(src): - logging.debug("File %s doesn't appear to exist" % src) - return - dst = os.path.join(os.path.expanduser("~"), os.path.basename(src)) - try: - shutil.move(src, dst) - format._set_data(dst) - except IOError, e: - logging.debug("Couldn't move file %s to %s: %s" % (src, dst, e)) - # dbus methods @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, in_signature="s", out_signature="o") @@ -96,11 +74,13 @@ class ClipboardService(dbus.service.Object): def add_object_format(self, object_path, format_type, data, on_disk): logging.debug('ClipboardService.add_object_format') cb_object = self._objects[str(object_path)] - cb_object.add_format(Format(format_type, data, on_disk)) - - if on_disk: - logging.debug('Added format of type ' + format_type + ' with path at ' + data) + + if 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.object_state_changed(object_path, {NAME_KEY: cb_object.get_name(), @@ -132,7 +112,10 @@ class ClipboardService(dbus.service.Object): cb_object.set_percent(percent) if percent == 100: - self._handle_file_completed(cb_object) + for format_name, format in cb_object.get_formats().iteritems(): + if format.is_on_disk(): + new_uri = self._copy_file(format.get_data()) + format.set_data(new_uri) self.object_state_changed(object_path, {NAME_KEY: cb_object.get_name(), PERCENT_KEY: percent, @@ -183,6 +166,21 @@ class ClipboardService(dbus.service.Object): def object_state_changed(self, object_path, values): pass + 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) + + return 'file://' + new_file_path + _instance = None def get_instance(): diff --git a/services/console/interface/xo/Makefile.am b/services/console/interface/xo/Makefile.am index be9be793..dbc96c40 100644 --- a/services/console/interface/xo/Makefile.am +++ b/services/console/interface/xo/Makefile.am @@ -4,5 +4,4 @@ sugar_PYTHON = \ xo.py \ cpu.py \ system.py \ - battery.py \ nandflash.py diff --git a/services/console/interface/xo/battery.py b/services/console/interface/xo/battery.py deleted file mode 100644 index 8731d8b9..00000000 --- a/services/console/interface/xo/battery.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (C) 2007, Eduardo Silva (edsiper@gmail.com). -# -# 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 gtk -import gobject - -from label import Label -from graphics.box import BoxGraphic - -class XO_Battery(gtk.Fixed): - - def __init__(self): - gtk.Fixed.__init__(self) - - self._frame_text = 'Battery Status' - self.frame = gtk.Frame(self._frame_text) - self.set_border_width(10) - - self._battery_charge = self._get_battery_status() - - self._battery_box = BoxGraphic() - self._battery_box.set_size_request(70, 150) - self._battery_box.set_capacity(self._battery_charge) - - fixed = gtk.Fixed(); - fixed.set_border_width(10) - fixed.add(self._battery_box) - - hbox = gtk.HBox(False, 0) - hbox.pack_start(fixed, False, False, 4) - - # Battery info - table = gtk.Table(2, 2) - table.set_border_width(5) - table.set_col_spacings(7) - table.set_row_spacings(7) - - label_charge = Label('Charge: ' , Label.DESCRIPTION) - self.label_charge_value = Label(str(self._battery_charge) + '%', Label.DESCRIPTION) - - table.attach(label_charge, 0, 1, 0, 1) - table.attach(self.label_charge_value, 1,2, 0,1) - - # Charging - """ - hbox_charging = gtk.HBox(False, 2) - l_charging = gtk.Label('Charging: ') - l_charging.set_justify(gtk.JUSTIFY_LEFT) - hbox_charging.pack_start(l_charging, False, False, 0) - - self._label_charging = gtk.Label('No') - self._label_charging.set_justify(gtk.JUSTIFY_LEFT) - - hbox_charging.pack_start(self._label_charging, False, False, 0) - """ - - alignment = gtk.Alignment(0,0,0,0) - alignment.add(table) - - hbox.pack_start(alignment, False, False, 0) - self.frame.add(hbox) - self.add(self.frame) - self.show_all() - - def update_status(self): - - new_charge = self._get_battery_status() - frame_label = str(self._battery_charge) + '%' - - if new_charge != self._battery_charge: - self._battery_charge = self._get_battery_status() - self.label_charge_value.set_text(frame_label) - self._battery_box.set_capacity(self._battery_charge) - - def _get_battery_status(self): - battery_class_path = '/sys/class/battery/psu_0/' - capacity_path = battery_class_path + 'capacity_percentage' - try: - f = open(capacity_path, 'r') - val = f.read().split('\n') - capacity = int(val[0]) - f.close() - except: - capacity = 0 - - return capacity diff --git a/services/console/interface/xo/xo.py b/services/console/interface/xo/xo.py index 981d2e52..d2056058 100644 --- a/services/console/interface/xo/xo.py +++ b/services/console/interface/xo/xo.py @@ -23,7 +23,6 @@ import string from cpu import XO_CPU from system import XO_System -from battery import XO_Battery from nandflash import XO_NandFlash class Interface: @@ -40,11 +39,9 @@ class Interface: self.vbox.pack_start(xo_cpu, False, False, 0) # Graphics: Battery Status, NandFlash - self._xo_battery = XO_Battery() self._xo_nandflash = XO_NandFlash() hbox = gtk.HBox(False, 2) - hbox.pack_start(self._xo_battery, False, False, 0) hbox.pack_start(self._xo_nandflash, False, False, 0) self.vbox.pack_start(hbox, False, False, 0) @@ -54,7 +51,6 @@ class Interface: gobject.timeout_add(5000, self._update_components) def _update_components(self): - self._xo_battery.update_status() self._xo_nandflash.update_status() return True diff --git a/shell/model/BuddyModel.py b/shell/model/BuddyModel.py index 75c044ac..9f86e57e 100644 --- a/shell/model/BuddyModel.py +++ b/shell/model/BuddyModel.py @@ -36,7 +36,7 @@ class BuddyModel(gobject.GObject): ([gobject.TYPE_PYOBJECT])) } - def __init__(self, key=None, buddy=None): + def __init__(self, key=None, buddy=None, nick=None): if (key and buddy) or (not key and not buddy): raise RuntimeError("Must specify only _one_ of key or buddy.") @@ -51,7 +51,6 @@ class BuddyModel(gobject.GObject): self._pservice = presenceservice.get_instance() self._buddy = None - self._nick = None # If given just a key, try to get the buddy from the PS first if not buddy: @@ -72,7 +71,7 @@ class BuddyModel(gobject.GObject): self._key = key # Set color to 'inactive'/'disconnected' self._set_color_from_string(_NOT_PRESENT_COLOR) - self._name = "Unknown buddy" + self._nick = nick def _set_color_from_string(self, color_string): self._color = XoColor(color_string) diff --git a/shell/model/Friends.py b/shell/model/Friends.py index 23ce94a8..2b7d6bfd 100644 --- a/shell/model/Friends.py +++ b/shell/model/Friends.py @@ -69,7 +69,7 @@ class Friends(gobject.GObject): # HACK: don't screw up on old friends files if len(key) < 20: continue - buddy = BuddyModel(key=key) + buddy = BuddyModel(key=key, nick=cp.get(key, 'nick')) self.add_friend(buddy) except Exception, exc: logging.error("Error parsing friends file: %s" % exc) diff --git a/shell/model/devices/battery.py b/shell/model/devices/battery.py index cdb49948..853d00ec 100644 --- a/shell/model/devices/battery.py +++ b/shell/model/devices/battery.py @@ -14,6 +14,8 @@ # 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 gobject import dbus @@ -45,9 +47,30 @@ class Device(device.Device): 'org.freedesktop.Hal', udi) - self._level = self._battery.GetProperty(_LEVEL_PROP) - self._charging = self._battery.GetProperty(_CHARGING_PROP) - self._discharging = self._battery.GetProperty(_DISCHARGING_PROP) + self._level = self._get_level() + self._charging = self._get_charging() + self._discharging = self._get_discharging() + + def _get_level(self): + try: + return self._battery.GetProperty(_LEVEL_PROP) + except dbus.DBusException: + logging.error('Cannot access %s' % _LEVEL_PROP) + return 0 + + def _get_charging(self): + try: + return self._battery.GetProperty(_CHARGING_PROP) + except dbus.DBusException: + logging.error('Cannot access %s' % _CHARGING_PROP) + return False + + def _get_discharging(self): + try: + return self._battery.GetProperty(_DISCHARGING_PROP) + except dbus.DBusException: + logging.error('Cannot access %s' % _DISCHARGING_PROP) + return False def do_get_property(self, pspec): if pspec.name == 'level': @@ -63,11 +86,11 @@ class Device(device.Device): def _battery_changed(self, num_changes, changes_list): for change in changes_list: if change[0] == _LEVEL_PROP: - self._level = self._battery.GetProperty(_LEVEL_PROP) + self._level = self._get_level() self.notify('level') elif change[0] == _CHARGING_PROP: - self._charging = self._battery.GetProperty(_CHARGING_PROP) + self._charging = self._get_charging() self.notify('charging') elif change[0] == _DISCHARGING_PROP: - self._discharging = self._battery.GetProperty(_DISCHARGING_PROP) + self._discharging = self._get_discharging() self.notify('discharging') diff --git a/shell/shellservice.py b/shell/shellservice.py index b4c96ffc..c612d6e2 100644 --- a/shell/shellservice.py +++ b/shell/shellservice.py @@ -56,6 +56,9 @@ class ShellService(dbus.service.Object): self._home_model.connect('active-activity-changed', self._cur_activity_changed_cb) + bundle_registry = bundleregistry.get_registry() + bundle_registry.connect('bundle-added', self._bundle_added_cb) + bus = dbus.SessionBus() bus_name = dbus.service.BusName(_DBUS_SERVICE, bus=bus) dbus.service.Object.__init__(self, bus_name, _DBUS_PATH) @@ -121,6 +124,10 @@ class ShellService(dbus.service.Object): return result + @dbus.service.signal(_DBUS_ACTIVITY_REGISTRY_IFACE, signature="a{sv}") + def ActivityAdded(self, activity_info): + pass + @dbus.service.signal(_DBUS_OWNER_IFACE, signature="s") def ColorChanged(self, color): pass @@ -158,3 +165,7 @@ class ShellService(dbus.service.Object): 'icon': bundle.get_icon(), 'service_name': bundle.get_service_name(), 'path': bundle.get_path()} + + def _bundle_added_cb(self, bundle_registry, bundle): + self.ActivityAdded(self._bundle_to_dict(bundle)) + diff --git a/shell/view/frame/Makefile.am b/shell/view/frame/Makefile.am index ff2bff35..4a7083b2 100644 --- a/shell/view/frame/Makefile.am +++ b/shell/view/frame/Makefile.am @@ -8,6 +8,6 @@ sugar_PYTHON = \ FriendsBox.py \ eventarea.py \ frame.py \ - ZoomBox.py \ overlaybox.py \ - framewindow.py + framewindow.py \ + zoombox.py diff --git a/shell/view/frame/clipboardbox.py b/shell/view/frame/clipboardbox.py index 7cb3698f..60c154ba 100644 --- a/shell/view/frame/clipboardbox.py +++ b/shell/view/frame/clipboardbox.py @@ -13,16 +13,14 @@ # 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 shutil + import os import logging -import urlparse import hippo import gtk from sugar import util -from sugar.objects import mime from view.clipboardicon import ClipboardIcon from sugar.clipboard import clipboardservice @@ -101,21 +99,10 @@ class ClipboardBox(hippo.CanvasBox): uris = selection.data.split('\n') if len(uris) > 1: raise NotImplementedError('Multiple uris in text/uri-list still not supported.') - uri = urlparse.urlparse(uris[0]) - 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) - file_name = root + '.' + mime.get_primary_extension(mime_type) - - # Copy the file, as it will be deleted when the dnd operation finishes. - new_file_path = os.path.join(path, 'cb' + file_name) - shutil.copyfile(uri.path, new_file_path) cb_service.add_object_format(object_id, selection.type, - "file://" + new_file_path, + uris[0], on_disk=True) else: cb_service.add_object_format(object_id, diff --git a/shell/view/frame/frame.py b/shell/view/frame/frame.py index 5210f57a..2a94754c 100644 --- a/shell/view/frame/frame.py +++ b/shell/view/frame/frame.py @@ -27,7 +27,7 @@ from sugar.clipboard import clipboardservice from view.frame.eventarea import EventArea from view.frame.ActivitiesBox import ActivitiesBox -from view.frame.ZoomBox import ZoomBox +from view.frame.zoombox import ZoomBox from view.frame.overlaybox import OverlayBox from view.frame.FriendsBox import FriendsBox from view.frame.framewindow import FrameWindow diff --git a/shell/view/frame/ZoomBox.py b/shell/view/frame/zoombox.py similarity index 75% rename from shell/view/frame/ZoomBox.py rename to shell/view/frame/zoombox.py index 5bfb0e76..f4b8535d 100644 --- a/shell/view/frame/ZoomBox.py +++ b/shell/view/frame/zoombox.py @@ -14,10 +14,14 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +from gettext import gettext as _ + import hippo from sugar.graphics import color +from sugar.graphics.palette import Palette from sugar.graphics.iconbutton import IconButton +from frameinvoker import FrameCanvasInvoker from model.shellmodel import ShellModel @@ -35,6 +39,11 @@ class ZoomBox(hippo.CanvasBox): ShellModel.ZOOM_MESH) self.append(icon) + palette = Palette(_('Neighborhood')) + palette.props.invoker = FrameCanvasInvoker(icon) + palette.set_group_id('frame') + icon.set_palette(palette) + icon = IconButton(icon_name='theme:stock-zoom-friends', stroke_color=color.BLACK, fill_color=color.WHITE) @@ -43,6 +52,11 @@ class ZoomBox(hippo.CanvasBox): ShellModel.ZOOM_FRIENDS) self.append(icon) + palette = Palette(_('Group')) + palette.props.invoker = FrameCanvasInvoker(icon) + palette.set_group_id('frame') + icon.set_palette(palette) + icon = IconButton(icon_name='theme:stock-zoom-home', stroke_color=color.BLACK, fill_color=color.WHITE) @@ -51,6 +65,11 @@ class ZoomBox(hippo.CanvasBox): ShellModel.ZOOM_HOME) self.append(icon) + palette = Palette(_('Home')) + palette.props.invoker = FrameCanvasInvoker(icon) + palette.set_group_id('frame') + icon.set_palette(palette) + icon = IconButton(icon_name='theme:stock-zoom-activity', stroke_color=color.BLACK, fill_color=color.WHITE) @@ -59,5 +78,10 @@ class ZoomBox(hippo.CanvasBox): ShellModel.ZOOM_ACTIVITY) self.append(icon) + palette = Palette(_('Activity')) + palette.props.invoker = FrameCanvasInvoker(icon) + palette.set_group_id('frame') + icon.set_palette(palette) + def _level_clicked_cb(self, item, level): self._shell.set_zoom_level(level) diff --git a/shell/view/home/FriendsBox.py b/shell/view/home/FriendsBox.py index 39afa0bc..77218b04 100644 --- a/shell/view/home/FriendsBox.py +++ b/shell/view/home/FriendsBox.py @@ -19,9 +19,12 @@ import random import hippo import gobject +from sugar import profile from sugar.graphics.spreadlayout import SpreadLayout from sugar.graphics import units -from view.home.MyIcon import MyIcon + +from model.BuddyModel import BuddyModel +from view.BuddyIcon import BuddyIcon from view.home.FriendView import FriendView class FriendsBox(hippo.CanvasBox): @@ -35,8 +38,10 @@ class FriendsBox(hippo.CanvasBox): self._layout = SpreadLayout() self.set_layout(self._layout) - self._my_icon = MyIcon(units.LARGE_ICON_SCALE) - self._layout.add_center(self._my_icon) + buddy_model = BuddyModel(key=profile.get_pubkey()) + self._owner_icon = BuddyIcon(shell, buddy_model) + self._owner_icon.props.scale = units.LARGE_ICON_SCALE + self._layout.add_center(self._owner_icon) friends = self._shell.get_model().get_friends() diff --git a/sugar/activity/activity.py b/sugar/activity/activity.py index 8a971997..32027035 100644 --- a/sugar/activity/activity.py +++ b/sugar/activity/activity.py @@ -64,11 +64,11 @@ class ActivityToolbar(gtk.Toolbar): self.insert(separator, -1) separator.show() - self.save = ToolButton('document-save') - self.save.set_tooltip(_('Save')) - self.save.connect('clicked', self._save_clicked_cb) - self.insert(self.save, -1) - self.save.show() + 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() self.share = ToolButton('stock-share-mesh') self.share.set_tooltip(_('Share')) @@ -83,21 +83,21 @@ class ActivityToolbar(gtk.Toolbar): self.insert(separator, -1) separator.show() - self.close = ToolButton('window-close') - self.close.set_tooltip(_('Close')) - self.close.connect('clicked', self._close_clicked_cb) - self.insert(self.close, -1) - self.close.show() + self.stop = ToolButton('activity-stop') + self.stop.set_tooltip(_('Stop')) + self.stop.connect('clicked', self._stop_clicked_cb) + self.insert(self.stop, -1) + self.stop.show() self._update_title_sid = None def _share_clicked_cb(self, button): self._activity.share() - def _save_clicked_cb(self, button): + def _keep_clicked_cb(self, button): self._activity.save() - def _close_clicked_cb(self, button): + def _stop_clicked_cb(self, button): self._activity.close() self._activity.destroy() diff --git a/sugar/activity/bundlebuilder.py b/sugar/activity/bundlebuilder.py index a82d744b..8e8c49d6 100644 --- a/sugar/activity/bundlebuilder.py +++ b/sugar/activity/bundlebuilder.py @@ -50,26 +50,22 @@ class _DefaultFileList(list): self.append(os.path.join('activity', name)) self.append('activity/activity.info') - self.append('setup.py') if os.path.isfile(_get_source_path('NEWS')): self.append('NEWS') -class _ManifestFileList(list): - def __init__(self, manifest=None): +class _ManifestFileList(_DefaultFileList): + def __init__(self, manifest): + _DefaultFileList.__init__(self) self.append(manifest) f = open(manifest,'r') for line in f.readlines(): stripped_line = line.strip() - if stripped_line: + if stripped_line and not stripped_line in self: self.append(stripped_line) f.close() - defaults = _DefaultFileList() - for path in defaults: - self.append(path) - def _extract_bundle(source_file, dest_dir): if not os.path.exists(dest_dir): os.mkdir(dest_dir) @@ -270,8 +266,8 @@ def cmd_release(bundle_name, manifest): sugar_news += '%s - %d\n\n' % (bundle_name, version) f = open(news_path,'r') - for line in f.readline(): - if len(line) > 0: + for line in f.readlines(): + if len(line.strip()) > 0: sugar_news += line else: break diff --git a/sugar/activity/registry.py b/sugar/activity/registry.py index 171f740e..b19abee6 100644 --- a/sugar/activity/registry.py +++ b/sugar/activity/registry.py @@ -15,6 +15,8 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. +import logging + import dbus _SHELL_SERVICE = "org.laptop.Shell" @@ -39,6 +41,11 @@ class ActivityRegistry(object): bus = dbus.SessionBus() bus_object = bus.get_object(_SHELL_SERVICE, _SHELL_PATH) self._registry = dbus.Interface(bus_object, _REGISTRY_IFACE) + self._registry.connect_to_signal('ActivityAdded', self._activity_added_cb) + + # Two caches fo saving some travel across dbus. + self._service_name_to_activity_info = {} + self._mime_type_to_activities = {} def _convert_info_list(self, info_list): result = [] @@ -49,16 +56,33 @@ class ActivityRegistry(object): return result def get_activity(self, service_name): + if self._service_name_to_activity_info.has_key(service_name): + return self._service_name_to_activity_info[service_name] + info_dict = self._registry.GetActivity(service_name) - return _activity_info_from_dict(info_dict) + activity_info = _activity_info_from_dict(info_dict) + + self._service_name_to_activity_info[service_name] = activity_info + return activity_info def find_activity(self, name): info_list = self._registry.FindActivity(name) return self._convert_info_list(info_list) def get_activities_for_type(self, mime_type): + if self._mime_type_to_activities.has_key(mime_type): + return self._mime_type_to_activities[mime_type] + info_list = self._registry.GetActivitiesForType(mime_type) - return self._convert_info_list(info_list) + activities = self._convert_info_list(info_list) + + self._mime_type_to_activities[mime_type] = activities + return activities + + def _activity_added_cb(self, bundle): + logging.debug('ActivityRegistry._activity_added_cb: flushing caches') + self._service_name_to_activity_info.clear() + self._mime_type_to_activities.clear() _registry = None diff --git a/sugar/graphics/style.py b/sugar/graphics/style.py index fedbc9ec..1306caad 100644 --- a/sugar/graphics/style.py +++ b/sugar/graphics/style.py @@ -18,6 +18,10 @@ import gtk import pango +def _get_screen_dpi(): + xft_dpi = gtk.settings_get_default().get_property('gtk-xft-dpi') + return float(xft_dpi / 1024) + def _compute_zoom_factor(): return gtk.gdk.screen_width() / 1200.0 @@ -43,17 +47,21 @@ class Font(object): def get_pango_desc(self): return pango.FontDescription(self._desc) +_XO_DPI = 200.0 + _FOCUS_LINE_WIDTH = 2 _TAB_CURVATURE = 1 ZOOM_FACTOR = _compute_zoom_factor() -FONT_SIZE = _zoom(7 * 200 / 72.0) +FONT_SIZE = _zoom(7 * _XO_DPI / _get_screen_dpi()) FONT_NORMAL = Font('Bitstream Vera Sans %d' % FONT_SIZE) FONT_BOLD = Font('Bitstream Vera Sans bold %d' % FONT_SIZE) +FONT_NORMAL_H = _compute_font_height(FONT_NORMAL) +FONT_BOLD_H = _compute_font_height(FONT_BOLD) TOOLBOX_SEPARATOR_HEIGHT = _zoom(9) TOOLBOX_HORIZONTAL_PADDING = _zoom(75) -TOOLBOX_TAB_VBORDER = int((_zoom(36) - FONT_SIZE - _FOCUS_LINE_WIDTH) / 2) +TOOLBOX_TAB_VBORDER = int((_zoom(36) - FONT_NORMAL_H - _FOCUS_LINE_WIDTH) / 2) TOOLBOX_TAB_HBORDER = _zoom(15) - _FOCUS_LINE_WIDTH - _TAB_CURVATURE TOOLBOX_TAB_LABEL_WIDTH = _zoom(150 - 15 * 2) diff --git a/sugar/objects/objecttype.py b/sugar/objects/objecttype.py index dd2da548..a8192168 100644 --- a/sugar/objects/objecttype.py +++ b/sugar/objects/objecttype.py @@ -36,20 +36,39 @@ class ObjectType(object): self.name = name self.icon = icon self.mime_types = mime_types + + self._type_id_to_type = {} + self._mime_type_to_type = {} class ObjectTypeRegistry(object): def __init__(self): bus = dbus.SessionBus() bus_object = bus.get_object(_SERVICE, _PATH) self._registry = dbus.Interface(bus_object, _IFACE) + + # Two caches fo saving some travel across dbus. + self._type_id_to_type = {} + self._mime_type_to_type = {} def get_type(self, type_id): + if self._type_id_to_type.has_key(type_id): + return self._type_id_to_type[type_id] + type_dict = self._registry.GetType(type_id) - return _object_type_from_dict(type_dict) + object_type = _object_type_from_dict(type_dict) + + self._type_id_to_type[type_id] = object_type + return object_type def get_type_for_mime(self, mime_type): + if self._mime_type_to_type.has_key(mime_type): + return self._mime_type_to_type[mime_type] + type_dict = self._registry.GetTypeForMIME(mime_type) - return _object_type_from_dict(type_dict) + object_type = _object_type_from_dict(type_dict) + + self._mime_type_to_type[mime_type] = object_type + return object_type _registry = None