# Copyright (C) 2008 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 statvfs from gettext import gettext as _ import logging from gi.repository import GConf import glib from gi.repository import Gtk from sugar3 import env from sugar3.graphics.palette import Palette from sugar3.graphics.palettemenuitem import PaletteMenuItem from sugar3.graphics.palettemenuitem import PaletteMenuItemSeparator from sugar3.graphics.menuitem import MenuItem from sugar3.graphics.icon import Icon from sugar3.graphics import style from sugar3.graphics.xocolor import XoColor from sugar3.activity.i18n import pgettext from jarabe.model import shell from jarabe.view.viewsource import setup_view_source from jarabe.journal import misc class BasePalette(Palette): def __init__(self, home_activity): Palette.__init__(self) self._notify_launch_hid = None if home_activity.props.launch_status == shell.Activity.LAUNCHING: self._notify_launch_hid = home_activity.connect( \ 'notify::launch-status', self.__notify_launch_status_cb) self.set_primary_text(glib.markup_escape_text(_('Starting...'))) elif home_activity.props.launch_status == shell.Activity.LAUNCH_FAILED: self._on_failed_launch() else: self.setup_palette() def setup_palette(self): raise NotImplementedError def _on_failed_launch(self): message = _('Activity failed to start') self.set_primary_text(glib.markup_escape_text(message)) def __notify_launch_status_cb(self, home_activity, pspec): home_activity.disconnect(self._notify_launch_hid) self._notify_launch_hid = None if home_activity.props.launch_status == shell.Activity.LAUNCH_FAILED: self._on_failed_launch() else: self.setup_palette() class CurrentActivityPalette(BasePalette): def __init__(self, home_activity): self._home_activity = home_activity BasePalette.__init__(self, home_activity) def setup_palette(self): activity_name = self._home_activity.get_activity_name() if activity_name: self.props.primary_text = glib.markup_escape_text(activity_name) title = self._home_activity.get_title() if title and title != activity_name: self.props.secondary_text = glib.markup_escape_text(title) menu_item = MenuItem(_('Resume'), 'activity-start') menu_item.connect('activate', self.__resume_activate_cb) self.menu.append(menu_item) menu_item.show() # TODO: share-with, keep menu_item = MenuItem(_('View Source'), 'view-source') # TODO Make this accelerator translatable menu_item.props.accelerator = 'v' menu_item.connect('activate', self.__view_source__cb) self.menu.append(menu_item) menu_item.show() separator = Gtk.SeparatorMenuItem() self.menu.append(separator) separator.show() menu_item = MenuItem(_('Stop'), 'activity-stop') menu_item.connect('activate', self.__stop_activate_cb) self.menu.append(menu_item) menu_item.show() def __resume_activate_cb(self, menu_item): self._home_activity.get_window().activate(Gtk.get_current_event_time()) def __view_source__cb(self, menu_item): setup_view_source(self._home_activity) shell_model = shell.get_model() if self._home_activity is not shell_model.get_active_activity(): self._home_activity.get_window().activate( \ Gtk.get_current_event_time()) def __stop_activate_cb(self, menu_item): self._home_activity.get_window().close(1) class ActivityPalette(Palette): __gtype_name__ = 'SugarActivityPalette' def __init__(self, activity_info): self._activity_info = activity_info client = GConf.Client.get_default() color = XoColor(client.get_string('/desktop/sugar/user/color')) activity_icon = Icon(file=activity_info.get_icon(), xo_color=color, icon_size=Gtk.IconSize.LARGE_TOOLBAR) name = activity_info.get_name() Palette.__init__(self, primary_text=glib.markup_escape_text(name), icon=activity_icon) xo_color = XoColor('%s,%s' % (style.COLOR_WHITE.get_svg(), style.COLOR_TRANSPARENT.get_svg())) menu_item = MenuItem(text_label=_('Start new'), file_name=activity_info.get_icon(), xo_color=xo_color) menu_item.connect('activate', self.__start_activate_cb) self.menu.append(menu_item) menu_item.show() # TODO: start-with def __start_activate_cb(self, menu_item): self.popdown(immediate=True) misc.launch(self._activity_info) class JournalPalette(BasePalette): def __init__(self, home_activity): self._home_activity = home_activity self._progress_bar = None self._free_space_label = None BasePalette.__init__(self, home_activity) def setup_palette(self): title = self._home_activity.get_title() self.set_primary_text(glib.markup_escape_text(title)) vbox = Gtk.VBox() self.set_content(vbox) vbox.show() menu_item = PaletteMenuItem(_('Show contents')) icon = Icon(file=self._home_activity.get_icon_path(), icon_size=Gtk.IconSize.MENU, xo_color=self._home_activity.get_icon_color()) menu_item.set_image(icon) icon.show() menu_item.connect('activate', self.__open_activate_cb) vbox.add(menu_item) menu_item.show() separator = PaletteMenuItemSeparator() vbox.pack_start(separator, True, True, 0) separator.show() self._progress_bar = Gtk.ProgressBar() vbox.add(self._progress_bar) self._progress_bar.show() self._free_space_label = Gtk.Label() self._free_space_label.set_alignment(0.5, 0.5) vbox.add(self._free_space_label) self._free_space_label.show() self.connect('popup', self.__popup_cb) def __open_activate_cb(self, menu_item): self._home_activity.get_window().activate(Gtk.get_current_event_time()) def __popup_cb(self, palette): stat = os.statvfs(env.get_profile_path()) free_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL] total_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BLOCKS] fraction = (total_space - free_space) / float(total_space) self._progress_bar.props.fraction = fraction self._free_space_label.props.label = _('%(free_space)d MB Free') % \ {'free_space': free_space / (1024 * 1024)} class VolumePalette(Palette): def __init__(self, mount): Palette.__init__(self, label=mount.get_name()) self._mount = mount path = mount.get_root().get_path() self.props.secondary_text = glib.markup_escape_text(path) self.content_box = Gtk.VBox() self.set_content(self.content_box) self.content_box.show() menu_item = PaletteMenuItem(pgettext('Volume', 'Remove')) icon = Icon(icon_name='media-eject', icon_size=Gtk.IconSize.MENU) menu_item.set_image(icon) icon.show() menu_item.connect('activate', self.__unmount_activate_cb) self.content_box.pack_start(menu_item, True, True, 0) menu_item.show() separator = PaletteMenuItemSeparator() self.content_box.pack_start(separator, True, True, 0) separator.show() self._progress_bar = Gtk.ProgressBar() self.content_box.pack_start(self._progress_bar, True, True, 0) self._progress_bar.show() self._free_space_label = Gtk.Label() self._free_space_label.set_alignment(0.5, 0.5) self.content_box.pack_start(self._free_space_label, True, True, 0) self._free_space_label.show() self.connect('popup', self.__popup_cb) def __unmount_activate_cb(self, menu_item): flags = 0 mount_operation = Gtk.MountOperation( \ parent=self.content_box.get_toplevel()) cancellable = None user_data = None self._mount.unmount_with_operation(flags, mount_operation, cancellable, self.__unmount_cb, user_data) def __unmount_cb(self, mount, result, user_data): logging.debug('__unmount_cb %r %r', mount, result) mount.unmount_with_operation_finish(result) def __popup_cb(self, palette): mount_point = self._mount.get_root().get_path() stat = os.statvfs(mount_point) free_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BAVAIL] total_space = stat[statvfs.F_BSIZE] * stat[statvfs.F_BLOCKS] fraction = (total_space - free_space) / float(total_space) self._progress_bar.props.fraction = fraction self._free_space_label.props.label = _('%(free_space)d MB Free') % \ {'free_space': free_space / (1024 * 1024)}