diff options
author | Marco Pesenti Gritti <mpgritti@gmail.com> | 2008-10-03 23:14:32 (GMT) |
---|---|---|
committer | Marco Pesenti Gritti <mpgritti@gmail.com> | 2008-10-03 23:14:32 (GMT) |
commit | 8ca1368eec29f1378ac1d81e3494c6d503355d04 (patch) | |
tree | a285efd64b378e8fab261a059e0212c727e18ea2 /extensions | |
parent | baed28d9da4c47477abb13833c92bab0623e41e3 (diff) |
Move controlpanel extensions to the extensions path.
Diffstat (limited to 'extensions')
31 files changed, 2246 insertions, 0 deletions
diff --git a/extensions/Makefile.am b/extensions/Makefile.am new file mode 100644 index 0000000..464800b --- /dev/null +++ b/extensions/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = cpsection diff --git a/extensions/cpsection/Makefile.am b/extensions/cpsection/Makefile.am new file mode 100644 index 0000000..0e69fd1 --- /dev/null +++ b/extensions/cpsection/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = aboutme aboutxo datetime frame language network power + +sugardir = $(pkgdatadir)/extensions/cpsection +sugar_PYTHON = __init__.py diff --git a/extensions/cpsection/__init__.py b/extensions/cpsection/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/extensions/cpsection/__init__.py diff --git a/extensions/cpsection/aboutme/Makefile.am b/extensions/cpsection/aboutme/Makefile.am new file mode 100644 index 0000000..9ca91d2 --- /dev/null +++ b/extensions/cpsection/aboutme/Makefile.am @@ -0,0 +1,6 @@ +sugardir = $(pkgdatadir)/extensions/cpsection/aboutme + +sugar_PYTHON = \ + __init__.py \ + model.py \ + view.py diff --git a/extensions/cpsection/aboutme/__init__.py b/extensions/cpsection/aboutme/__init__.py new file mode 100644 index 0000000..b683e28 --- /dev/null +++ b/extensions/cpsection/aboutme/__init__.py @@ -0,0 +1,25 @@ +# Copyright (C) 2008, OLPC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from gettext import gettext as _ +from sugar import profile + +CLASS = 'AboutMe' +ICON = 'module-about_me' +TITLE = _('About Me') +COLOR = profile.get_color() + + diff --git a/extensions/cpsection/aboutme/model.py b/extensions/cpsection/aboutme/model.py new file mode 100644 index 0000000..3818792 --- /dev/null +++ b/extensions/cpsection/aboutme/model.py @@ -0,0 +1,116 @@ +# 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 +# + +from gettext import gettext as _ + +from sugar import profile +from sugar.graphics.xocolor import XoColor + +_COLORS = {'red': {'dark':'#b20008', 'medium':'#e6000a', 'light':'#ffadce'}, + 'orange': {'dark':'#9a5200', 'medium':'#c97e00', 'light':'#ffc169'}, + 'yellow': {'dark':'#807500', 'medium':'#be9e00', 'light':'#fffa00'}, + 'green': {'dark':'#008009', 'medium':'#00b20d', 'light':'#8bff7a'}, + 'blue': {'dark':'#00588c', 'medium':'#005fe4', 'light':'#bccdff'}, + 'purple': {'dark':'#5e008c', 'medium':'#7f00bf', 'light':'#d1a3ff'} + } + +_MODIFIERS = ('dark', 'medium', 'light') + +def get_nick(): + return profile.get_nick_name() + +def print_nick(): + print get_nick() + +def set_nick(nick): + """Set the nickname. + nick : e.g. 'walter' + """ + if not nick: + raise ValueError(_("You must enter a name.")) + pro = profile.get_profile() + if not isinstance(nick, unicode): + nick = unicode(nick, 'utf-8') + pro.nick_name = nick + pro.save() + return 1 + +def get_color(): + return profile.get_color() + +def print_color(): + color_string = get_color().to_string() + tmp = color_string.split(',') + + stroke_tuple = None + fill_tuple = None + for color in _COLORS: + for hue in _COLORS[color]: + if _COLORS[color][hue] == tmp[0]: + stroke_tuple = (color, hue) + if _COLORS[color][hue] == tmp[1]: + fill_tuple = (color, hue) + + if stroke_tuple is not None: + print _('stroke: color=%s hue=%s') % (stroke_tuple[0], + stroke_tuple[1]) + else: + print _('stroke: %s') % (tmp[0]) + if fill_tuple is not None: + print _('fill: color=%s hue=%s') % (fill_tuple[0], fill_tuple[1]) + else: + print _('fill: %s') % (tmp[1]) + +def set_color(stroke, fill, stroke_modifier='medium', fill_modifier='medium'): + """Set the system color by setting a fill and stroke color. + fill : [red, orange, yellow, blue, green, purple] + stroke : [red, orange, yellow, blue, green, purple] + hue stroke : [dark, medium, light] (optional) + hue fill : [dark, medium, light] (optional) + """ + + if stroke_modifier not in _MODIFIERS or fill_modifier not in _MODIFIERS: + print (_("Error in specified color modifiers.")) + return + if stroke not in _COLORS or fill not in _COLORS: + print (_("Error in specified colors.")) + return + + if stroke_modifier == fill_modifier: + if fill_modifier == 'medium': + fill_modifier = 'light' + else: + fill_modifier = 'medium' + + color = _COLORS[stroke][stroke_modifier] + ',' \ + + _COLORS[fill][fill_modifier] + pro = profile.get_profile() + pro.color = XoColor(color) + pro.save() + return 1 + +def get_color_xo(): + return profile.get_color() + +def set_color_xo(color): + """Set a color with an XoColor + This method is used by the graphical user interface + """ + pro = profile.get_profile() + pro.color = color + pro.save() + return 1 diff --git a/extensions/cpsection/aboutme/view.py b/extensions/cpsection/aboutme/view.py new file mode 100644 index 0000000..fc4f351 --- /dev/null +++ b/extensions/cpsection/aboutme/view.py @@ -0,0 +1,226 @@ +# Copyright (C) 2008, OLPC +# +# 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 gettext import gettext as _ + +from sugar.graphics.icon import Icon +from sugar.graphics import style +from sugar.graphics.xocolor import XoColor +from sugar import profile + +from jarabe.controlpanel.sectionview import SectionView +from jarabe.controlpanel.inlinealert import InlineAlert + +CLASS = 'AboutMe' +ICON = 'module-about_me' +COLOR = profile.get_color() +TITLE = _('About Me') + +class EventIcon(gtk.EventBox): + __gtype_name__ = "SugarEventIcon" + def __init__(self, **kwargs): + gtk.EventBox.__init__(self) + + self.icon = Icon(pixel_size = style.XLARGE_ICON_SIZE, **kwargs) + + self.set_visible_window(False) + self.set_app_paintable(True) + self.set_events(gtk.gdk.BUTTON_PRESS_MASK) + + self.add(self.icon) + self.icon.show() + +class ColorPicker(EventIcon): + __gsignals__ = { + 'color-changed': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, + ([object])) + } + def __init__(self, xocolor=None): + EventIcon.__init__(self) + self.icon.props.xo_color = xocolor + self.icon.props.icon_name = 'computer-xo' + self.icon.props.pixel_size = style.XLARGE_ICON_SIZE + self.connect('button_press_event', self.__pressed_cb) + + def __pressed_cb(self, button, event): + self._set_random_colors() + + def _set_random_colors(self): + xocolor = XoColor() + self.icon.props.xo_color = xocolor + self.emit('color-changed', xocolor) + +class AboutMe(SectionView): + def __init__(self, model, alerts): + SectionView.__init__(self) + + self._model = model + self.restart_alerts = alerts + self._nick_sid = 0 + self._color_valid = True + self._nick_valid = True + self._color_change_handler = None + self._nick_change_handler = None + + self.set_border_width(style.DEFAULT_SPACING * 2) + self.set_spacing(style.DEFAULT_SPACING) + self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + + self._nick_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + self._nick_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + self._nick_entry = None + self._nick_alert = None + self._setup_nick() + + self._color_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + self._color_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + self._color_picker = None + self._color_alert = None + self._setup_color() + + self.setup() + + def _setup_nick(self): + label_entry = gtk.Label(_('Name:')) + label_entry.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + self._group.add_widget(label_entry) + label_entry.set_alignment(1, 0.5) + self._nick_box.pack_start(label_entry, expand=False) + label_entry.show() + + self._nick_entry = gtk.Entry() + self._nick_entry.modify_bg(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self._nick_entry.modify_base(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self._nick_entry.set_width_chars(25) + self._nick_box.pack_start(self._nick_entry, expand=False) + self._nick_entry.show() + + label_entry_error = gtk.Label() + self._group.add_widget(label_entry_error) + self._nick_alert_box.pack_start(label_entry_error, expand=False) + label_entry_error.show() + + self._nick_alert = InlineAlert() + self._nick_alert_box.pack_start(self._nick_alert) + if 'nick' in self.restart_alerts: + self._nick_alert.props.msg = self.restart_msg + self._nick_alert.show() + + self.pack_start(self._nick_box, False) + self.pack_start(self._nick_alert_box, False) + self._nick_box.show() + self._nick_alert_box.show() + + def _setup_color(self): + label_color = gtk.Label(_('Click to change your color:')) + label_color.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + self._group.add_widget(label_color) + self._color_box.pack_start(label_color, expand=False) + label_color.show() + + self._color_picker = ColorPicker() + self._color_box.pack_start(self._color_picker, expand=False) + self._color_picker.show() + + label_color_error = gtk.Label() + self._group.add_widget(label_color_error) + self._color_alert_box.pack_start(label_color_error, expand=False) + label_color_error.show() + + self._color_alert = InlineAlert() + self._color_alert_box.pack_start(self._color_alert) + if 'color' in self.restart_alerts: + self._color_alert.props.msg = self.restart_msg + self._color_alert.show() + + self.pack_start(self._color_box, False) + self.pack_start(self._color_alert_box, False) + self._color_box.show() + self._color_alert_box.show() + + def setup(self): + self._nick_entry.set_text(self._model.get_nick()) + self._color_picker.icon.props.xo_color = self._model.get_color_xo() + + self._color_valid = True + self._nick_valid = True + self.needs_restart = False + self._nick_change_handler = self._nick_entry.connect( \ + 'changed', self.__nick_changed_cb) + self._color_change_handler = self._color_picker.connect( \ + 'color-changed', self.__color_changed_cb) + + def undo(self): + self._color_picker.disconnect(self._color_change_handler) + self._nick_entry.disconnect(self._nick_change_handler) + self._model.undo() + self._nick_alert.hide() + self._color_alert.hide() + + def _validate(self): + if self._nick_valid and self._color_valid: + self.props.is_valid = True + else: + self.props.is_valid = False + + def __nick_changed_cb(self, widget, data=None): + if self._nick_sid: + gobject.source_remove(self._nick_sid) + self._nick_sid = gobject.timeout_add(self._APPLY_TIMEOUT, + self.__nick_timeout_cb, widget) + + def __nick_timeout_cb(self, widget): + self._nick_sid = 0 + + if widget.get_text() == self._model.get_nick(): + return False + try: + self._model.set_nick(widget.get_text()) + except ValueError, detail: + self._nick_alert.props.msg = detail + self._nick_valid = False + else: + self._nick_alert.props.msg = self.restart_msg + self._nick_valid = True + self.needs_restart = True + self.restart_alerts.append('nick') + + self._validate() + self._nick_alert.show() + return False + + def __color_changed_cb(self, colorpicker, xocolor): + self._model.set_color_xo(xocolor) + self.needs_restart = True + self._color_alert.props.msg = self.restart_msg + self._color_valid = True + self.restart_alerts.append('color') + + self._validate() + self._color_alert.show() + + + + + + diff --git a/extensions/cpsection/aboutxo/Makefile.am b/extensions/cpsection/aboutxo/Makefile.am new file mode 100644 index 0000000..3f71af0 --- /dev/null +++ b/extensions/cpsection/aboutxo/Makefile.am @@ -0,0 +1,6 @@ +sugardir = $(pkgdatadir)/extensions/cpsection/aboutxo + +sugar_PYTHON = \ + __init__.py \ + model.py \ + view.py diff --git a/extensions/cpsection/aboutxo/__init__.py b/extensions/cpsection/aboutxo/__init__.py new file mode 100644 index 0000000..4dc2cb2 --- /dev/null +++ b/extensions/cpsection/aboutxo/__init__.py @@ -0,0 +1,22 @@ +# Copyright (C) 2008, OLPC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from gettext import gettext as _ + +CLASS = 'AboutXO' +ICON = 'module-about_my_xo' +TITLE = _('About my XO') + diff --git a/extensions/cpsection/aboutxo/model.py b/extensions/cpsection/aboutxo/model.py new file mode 100644 index 0000000..ebbcca7 --- /dev/null +++ b/extensions/cpsection/aboutxo/model.py @@ -0,0 +1,101 @@ +# 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 logging +import re +from gettext import gettext as _ + +_logger = logging.getLogger('ControlPanel - AboutXO') +_not_available = _('Not available') + +def get_aboutxo(): + msg = 'Serial Number: %s \nBuild Number: %s \nFirmware Number: %s \n' \ + % (get_serial_number(), get_build_number(), get_firmware_number()) + return msg + +def print_aboutxo(): + print get_aboutxo() + +def get_serial_number(): + serial_no = _read_file('/ofw/serial-number') + if serial_no is None: + serial_no = _not_available + return serial_no + +def print_serial_number(): + print get_serial_number() + +def get_build_number(): + build_no = _read_file('/boot/olpc_build') + if build_no is None: + build_no = _not_available + return build_no + +def print_build_number(): + print get_build_number() + +def get_firmware_number(): + firmware_no = _read_file('/ofw/openprom/model') + if firmware_no is None: + firmware_no = _not_available + else: + firmware_no = re.split(" +", firmware_no) + if len(firmware_no) == 3: + firmware_no = firmware_no[1] + return firmware_no + +def print_firmware_number(): + print get_firmware_number() + +def _read_file(path): + if os.access(path, os.R_OK) == 0: + return None + + fd = open(path, 'r') + value = fd.read() + fd.close() + if value: + value = value.strip('\n') + return value + else: + _logger.debug('No information in file or directory: %s' % path) + return None + +def get_license(): + license_file = "/usr/share/licenses/common-licenses/GPLv2" + lang = os.environ['LANG'] + if lang.endswith("UTF-8"): + lang = lang[:-6] + + try_file = license_file + "." + lang + if os.path.isfile(try_file): + license_file = try_file + else: + try_file = license_file + "." + lang.split("_")[0] + if os.path.isfile(try_file): + license_file = try_file + + try: + fd = open(license_file) + # remove 0x0c page breaks which can't be rendered in text views + license_text = fd.read().replace('\x0c', '') + fd.close() + except IOError: + license_text = _not_available + return license_text + diff --git a/extensions/cpsection/aboutxo/view.py b/extensions/cpsection/aboutxo/view.py new file mode 100644 index 0000000..a3afa10 --- /dev/null +++ b/extensions/cpsection/aboutxo/view.py @@ -0,0 +1,193 @@ +# coding=utf-8 +# Copyright (C) 2008, OLPC +# +# 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 +from gettext import gettext as _ + +from jarabe import config +from sugar.graphics import style + +from jarabe.controlpanel.sectionview import SectionView + +class AboutXO(SectionView): + def __init__(self, model, alerts=None): + SectionView.__init__(self) + + self._model = model + + self.set_border_width(style.DEFAULT_SPACING * 2) + self.set_spacing(style.DEFAULT_SPACING) + + self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + + scrollwindow = gtk.ScrolledWindow() + scrollwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + self.pack_start(scrollwindow, expand=True) + scrollwindow.show() + + self._vbox = gtk.VBox() + scrollwindow.add_with_viewport(self._vbox) + self._vbox.show() + + self._setup_identity() + self._setup_software() + self._setup_copyright() + + def _setup_identity(self): + separator_identity = gtk.HSeparator() + self._vbox.pack_start(separator_identity, expand=False) + separator_identity.show() + + label_identity = gtk.Label(_('Identity')) + label_identity.set_alignment(0, 0) + self._vbox.pack_start(label_identity, expand=False) + label_identity.show() + vbox_identity = gtk.VBox() + vbox_identity.set_border_width(style.DEFAULT_SPACING * 2) + vbox_identity.set_spacing(style.DEFAULT_SPACING) + + box_identity = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_serial = gtk.Label(_('Serial Number:')) + label_serial.set_alignment(1, 0) + label_serial.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + box_identity.pack_start(label_serial, expand=False) + self._group.add_widget(label_serial) + label_serial.show() + label_serial_no = gtk.Label(self._model.get_serial_number()) + label_serial_no.set_alignment(0, 0) + box_identity.pack_start(label_serial_no, expand=False) + label_serial_no.show() + vbox_identity.pack_start(box_identity, expand=False) + box_identity.show() + + self._vbox.pack_start(vbox_identity, expand=False) + vbox_identity.show() + + + def _setup_software(self): + separator_software = gtk.HSeparator() + self._vbox.pack_start(separator_software, expand=False) + separator_software.show() + + label_software = gtk.Label(_('Software')) + label_software.set_alignment(0, 0) + self._vbox.pack_start(label_software, expand=False) + label_software.show() + box_software = gtk.VBox() + box_software.set_border_width(style.DEFAULT_SPACING * 2) + box_software.set_spacing(style.DEFAULT_SPACING) + + box_build = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_build = gtk.Label(_('Build:')) + label_build.set_alignment(1, 0) + label_build.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + box_build.pack_start(label_build, expand=False) + self._group.add_widget(label_build) + label_build.show() + label_build_no = gtk.Label(self._model.get_build_number()) + label_build_no.set_alignment(0, 0) + box_build.pack_start(label_build_no, expand=False) + label_build_no.show() + box_software.pack_start(box_build, expand=False) + box_build.show() + + box_sugar = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_sugar = gtk.Label(_('Sugar:')) + label_sugar.set_alignment(1, 0) + label_sugar.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + box_sugar.pack_start(label_sugar, expand=False) + self._group.add_widget(label_sugar) + label_sugar.show() + label_sugar_ver = gtk.Label(config.version) + label_sugar_ver.set_alignment(0, 0) + box_sugar.pack_start(label_sugar_ver, expand=False) + label_sugar_ver.show() + box_software.pack_start(box_sugar, expand=False) + box_sugar.show() + + box_firmware = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_firmware = gtk.Label(_('Firmware:')) + label_firmware.set_alignment(1, 0) + label_firmware.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + box_firmware.pack_start(label_firmware, expand=False) + self._group.add_widget(label_firmware) + label_firmware.show() + label_firmware_no = gtk.Label(self._model.get_firmware_number()) + label_firmware_no.set_alignment(0, 0) + box_firmware.pack_start(label_firmware_no, expand=False) + label_firmware_no.show() + box_software.pack_start(box_firmware, expand=False) + box_firmware.show() + + self._vbox.pack_start(box_software, expand=False) + box_software.show() + + def _setup_copyright(self): + separator_copyright = gtk.HSeparator() + self._vbox.pack_start(separator_copyright, expand=False) + separator_copyright.show() + + label_copyright = gtk.Label(_('Copyright and License')) + label_copyright.set_alignment(0, 0) + self._vbox.pack_start(label_copyright, expand=False) + label_copyright.show() + vbox_copyright = gtk.VBox() + vbox_copyright.set_border_width(style.DEFAULT_SPACING * 2) + vbox_copyright.set_spacing(style.DEFAULT_SPACING) + + label_copyright = gtk.Label(_("© 2008 One Laptop per Child " + "Association Inc; Red Hat Inc; " + "and Contributors.")) + label_copyright.set_alignment(0, 0) + label_copyright.show() + vbox_copyright.pack_start(label_copyright, expand=False) + + label_info = gtk.Label(_("Sugar is the graphical user interface that " + "you are looking at. Sugar is free software, " + "covered by the GNU General Public License, " + "and you are welcome to change it and/or " + "distribute copies of it under certain " + "conditions described therein.")) + label_info.set_alignment(0, 0) + label_info.set_line_wrap(True) + label_info.set_size_request(gtk.gdk.screen_width() / 2, -1) + label_info.show() + vbox_copyright.pack_start(label_info, expand=False) + + expander = gtk.Expander(_("Full license:")) + expander.connect("notify::expanded", self.license_expander_cb) + expander.show() + vbox_copyright.pack_start(expander, expand=True) + + self._vbox.pack_start(vbox_copyright, expand=True) + vbox_copyright.show() + + def license_expander_cb(self, expander, param_spec): + # load/destroy the license viewer on-demand, to avoid storing the + # GPL in memory at all times + if expander.get_expanded(): + view_license = gtk.TextView() + view_license.set_editable(False) + view_license.get_buffer().set_text(self._model.get_license()) + view_license.show() + expander.add(view_license) + else: + expander.get_child().destroy() diff --git a/extensions/cpsection/datetime/Makefile.am b/extensions/cpsection/datetime/Makefile.am new file mode 100644 index 0000000..b5b518e --- /dev/null +++ b/extensions/cpsection/datetime/Makefile.am @@ -0,0 +1,6 @@ +sugardir = $(pkgdatadir)/extensions/cpsection/datetime + +sugar_PYTHON = \ + __init__.py \ + model.py \ + view.py diff --git a/extensions/cpsection/datetime/__init__.py b/extensions/cpsection/datetime/__init__.py new file mode 100644 index 0000000..fc9be45 --- /dev/null +++ b/extensions/cpsection/datetime/__init__.py @@ -0,0 +1,21 @@ +# Copyright (C) 2008, OLPC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from gettext import gettext as _ + +CLASS = 'TimeZone' +ICON = 'module-date_and_time' +TITLE = _('Date & Time') diff --git a/extensions/cpsection/datetime/model.py b/extensions/cpsection/datetime/model.py new file mode 100644 index 0000000..4a4c560 --- /dev/null +++ b/extensions/cpsection/datetime/model.py @@ -0,0 +1,94 @@ +# Copyright (C) 2007, 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 +# +# +# The timezone config is based on the system-config-date +# (http://fedoraproject.org/wiki/SystemConfig/date) tool. +# Parts of the code were reused. +# + +import os +from gettext import gettext as _ + +from sugar import profile + +_zone_tab = '/usr/share/zoneinfo/zone.tab' + +def _initialize(): + '''Initialize the docstring of the set function''' + if set_timezone.__doc__ is None: + # when running under 'python -OO', all __doc__ fields are None, + # so += would fail -- and this function would be unnecessary anyway. + return + timezones = read_all_timezones() + for timezone in timezones: + set_timezone.__doc__ += timezone + '\n' + +def read_all_timezones(fn=_zone_tab): + fd = open (fn, 'r') + lines = fd.readlines() + fd.close() + timezones = [] + for line in lines: + if line.startswith('#'): + continue + line = line.split() + if len(line) > 1: + timezones.append(line[2]) + timezones.sort() + + for offset in xrange(-12, 13): + if offset < 0: + tz = 'GMT%d' % offset + elif offset > 0: + tz = 'GMT+%d' % offset + else: + tz = 'GMT' + timezones.append(tz) + for offset in xrange(-12, 13): + if offset < 0: + tz = 'UTC%d' % offset + elif offset > 0: + tz = 'UTC+%d' % offset + else: + tz = 'UTC' + timezones.append(tz) + return timezones + +def get_timezone(): + pro = profile.get_profile() + return pro.timezone + +def print_timezone(): + print get_timezone() + +def set_timezone(timezone): + """Set the system timezone + timezone : e.g. 'America/Los_Angeles' + """ + timezones = read_all_timezones() + if timezone in timezones: + os.environ['TZ'] = timezone + pro = profile.get_profile() + pro.timezone = timezone + pro.save() + else: + raise ValueError(_("Error timezone does not exist.")) + return 1 + +# inilialize the docstrings for the timezone +_initialize() + diff --git a/extensions/cpsection/datetime/view.py b/extensions/cpsection/datetime/view.py new file mode 100644 index 0000000..58719b4 --- /dev/null +++ b/extensions/cpsection/datetime/view.py @@ -0,0 +1,138 @@ +# Copyright (C) 2008, OLPC +# +# 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 gettext import gettext as _ + +from sugar.graphics import style +from sugar.graphics import iconentry + +from jarabe.controlpanel.sectionview import SectionView +from jarabe.controlpanel.inlinealert import InlineAlert + +class TimeZone(SectionView): + def __init__(self, model, alerts): + SectionView.__init__(self) + + self._model = model + self.restart_alerts = alerts + self._zone_sid = 0 + self._cursor_change_handler = None + + self.set_border_width(style.DEFAULT_SPACING * 2) + self.set_spacing(style.DEFAULT_SPACING) + + self.connect("realize", self.__realize_cb) + + self._entry = iconentry.IconEntry() + self._entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, + 'system-search') + self._entry.add_clear_button() + self._entry.modify_bg(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self._entry.modify_base(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self.pack_start(self._entry, False) + self._entry.show() + + self._scrolled_window = gtk.ScrolledWindow() + self._scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + self._scrolled_window.set_shadow_type(gtk.SHADOW_IN) + + self._store = gtk.ListStore(gobject.TYPE_STRING) + zones = model.read_all_timezones() + for zone in zones: + self._store.append([zone]) + + self._treeview = gtk.TreeView(self._store) + self._treeview.set_search_entry(self._entry) + self._treeview.set_search_equal_func(self._search) + self._treeview.set_search_column(0) + self._scrolled_window.add(self._treeview) + self._treeview.show() + + self._timezone_column = gtk.TreeViewColumn(_('Timezone')) + self._cell = gtk.CellRendererText() + self._timezone_column.pack_start(self._cell, True) + self._timezone_column.add_attribute(self._cell, 'text', 0) + self._timezone_column.set_sort_column_id(0) + self._treeview.append_column(self._timezone_column) + + self.pack_start(self._scrolled_window) + self._scrolled_window.show() + + self._zone_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + self.pack_start(self._zone_alert_box, False) + + self._zone_alert = InlineAlert() + self._zone_alert_box.pack_start(self._zone_alert) + if 'zone' in self.restart_alerts: + self._zone_alert.props.msg = self.restart_msg + self._zone_alert.show() + self._zone_alert_box.show() + + self.setup() + + def setup(self): + zone = self._model.get_timezone() + for row in self._store: + if zone == row[0]: + self._treeview.set_cursor(row.path, self._timezone_column, + False) + self._treeview.scroll_to_cell(row.path, self._timezone_column, + True, 0.5, 0.5) + break + + self.needs_restart = False + self._cursor_change_handler = self._treeview.connect( \ + "cursor-changed", self.__zone_changed_cd) + + def undo(self): + self._treeview.disconnect(self._cursor_change_handler) + self._model.undo() + self._zone_alert.hide() + + def __realize_cb(self, widget): + self._entry.grab_focus() + + def _search(self, model, column, key, iterator, data=None): + value = model.get_value(iterator, column) + if key.lower() in value.lower(): + return False + return True + + def __zone_changed_cd(self, treeview, data=None): + list_, row = treeview.get_selection().get_selected() + if not row: + return False + if self._model.get_timezone() == self._store.get_value(row, 0): + return False + + if self._zone_sid: + gobject.source_remove(self._zone_sid) + self._zone_sid = gobject.timeout_add(self._APPLY_TIMEOUT, + self.__zone_timeout_cb, row) + return True + + def __zone_timeout_cb(self, row): + self._zone_sid = 0 + self._model.set_timezone(self._store.get_value(row, 0)) + self.restart_alerts.append('zone') + self.needs_restart = True + self._zone_alert.props.msg = self.restart_msg + self._zone_alert.show() + return False diff --git a/extensions/cpsection/frame/Makefile.am b/extensions/cpsection/frame/Makefile.am new file mode 100644 index 0000000..1e09c04 --- /dev/null +++ b/extensions/cpsection/frame/Makefile.am @@ -0,0 +1,6 @@ +sugardir = $(pkgdatadir)/extensions/cpsection/frame + +sugar_PYTHON = \ + __init__.py \ + model.py \ + view.py diff --git a/extensions/cpsection/frame/__init__.py b/extensions/cpsection/frame/__init__.py new file mode 100644 index 0000000..a93f9c7 --- /dev/null +++ b/extensions/cpsection/frame/__init__.py @@ -0,0 +1,21 @@ +# Copyright (C) 2008, OLPC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from gettext import gettext as _ + +CLASS = 'Frame' +ICON = 'module-frame' +TITLE = _('Frame') diff --git a/extensions/cpsection/frame/model.py b/extensions/cpsection/frame/model.py new file mode 100644 index 0000000..0e19703 --- /dev/null +++ b/extensions/cpsection/frame/model.py @@ -0,0 +1,64 @@ +# 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 +# + +from gettext import gettext as _ + +from sugar import profile + +def get_corner_delay(): + pro = profile.get_profile() + return pro.hot_corners_delay + +def print_corner_delay(): + print get_corner_delay() + +def set_corner_delay(delay): + """Set a delay for the activation of the frame using hot corners. + instantaneous: 0 (0 milliseconds) + delay: 100 (100 milliseconds) + never: 1000 (disable activation) + """ + try: + int(delay) + except ValueError: + raise ValueError(_("Value must be an integer.")) + pro = profile.get_profile() + pro.hot_corners_delay = int(delay) + pro.save() + return 1 + +def get_edge_delay(): + pro = profile.get_profile() + return pro.warm_edges_delay + +def print_edge_delay(): + print get_edge_delay() + +def set_edge_delay(delay): + """Set a delay for the activation of the frame using warm edges. + instantaneous: 0 (0 milliseconds) + delay: 100 (100 milliseconds) + never: 1000 (disable activation) + """ + try: + int(delay) + except ValueError: + raise ValueError(_("Value must be an integer.")) + pro = profile.get_profile() + pro.warm_edges_delay = int(delay) + pro.save() + return 1 diff --git a/extensions/cpsection/frame/view.py b/extensions/cpsection/frame/view.py new file mode 100644 index 0000000..7ab7bd2 --- /dev/null +++ b/extensions/cpsection/frame/view.py @@ -0,0 +1,232 @@ +# Copyright (C) 2008, OLPC +# +# 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 gettext import gettext as _ + +from sugar.graphics import style + +from jarabe.controlpanel.sectionview import SectionView +from jarabe.controlpanel.inlinealert import InlineAlert + +_never = _('never') +_instantaneous = _('instantaneous') +_seconds_label = _('%s seconds') +_MAX_DELAY = 1000.0 + +class Frame(SectionView): + def __init__(self, model, alerts): + SectionView.__init__(self) + + self._model = model + self._corner_delay_sid = 0 + self._corner_delay_is_valid = True + self._corner_delay_change_handler = None + self._edge_delay_sid = 0 + self._edge_delay_is_valid = True + self._edge_delay_change_handler = None + self.restart_alerts = alerts + + self.set_border_width(style.DEFAULT_SPACING * 2) + self.set_spacing(style.DEFAULT_SPACING) + self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + + separator = gtk.HSeparator() + self.pack_start(separator, expand=False) + separator.show() + + label_activation = gtk.Label(_('Activation Delay')) + label_activation.set_alignment(0, 0) + self.pack_start(label_activation, expand=False) + label_activation.show() + + self._box_sliders = gtk.VBox() + self._box_sliders.set_border_width(style.DEFAULT_SPACING * 2) + self._box_sliders.set_spacing(style.DEFAULT_SPACING) + + self._corner_delay_slider = None + self._corner_delay_alert = None + self._setup_corner() + + self._edge_delay_slider = None + self._edge_delay_alert = None + self._setup_edge() + + self.pack_start(self._box_sliders, expand=False) + self._box_sliders.show() + + self.setup() + + def _setup_corner(self): + box_delay = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_delay = gtk.Label(_('Corner')) + label_delay.set_alignment(1, 0.75) + label_delay.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + box_delay.pack_start(label_delay, expand=False) + self._group.add_widget(label_delay) + label_delay.show() + + adj = gtk.Adjustment(value=100, lower=0, upper=_MAX_DELAY, + step_incr=100, page_incr=100, page_size=0) + self._corner_delay_slider = gtk.HScale(adj) + self._corner_delay_slider.set_digits(0) + self._corner_delay_slider.connect('format-value', + self.__corner_delay_format_cb) + box_delay.pack_start(self._corner_delay_slider) + self._corner_delay_slider.show() + self._box_sliders.pack_start(box_delay, expand=False) + box_delay.show() + + self._corner_delay_alert = InlineAlert() + label_delay_error = gtk.Label() + self._group.add_widget(label_delay_error) + + delay_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + delay_alert_box.pack_start(label_delay_error, expand=False) + label_delay_error.show() + delay_alert_box.pack_start(self._corner_delay_alert, expand=False) + self._box_sliders.pack_start(delay_alert_box, expand=False) + delay_alert_box.show() + if 'corner_delay' in self.restart_alerts: + self._corner_delay_alert.props.msg = self.restart_msg + self._corner_delay_alert.show() + + def _setup_edge(self): + box_delay = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_delay = gtk.Label(_('Edge')) + label_delay.set_alignment(1, 0.75) + label_delay.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + box_delay.pack_start(label_delay, expand=False) + self._group.add_widget(label_delay) + label_delay.show() + + adj = gtk.Adjustment(value=100, lower=0, upper=_MAX_DELAY, + step_incr=100, page_incr=100, page_size=0) + self._edge_delay_slider = gtk.HScale(adj) + self._edge_delay_slider.set_digits(0) + self._edge_delay_slider.connect('format-value', + self.__edge_delay_format_cb) + box_delay.pack_start(self._edge_delay_slider) + self._edge_delay_slider.show() + self._box_sliders.pack_start(box_delay, expand=False) + box_delay.show() + + self._edge_delay_alert = InlineAlert() + label_delay_error = gtk.Label() + self._group.add_widget(label_delay_error) + + delay_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + delay_alert_box.pack_start(label_delay_error, expand=False) + label_delay_error.show() + delay_alert_box.pack_start(self._edge_delay_alert, expand=False) + self._box_sliders.pack_start(delay_alert_box, expand=False) + delay_alert_box.show() + if 'edge_delay' in self.restart_alerts: + self._edge_delay_alert.props.msg = self.restart_msg + self._edge_delay_alert.show() + + def setup(self): + self._corner_delay_slider.set_value(self._model.get_corner_delay()) + self._edge_delay_slider.set_value(self._model.get_edge_delay()) + self._corner_delay_is_valid = True + self._edge_delay_is_valid = True + self.needs_restart = False + self._corner_delay_change_handler = self._corner_delay_slider.connect( \ + 'value-changed', self.__corner_delay_changed_cb) + self._edge_delay_change_handler = self._edge_delay_slider.connect( \ + 'value-changed', self.__edge_delay_changed_cb) + + def undo(self): + self._corner_delay_slider.disconnect(self._corner_delay_change_handler) + self._edge_delay_slider.disconnect(self._edge_delay_change_handler) + self._model.undo() + self._corner_delay_alert.hide() + self._edge_delay_alert.hide() + + def _validate(self): + if self._edge_delay_is_valid and self._corner_delay_is_valid: + self.props.is_valid = True + else: + self.props.is_valid = False + + def __corner_delay_changed_cb(self, scale, data=None): + if self._corner_delay_sid: + gobject.source_remove(self._corner_delay_sid) + self._corner_delay_sid = gobject.timeout_add( \ + self._APPLY_TIMEOUT, self.__corner_delay_timeout_cb, scale) + + def __corner_delay_timeout_cb(self, scale): + self._corner_delay_sid = 0 + if scale.get_value() == self._model.get_corner_delay(): + return + try: + self._model.set_corner_delay(scale.get_value()) + except ValueError, detail: + self._corner_delay_alert.props.msg = detail + self._corner_delay_is_valid = False + else: + self._corner_delay_alert.props.msg = self.restart_msg + self._corner_delay_is_valid = True + self.needs_restart = True + self.restart_alerts.append('corner_delay') + + self._validate() + self._corner_delay_alert.show() + return False + + def __corner_delay_format_cb(self, scale, value): + if value == _MAX_DELAY: + return _never + elif value == 0.0: + return _instantaneous + else: + return _seconds_label % (value / _MAX_DELAY) + + def __edge_delay_changed_cb(self, scale, data=None): + if self._edge_delay_sid: + gobject.source_remove(self._edge_delay_sid) + self._edge_delay_sid = gobject.timeout_add( \ + self._APPLY_TIMEOUT, self.__edge_delay_timeout_cb, scale) + + def __edge_delay_timeout_cb(self, scale): + self._edge_delay_sid = 0 + if scale.get_value() == self._model.get_edge_delay(): + return + try: + self._model.set_edge_delay(scale.get_value()) + except ValueError, detail: + self._edge_delay_alert.props.msg = detail + self._edge_delay_is_valid = False + else: + self._edge_delay_alert.props.msg = self.restart_msg + self._edge_delay_is_valid = True + self.needs_restart = True + self.restart_alerts.append('edge_delay') + + self._validate() + self._edge_delay_alert.show() + return False + + def __edge_delay_format_cb(self, scale, value): + if value == _MAX_DELAY: + return _never + elif value == 0.0: + return _instantaneous + else: + return _seconds_label % (value / _MAX_DELAY) diff --git a/extensions/cpsection/language/Makefile.am b/extensions/cpsection/language/Makefile.am new file mode 100644 index 0000000..ed8992c --- /dev/null +++ b/extensions/cpsection/language/Makefile.am @@ -0,0 +1,6 @@ +sugardir = $(pythondir)/jarabe/controlpanel/language + +sugar_PYTHON = \ + __init__.py \ + model.py \ + view.py diff --git a/extensions/cpsection/language/__init__.py b/extensions/cpsection/language/__init__.py new file mode 100644 index 0000000..a8f9f08 --- /dev/null +++ b/extensions/cpsection/language/__init__.py @@ -0,0 +1,22 @@ +# Copyright (C) 2008, OLPC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from gettext import gettext as _ + +CLASS = 'Language' +ICON = 'module-language' +TITLE = _('Language') + diff --git a/extensions/cpsection/language/model.py b/extensions/cpsection/language/model.py new file mode 100644 index 0000000..404d9dd --- /dev/null +++ b/extensions/cpsection/language/model.py @@ -0,0 +1,135 @@ +# Copyright (C) 2007, 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 +# +# +# The language config is based on the system-config-language +# (http://fedoraproject.org/wiki/SystemConfig/language) tool +# Parts of the code were reused. +# + +import os +from gettext import gettext as _ +import subprocess + +_default_lang = 'en_US.utf8' +_standard_msg = _("Could not access ~/.i18n. Create standard settings.") + +def read_all_languages(): + fdp = subprocess.Popen(['locale', '-av'], stdout=subprocess.PIPE) + lines = fdp.stdout.read().split('\n') + locales = [] + + for line in lines: + if line.find('locale:') != -1: + locale = line.lstrip('locale:') + locale = locale.split('archive:')[0].strip() + elif line.find('language |') != -1: + lang = line.lstrip('language |') + elif line.find('territory |') != -1: + territory = line.lstrip('territory |') + if locale.endswith('utf8') and len(lang): + locales.append((lang, territory, locale)) + + #FIXME: This is a temporary workaround for locales that are essential to + # OLPC, but are not in Glibc yet. + locales.append(('Kreyol', 'Haiti', 'ht_HT.utf8')) + locales.append(('Dari', 'Afghanistan', 'fa_AF.utf8')) + locales.append(('Pashto', 'Afghanistan', 'ps_AF.utf8')) + + locales.sort() + return locales + +def _initialize(): + if set_language.__doc__ is None: + # when running under 'python -OO', all __doc__ fields are None, + # so += would fail -- and this function would be unnecessary anyway. + return + languages = read_all_languages() + set_language.__doc__ += '\n' + for lang in languages: + set_language.__doc__ += '%s \n' % (lang[0].replace(' ', '_') + '/' + + lang[1].replace(' ', '_')) + +def _write_i18n(lang): + path = os.path.join(os.environ.get("HOME"), '.i18n') + if os.access(path, os.W_OK) == 0: + print _standard_msg + fd = open(path, 'w') + fd.write('LANG="%s"\n' % _default_lang) + fd.close() + else: + fd = open(path, 'r') + lines = fd.readlines() + fd.close() + for i in range(len(lines)): + if lines[i][:5] == "LANG=": + lines[i] = 'LANG="%s"\n' % lang + fd = open(path, 'w') + fd.writelines(lines) + fd.close() + +def get_language(): + path = os.path.join(os.environ.get("HOME"), '.i18n') + if os.access(path, os.R_OK) == 0: + print _standard_msg + fd = open(path, 'w') + fd.write('LANG="%s"\n' % _default_lang) + fd.close() + return _default_lang + + fd = open(path, "r") + lines = fd.readlines() + fd.close() + + lang = None + + for line in lines: + if line[:5] == "LANG=": + lang = line[5:].replace('"', '') + lang = lang.strip() + + return lang + +def print_language(): + code = get_language() + + languages = read_all_languages() + for lang in languages: + if lang[2].split('.')[0] == code.split('.')[0]: + print lang[0].replace(' ', '_') + '/' + lang[1].replace(' ', '_') + return + print (_("Language for code=%s could not be determined.") % code) + +def set_language(language): + """Set the system language. + languages : + """ + if language.endswith('utf8'): + _write_i18n(language) + return 1 + else: + languages = read_all_languages() + for lang, territory, locale in languages: + code = lang.replace(' ', '_') + '/' \ + + territory.replace(' ', '_') + if code == language: + _write_i18n(locale) + return 1 + print (_("Sorry I do not speak \'%s\'.") % language) + +# inilialize the docstrings for the language +_initialize() + diff --git a/extensions/cpsection/language/view.py b/extensions/cpsection/language/view.py new file mode 100644 index 0000000..71a185f --- /dev/null +++ b/extensions/cpsection/language/view.py @@ -0,0 +1,142 @@ +# Copyright (C) 2008, OLPC +# +# 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 gettext import gettext as _ + +from sugar.graphics import style +from sugar.graphics import iconentry + +from jarabe.controlpanel.sectionview import SectionView +from jarabe.controlpanel.inlinealert import InlineAlert + +class Language(SectionView): + def __init__(self, model, alerts): + SectionView.__init__(self) + + self._model = model + self.restart_alerts = alerts + self._lang_sid = 0 + self._cursor_change_handler = None + + self.set_border_width(style.DEFAULT_SPACING * 2) + self.set_spacing(style.DEFAULT_SPACING) + + self.connect("realize", self.__realize_cb) + + self._entry = iconentry.IconEntry() + self._entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY, + 'system-search') + self._entry.add_clear_button() + self._entry.modify_bg(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self._entry.modify_base(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self.pack_start(self._entry, False) + self._entry.show() + + self._scrolled_window = gtk.ScrolledWindow() + self._scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + self._scrolled_window.set_shadow_type(gtk.SHADOW_IN) + + self._store = gtk.ListStore(gobject.TYPE_STRING, + gobject.TYPE_STRING) + locales = model.read_all_languages() + for locale in locales: + self._store.append([locale[2], '%s (%s)' % + (locale[0], locale[1])]) + + self._treeview = gtk.TreeView(self._store) + self._treeview.set_search_entry(self._entry) + self._treeview.set_search_equal_func(self._search) + self._treeview.set_search_column(1) + self._scrolled_window.add(self._treeview) + self._treeview.show() + + self._language_column = gtk.TreeViewColumn(_('Language')) + self._cell = gtk.CellRendererText() + self._language_column.pack_start(self._cell, True) + self._language_column.add_attribute(self._cell, 'text', 1) + self._language_column.set_sort_column_id(1) + self._treeview.append_column(self._language_column) + + self.pack_start(self._scrolled_window) + self._scrolled_window.show() + + self._lang_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + self.pack_start(self._lang_alert_box, False) + + self._lang_alert = InlineAlert() + self._lang_alert_box.pack_start(self._lang_alert) + if 'lang' in self.restart_alerts: + self._lang_alert.props.msg = self.restart_msg + self._lang_alert.show() + self._lang_alert_box.show() + + self.setup() + + def setup(self): + lang_code = self._model.get_language() + for row in self._store: + lang = lang_code.split('.')[0] + lang_column = row[0].split('.')[0] + if lang in lang_column: + self._treeview.set_cursor(row.path, self._language_column, + False) + self._treeview.scroll_to_cell(row.path, self._language_column, + True, 0.5, 0.5) + break + + self.needs_restart = False + self._cursor_change_handler = self._treeview.connect( \ + "cursor-changed", self.__lang_changed_cd) + + def undo(self): + self._treeview.disconnect(self._cursor_change_handler) + self._model.undo() + self._lang_alert.hide() + + def __realize_cb(self, widget): + self._entry.grab_focus() + + def _search(self, model, column, key, iterator, data=None): + value = model.get_value(iterator, column) + if key.lower() in value.lower(): + return False + return True + + def __lang_changed_cd(self, treeview, data=None): + row = treeview.get_selection().get_selected() + if not row[1]: + return False + if self._model.get_language() == self._store.get_value(row[1], 0): + return False + + if self._lang_sid: + gobject.source_remove(self._lang_sid) + self._lang_sid = gobject.timeout_add(self._APPLY_TIMEOUT, + self.__lang_timeout_cb, + self._store.get_value(row[1], 0)) + + def __lang_timeout_cb(self, code): + self._lang_sid = 0 + self._model.set_language(code) + self.restart_alerts.append('lang') + self.needs_restart = True + self._lang_alert.props.msg = self.restart_msg + self._lang_alert.show() + return False diff --git a/extensions/cpsection/network/Makefile.am b/extensions/cpsection/network/Makefile.am new file mode 100644 index 0000000..35fd27c --- /dev/null +++ b/extensions/cpsection/network/Makefile.am @@ -0,0 +1,6 @@ +sugardir = $(pkgdatadir)/extensions/cpsection/network + +sugar_PYTHON = \ + __init__.py \ + model.py \ + view.py diff --git a/extensions/cpsection/network/__init__.py b/extensions/cpsection/network/__init__.py new file mode 100644 index 0000000..8fea274 --- /dev/null +++ b/extensions/cpsection/network/__init__.py @@ -0,0 +1,25 @@ +# Copyright (C) 2006-2007, Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from gettext import gettext as _ + +CLASS = 'Network' +ICON = 'module-network' +TITLE = _('Network') +KEYWORDS = ['network', 'jabber', 'radio', 'server'] + + + diff --git a/extensions/cpsection/network/model.py b/extensions/cpsection/network/model.py new file mode 100644 index 0000000..101297c --- /dev/null +++ b/extensions/cpsection/network/model.py @@ -0,0 +1,102 @@ +# 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 dbus +from gettext import gettext as _ + +from sugar import profile + +from jarabe.model.network import get_manager + +NM_SERVICE_NAME = 'org.freedesktop.NetworkManager' +NM_SERVICE_PATH = '/org/freedesktop/NetworkManager' +NM_SERVICE_IFACE = 'org.freedesktop.NetworkManager' +NM_ASLEEP = 1 + +KEYWORDS = ['network', 'jabber', 'radio', 'server'] + +class ReadError(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + +def get_jabber(): + pro = profile.get_profile() + return pro.jabber_server + +def print_jabber(): + print get_jabber() + +def set_jabber(server): + """Set the jabber server + server : e.g. 'olpc.collabora.co.uk' + """ + pro = profile.get_profile() + pro.jabber_server = server + pro.jabber_registered = False + pro.save() + return 1 + +def get_radio(): + bus = dbus.SystemBus() + proxy = bus.get_object(NM_SERVICE_NAME, NM_SERVICE_PATH) + nm = dbus.Interface(proxy, NM_SERVICE_IFACE) + state = nm.getWirelessEnabled() + if state in (0, 1): + return state + else: + raise ReadError(_('State is unknown.')) + +def print_radio(): + print ('off', 'on')[get_radio()] + +def set_radio(state): + """Turn Radio 'on' or 'off' + state : 'on/off' + """ + if state == 'on' or state == 1: + bus = dbus.SystemBus() + proxy = bus.get_object(NM_SERVICE_NAME, NM_SERVICE_PATH) + nm = dbus.Interface(proxy, NM_SERVICE_IFACE) + nm.setWirelessEnabled(True) + elif state == 'off' or state == 0: + bus = dbus.SystemBus() + proxy = bus.get_object(NM_SERVICE_NAME, NM_SERVICE_PATH) + nm = dbus.Interface(proxy, NM_SERVICE_IFACE) + nm.setWirelessEnabled(False) + else: + raise ValueError(_("Error in specified radio argument use on/off.")) + + return 0 + +def clear_registration(): + """Clear the registration with the schoolserver + """ + pro = profile.get_profile() + pro.backup1 = None + pro.save() + return 1 + +def clear_networks(): + """Clear saved passwords and network configurations. + """ + network_manager = get_manager() + if not network_manager: + return + network_manager.nminfo.delete_all_networks() + return 1 diff --git a/extensions/cpsection/network/view.py b/extensions/cpsection/network/view.py new file mode 100644 index 0000000..4f4ada7 --- /dev/null +++ b/extensions/cpsection/network/view.py @@ -0,0 +1,231 @@ +# Copyright (C) 2008, OLPC +# +# 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 gettext import gettext as _ + +from sugar.graphics import style + +from jarabe.controlpanel.sectionview import SectionView +from jarabe.controlpanel.inlinealert import InlineAlert + +CLASS = 'Network' +ICON = 'module-network' +TITLE = _('Network') + +class Network(SectionView): + def __init__(self, model, alerts): + SectionView.__init__(self) + + self._model = model + self.restart_alerts = alerts + self._jabber_sid = 0 + self._jabber_valid = True + self._radio_valid = True + self._jabber_change_handler = None + self._radio_change_handler = None + self._network_configuration_reset_handler = None + + self.set_border_width(style.DEFAULT_SPACING * 2) + self.set_spacing(style.DEFAULT_SPACING) + group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + + self._radio_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + self._jabber_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + + separator_wireless = gtk.HSeparator() + self.pack_start(separator_wireless, expand=False) + separator_wireless.show() + + label_wireless = gtk.Label(_('Wireless')) + label_wireless.set_alignment(0, 0) + self.pack_start(label_wireless, expand=False) + label_wireless.show() + box_wireless = gtk.VBox() + box_wireless.set_border_width(style.DEFAULT_SPACING * 2) + box_wireless.set_spacing(style.DEFAULT_SPACING) + + radio_info = gtk.Label(_("Turn of the wireless radio to save " + "battery life")) + radio_info.set_alignment(0, 0) + radio_info.set_line_wrap(True) + radio_info.show() + box_wireless.pack_start(radio_info, expand=False) + + box_radio = gtk.HBox(spacing=style.DEFAULT_SPACING) + self._button = gtk.CheckButton() + self._button.set_alignment(0, 0) + box_radio.pack_start(self._button, expand=False) + self._button.show() + + label_radio = gtk.Label(_('Radio')) + label_radio.set_alignment(0, 0.5) + box_radio.pack_start(label_radio, expand=False) + label_radio.show() + + box_wireless.pack_start(box_radio, expand=False) + box_radio.show() + + self._radio_alert = InlineAlert() + self._radio_alert_box.pack_start(self._radio_alert, expand=False) + box_radio.pack_end(self._radio_alert_box, expand=False) + self._radio_alert_box.show() + if 'radio' in self.restart_alerts: + self._radio_alert.props.msg = self.restart_msg + self._radio_alert.show() + + history_info = gtk.Label(_("Discard network history if you " + "have trouble connecting to the network")) + history_info.set_alignment(0, 0) + history_info.set_line_wrap(True) + history_info.show() + box_wireless.pack_start(history_info, expand=False) + + box_clear_history = gtk.HBox(spacing=style.DEFAULT_SPACING) + self._clear_history_button = gtk.Button() + self._clear_history_button.set_label(_('Discard network history')) + box_clear_history.pack_start(self._clear_history_button, expand=False) + self._clear_history_button.show() + box_wireless.pack_start(box_clear_history, expand=False) + box_clear_history.show() + + self.pack_start(box_wireless, expand=False) + box_wireless.show() + + separator_mesh = gtk.HSeparator() + self.pack_start(separator_mesh, False) + separator_mesh.show() + + label_mesh = gtk.Label(_('Mesh')) + label_mesh.set_alignment(0, 0) + self.pack_start(label_mesh, expand=False) + label_mesh.show() + box_mesh = gtk.VBox() + box_mesh.set_border_width(style.DEFAULT_SPACING * 2) + box_mesh.set_spacing(style.DEFAULT_SPACING) + + box_server = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_server = gtk.Label(_('Server:')) + label_server.set_alignment(1, 0.5) + label_server.modify_fg(gtk.STATE_NORMAL, + style.COLOR_SELECTION_GREY.get_gdk_color()) + box_server.pack_start(label_server, expand=False) + group.add_widget(label_server) + label_server.show() + self._entry = gtk.Entry() + self._entry.set_alignment(0) + self._entry.modify_bg(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self._entry.modify_base(gtk.STATE_INSENSITIVE, + style.COLOR_WHITE.get_gdk_color()) + self._entry.set_size_request(int(gtk.gdk.screen_width() / 3), -1) + box_server.pack_start(self._entry, expand=False) + self._entry.show() + box_mesh.pack_start(box_server, expand=False) + box_server.show() + + self._jabber_alert = InlineAlert() + label_jabber_error = gtk.Label() + group.add_widget(label_jabber_error) + self._jabber_alert_box.pack_start(label_jabber_error, expand=False) + label_jabber_error.show() + self._jabber_alert_box.pack_start(self._jabber_alert, expand=False) + box_mesh.pack_end(self._jabber_alert_box, expand=False) + self._jabber_alert_box.show() + if 'jabber' in self.restart_alerts: + self._jabber_alert.props.msg = self.restart_msg + self._jabber_alert.show() + + self.pack_start(box_mesh, expand=False) + box_mesh.show() + + self.setup() + + def setup(self): + self._entry.set_text(self._model.get_jabber()) + try: + radio_state = self._model.get_radio() + except Exception, detail: + self._radio_alert.props.msg = detail + self._radio_alert.show() + else: + self._button.set_active(radio_state) + + self._jabber_valid = True + self._radio_valid = True + self.needs_restart = False + self._radio_change_handler = self._button.connect( \ + 'toggled', self.__radio_toggled_cb) + self._jabber_change_handler = self._entry.connect( \ + 'changed', self.__jabber_changed_cb) + self._network_configuration_reset_handler = \ + self._clear_history_button.connect( \ + 'clicked', self.__network_configuration_reset_cb) + + def undo(self): + self._button.disconnect(self._radio_change_handler) + self._entry.disconnect(self._jabber_change_handler) + self._model.undo() + self._jabber_alert.hide() + self._radio_alert.hide() + + def _validate(self): + if self._jabber_valid and self._radio_valid: + self.props.is_valid = True + else: + self.props.is_valid = False + + def __radio_toggled_cb(self, widget, data=None): + radio_state = widget.get_active() + try: + self._model.set_radio(radio_state) + except Exception, detail: + self._radio_alert.props.msg = detail + self._radio_valid = False + else: + self._radio_valid = True + + self._validate() + return False + + def __jabber_changed_cb(self, widget, data=None): + if self._jabber_sid: + gobject.source_remove(self._jabber_sid) + self._jabber_sid = gobject.timeout_add(self._APPLY_TIMEOUT, + self.__jabber_timeout_cb, widget) + + def __jabber_timeout_cb(self, widget): + self._jabber_sid = 0 + if widget.get_text() == self._model.get_jabber: + return + try: + self._model.set_jabber(widget.get_text()) + except ValueError, detail: + self._jabber_alert.props.msg = detail + self._jabber_valid = False + else: + self._jabber_alert.props.msg = self.restart_msg + self._jabber_valid = True + self.needs_restart = True + self.restart_alerts.append('jabber') + + self._validate() + self._jabber_alert.show() + return False + + def __network_configuration_reset_cb(self, widget): + self._model.clear_networks() diff --git a/extensions/cpsection/power/Makefile.am b/extensions/cpsection/power/Makefile.am new file mode 100644 index 0000000..325260c --- /dev/null +++ b/extensions/cpsection/power/Makefile.am @@ -0,0 +1,6 @@ +sugardir = $(pkgdatadir)/extensions/cpsection/power + +sugar_PYTHON = \ + __init__.py \ + model.py \ + view.py diff --git a/extensions/cpsection/power/__init__.py b/extensions/cpsection/power/__init__.py new file mode 100644 index 0000000..8b2e85f --- /dev/null +++ b/extensions/cpsection/power/__init__.py @@ -0,0 +1,23 @@ +# Copyright (C) 2008, OLPC +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from gettext import gettext as _ + +CLASS = 'Power' +ICON = 'module-power' +TITLE = _('Power') +KEYWORDS = ['automatic', 'extreme', 'power', 'suspend', 'battery'] + diff --git a/extensions/cpsection/power/model.py b/extensions/cpsection/power/model.py new file mode 100644 index 0000000..47af483 --- /dev/null +++ b/extensions/cpsection/power/model.py @@ -0,0 +1,89 @@ +# 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 +# + +from gettext import gettext as _ + +from sugar import profile +import dbus + +OHM_SERVICE_NAME = 'org.freedesktop.ohm' +OHM_SERVICE_PATH = '/org/freedesktop/ohm/Keystore' +OHM_SERVICE_IFACE = 'org.freedesktop.ohm.Keystore' + +class ReadError(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + +def get_automatic_pm(): + pro = profile.get_profile() + ret = pro.automatic_pm + return ret + +def print_automatic_pm(): + print ('off', 'on')[get_automatic_pm()] + +def set_automatic_pm(enabled): + """Automatic suspends on/off.""" + + bus = dbus.SystemBus() + proxy = bus.get_object(OHM_SERVICE_NAME, OHM_SERVICE_PATH) + keystore = dbus.Interface(proxy, OHM_SERVICE_IFACE) + + if enabled == 'on' or enabled == 1: + keystore.SetKey("suspend.automatic_pm", 1) + enabled = True + elif enabled == 'off' or enabled == 0: + keystore.SetKey("suspend.automatic_pm", 0) + enabled = False + else: + raise ValueError(_("Error in automatic pm argument, use on/off.")) + + pro = profile.get_profile() + pro.automatic_pm = enabled + pro.save() + return 0 + +def get_extreme_pm(): + pro = profile.get_profile() + ret = pro.extreme_pm + return ret + +def print_extreme_pm(): + print ('off', 'on')[get_extreme_pm()] + +def set_extreme_pm(enabled): + """Extreme power management on/off.""" + + bus = dbus.SystemBus() + proxy = bus.get_object(OHM_SERVICE_NAME, OHM_SERVICE_PATH) + keystore = dbus.Interface(proxy, OHM_SERVICE_IFACE) + + if enabled == 'on' or enabled == 1: + keystore.SetKey("suspend.extreme_pm", 1) + enabled = True + elif enabled == 'off' or enabled == 0: + keystore.SetKey("suspend.extreme_pm", 0) + enabled = False + else: + raise ValueError(_("Error in extreme pm argument, use on/off.")) + + pro = profile.get_profile() + pro.extreme_pm = enabled + pro.save() + return 0 diff --git a/extensions/cpsection/power/view.py b/extensions/cpsection/power/view.py new file mode 100644 index 0000000..8f1ed56 --- /dev/null +++ b/extensions/cpsection/power/view.py @@ -0,0 +1,177 @@ +# Copyright (C) 2008, OLPC +# +# 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 +from gettext import gettext as _ + +from sugar.graphics import style + +from jarabe.controlpanel.sectionview import SectionView +from jarabe.controlpanel.inlinealert import InlineAlert + +class Power(SectionView): + def __init__(self, model, alerts): + SectionView.__init__(self) + + self._model = model + self.restart_alerts = alerts + self._automatic_pm_valid = True + self._extreme_pm_valid = True + self._extreme_pm_change_handler = None + self._automatic_pm_change_handler = None + + self.set_border_width(style.DEFAULT_SPACING * 2) + self.set_spacing(style.DEFAULT_SPACING) + group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + + self._automatic_pm_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + self._extreme_pm_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING) + + separator_pm = gtk.HSeparator() + self.pack_start(separator_pm, expand=False) + separator_pm.show() + + label_pm = gtk.Label(_('Power management')) + label_pm.set_alignment(0, 0) + self.pack_start(label_pm, expand=False) + label_pm.show() + box_pm = gtk.VBox() + box_pm.set_border_width(style.DEFAULT_SPACING * 2) + box_pm.set_spacing(style.DEFAULT_SPACING) + + box_automatic_pm = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_automatic_pm = gtk.Label( + _('Automatic power management (increases battery life)')) + label_automatic_pm.set_alignment(0, 0.5) + self._automatic_button = gtk.CheckButton() + self._automatic_button.set_alignment(0, 0) + box_automatic_pm.pack_start(self._automatic_button, expand=False) + box_automatic_pm.pack_start(label_automatic_pm, expand=False) + self._automatic_button.show() + label_automatic_pm.show() + group.add_widget(label_automatic_pm) + box_pm.pack_start(box_automatic_pm, expand=False) + box_automatic_pm.show() + + self._automatic_pm_alert = InlineAlert() + label_automatic_pm_error = gtk.Label() + group.add_widget(label_automatic_pm_error) + self._automatic_pm_alert_box.pack_start(label_automatic_pm_error, + expand=False) + label_automatic_pm_error.show() + self._automatic_pm_alert_box.pack_start(self._automatic_pm_alert, + expand=False) + box_pm.pack_end(self._automatic_pm_alert_box, expand=False) + self._automatic_pm_alert_box.show() + if 'automatic_pm' in self.restart_alerts: + self._automatic_pm_alert.props.msg = self.restart_msg + self._automatic_pm_alert.show() + + box_extreme_pm = gtk.HBox(spacing=style.DEFAULT_SPACING) + label_extreme_pm = gtk.Label( + _('Extreme power management (disables' \ + 'wireless radio, increases battery life)')) + label_extreme_pm.set_alignment(0, 0.5) + self._extreme_button = gtk.CheckButton() + self._extreme_button.set_alignment(0, 0) + box_extreme_pm.pack_start(self._extreme_button, expand=False) + self._extreme_button.show() + box_extreme_pm.pack_start(label_extreme_pm, expand=False) + group.add_widget(label_extreme_pm) + label_extreme_pm.show() + box_pm.pack_start(box_extreme_pm, expand=False) + box_extreme_pm.show() + + self._extreme_pm_alert = InlineAlert() + label_extreme_pm_error = gtk.Label() + group.add_widget(label_extreme_pm_error) + self._extreme_pm_alert_box.pack_start(label_extreme_pm_error, + expand=False) + label_extreme_pm_error.show() + self._extreme_pm_alert_box.pack_start(self._extreme_pm_alert, + expand=False) + box_pm.pack_end(self._extreme_pm_alert_box, expand=False) + self._extreme_pm_alert_box.show() + if 'extreme_pm' in self.restart_alerts: + self._extreme_pm_alert.props.msg = self.restart_msg + self._extreme_pm_alert.show() + + self.pack_start(box_pm, expand=False) + box_pm.show() + + self.setup() + + def setup(self): + try: + automatic_state = self._model.get_automatic_pm() + extreme_state = self._model.get_extreme_pm() + + except Exception, detail: + self._automatic_pm_alert.props.msg = detail + self._automatic_pm_alert.show() + + self._extreme_pm_alert.props.msg = detail + self._extreme_pm_alert.show() + else: + self._automatic_button.set_active(automatic_state) + self._extreme_button.set_active(extreme_state) + + self._extreme_pm_valid = True + self._automatic_pm_valid = True + self.needs_restart = False + self._automatic_pm_change_handler = self._automatic_button.connect( \ + 'toggled', self.__automatic_pm_toggled_cb) + self._extreme_pm_change_handler = self._extreme_button.connect( \ + 'toggled', self.__extreme_pm_toggled_cb) + + def undo(self): + self._automatic_button.disconnect(self._automatic_pm_change_handler) + self._extreme_button.disconnect(self._extreme_pm_change_handler) + self._model.undo() + self._extreme_pm_alert.hide() + self._automatic_pm_alert.hide() + + def _validate(self): + if self._extreme_pm_valid and self._automatic_pm_valid: + self.props.is_valid = True + else: + self.props.is_valid = False + + def __automatic_pm_toggled_cb(self, widget, data=None): + state = widget.get_active() + try: + self._model.set_automatic_pm(state) + except Exception, detail: + print detail + self._automatic_pm_alert.props.msg = detail + else: + self._automatic_pm_valid = True + + self._validate() + return False + + def __extreme_pm_toggled_cb(self, widget, data=None): + state = widget.get_active() + try: + self._model.set_extreme_pm(state) + except Exception, detail: + print detail + self._extreme_pm_alert.props.msg = detail + else: + self._extreme_pm_valid = True + + self._validate() + return False |