Hi,
the first patch to review will modularize the model. Each section has a
file with it's set/get/print functions placed in a folder called model.
This will then be used by the command-line-interface and the graphical
frontend.
The timezone is using the environment variable 'TZ' which is set in the
main function of the shell. The second patch adds the variable to the
sugar config. All this was done to avoid to use root (since the timezone
method had to write to /etc/sysconfig/clock before).
Best,
Simon
diff --git a/src/sugar/profile.py b/src/sugar/profile.py
index 11991dd..3b917e5 100644
--- a/src/sugar/profile.py
+++ b/src/sugar/profile.py
@@ -26,6 +26,7 @@ from sugar.graphics.xocolor import XoColor
DEFAULT_JABBER_SERVER = 'olpc.collabora.co.uk'
DEFAULT_VOLUME = 81
+DEFAULT_TIMEZONE = 'UTC'
_profile = None
@@ -63,6 +64,7 @@ class Profile(object):
self.color = None
self.jabber_server = DEFAULT_JABBER_SERVER
self.jabber_registered = False
+ self.timezone = DEFAULT_TIMEZONE
self.backup1 = None
self.sound_volume = DEFAULT_VOLUME
@@ -93,6 +95,8 @@ class Profile(object):
_set_key(cp, 'Server', 'Backup1', self.backup1)
if self.jabber_server:
_set_key(cp, 'Jabber', 'Server', self.jabber_server)
+ if self.timezone:
+ _set_key(cp, 'Date', 'Timezone', self.timezone)
_set_key(cp, 'Jabber', 'Registered', self.jabber_registered)
@@ -118,6 +122,8 @@ class Profile(object):
registered = cp.get('Jabber', 'Registered')
if registered.lower() == "true":
self.jabber_registered = True
+ if cp.has_option('Date', 'Timezone'):
+ self.timezone = cp.get('Date', 'Timezone')
if cp.has_option('Server', 'Backup1'):
self.backup1 = cp.get('Server', 'Backup1')
if cp.has_option('Sound', 'Volume'):
diff --git a/bin/sugar-control-panel.in b/bin/sugar-control-panel.in
index 922f95c..e70764b 100644
--- a/bin/sugar-control-panel.in
+++ b/bin/sugar-control-panel.in
@@ -17,10 +17,12 @@
import sys
-sys.path.insert(0, '@prefix@/share/sugar/shell')
+path = '@prefix@/share/sugar/shell'
+
+sys.path.insert(0, path)
from controlpanel.cmd import main
-main()
+main(path)
diff --git a/configure.ac b/configure.ac
index a99fdf0..d6e8b12 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,6 +43,7 @@ data/Makefile
service/Makefile
src/Makefile
src/controlpanel/Makefile
+src/controlpanel/model/Makefile
src/intro/Makefile
src/hardware/Makefile
src/view/Makefile
diff --git a/src/controlpanel/Makefile.am b/src/controlpanel/Makefile.am
index f89132c..d50559d 100644
--- a/src/controlpanel/Makefile.am
+++ b/src/controlpanel/Makefile.am
@@ -1,5 +1,4 @@
sugardir = $(pkgdatadir)/shell/controlpanel
sugar_PYTHON = \
__init__.py \
- cmd.py \
- control.py
+ cmd.py
diff --git a/src/controlpanel/cmd.py b/src/controlpanel/cmd.py
index 24653b2..da89cda 100644
--- a/src/controlpanel/cmd.py
+++ b/src/controlpanel/cmd.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007, One Laptop Per Child
+# 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
@@ -16,11 +16,12 @@
import sys
import getopt
+import os
from gettext import gettext as _
-from controlpanel import control
-
+
def cmd_help():
+ '''Print the help for to the screen'''
print _('Usage: sugar-control-panel [ option ] key [ args ... ] \n\
Control for the sugar environment. \n\
Options: \n\
@@ -31,7 +32,28 @@ def cmd_help():
-s key set the current value for the key \n\
')
-def main():
+def note_restart():
+ '''Instructions how to restart sugar'''
+ print _('To apply your changes you have to restart sugar.\n' +
+ 'Hit ctrl+alt+erase on the keyboard to trigger a restart.')
+
+def load_modules(path):
+ '''Build a list of pointers to available modules in the model directory
+ and load them.
+ '''
+ subpath = ['controlpanel', 'model']
+ names = os.listdir(os.path.join(path, '/'.join(subpath)))
+
+ modules = []
+ for name in names:
+ if name.endswith('.py') and name != '__init__.py':
+ tmp = name.strip('.py')
+ mod = __import__('.'.join(subpath) + '.' +
+ tmp, globals(), locals(), [tmp])
+ modules.append(mod)
+ return modules
+
+def main(path):
try:
opts, args = getopt.getopt(sys.argv[1:], "h:s:g:l", [])
except getopt.GetoptError:
@@ -41,37 +63,49 @@ def main():
if not opts:
cmd_help()
sys.exit()
-
+
+ modules = load_modules(path)
+
for opt, key in opts:
- if opt in ("-h"):
- method = getattr(control, 'set_' + key, None)
- if method is None:
- print _("sugar-control-panel: key=%s not an available option"
- % key)
- sys.exit()
- else:
- print method.__doc__
- if opt in ("-l"):
- elems = dir(control)
- for elem in elems:
- if elem.startswith('set_'):
- print elem[4:]
+ if opt in ("-h"):
+ for module in modules:
+ method = getattr(module, 'set_' + key, None)
+ if method:
+ print method.__doc__
+ sys.exit()
+ print _("sugar-control-panel: key=%s not an available option"
+ % key)
+ if opt in ("-l"):
+ for module in modules:
+ methods = dir(module)
+ print '%s:' % module.__name__.split('.')[-1]
+ for method in methods:
+ if method.startswith('get_'):
+ print ' %s' % method[4:]
if opt in ("-g"):
- method = getattr(control, 'print_' + key, None)
- if method is None:
- print _("sugar-control-panel: key=%s not an available option"
- % key)
- sys.exit()
- else:
- method()
+ for module in modules:
+ method = getattr(module, 'print_' + key, None)
+ if method:
+ try:
+ method()
+ except Exception, detail:
+ print _("sugar-control-panel: %s"
+ % detail)
+ sys.exit()
+ print _("sugar-control-panel: key=%s not an available option"
+ % key)
if opt in ("-s"):
- method = getattr(control, 'set_' + key, None)
- if method is None:
- print _("sugar-control-panel: key=%s not an available option"
- % key)
- sys.exit()
- else:
- try:
- method(*args)
- except Exception, e:
- print _("sugar-control-panel: %s"% e)
+ for module in modules:
+ method = getattr(module, 'set_' + key, None)
+ if method:
+ note = 0
+ try:
+ note = method(*args)
+ except Exception, detail:
+ print _("sugar-control-panel: %s"
+ % detail)
+ if note == 'RESTART':
+ note_restart()
+ sys.exit()
+ print _("sugar-control-panel: key=%s not an available option"
+ % key)
diff --git a/src/controlpanel/model/Makefile.am b/src/controlpanel/model/Makefile.am
new file mode 100644
index 0000000..4bc3264
--- /dev/null
+++ b/src/controlpanel/model/Makefile.am
@@ -0,0 +1,8 @@
+sugardir = $(pkgdatadir)/shell/controlpanel/model
+sugar_PYTHON = \
+ __init__.py \
+ network.py \
+ aboutme.py \
+ language.py \
+ timezone.py \
+ aboutxo.py
diff --git a/src/controlpanel/model/__init__.py b/src/controlpanel/model/__init__.py
new file mode 100644
index 0000000..2b0f269
--- /dev/null
+++ b/src/controlpanel/model/__init__.py
@@ -0,0 +1,17 @@
+# 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
+#
+
diff --git a/src/controlpanel/model/aboutme.py b/src/controlpanel/model/aboutme.py
new file mode 100644
index 0000000..98726c6
--- /dev/null
+++ b/src/controlpanel/model/aboutme.py
@@ -0,0 +1,108 @@
+# 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()
+ pro.nick_name = nick
+ pro.save()
+ return 'RESTART'
+
+def get_color():
+ return profile.get_color()
+
+def print_color():
+ color = get_color().to_string()
+ tmp = color.split(',')
+
+ stroke = None
+ fill = None
+ for color in _COLORS:
+ for hue in _COLORS[color]:
+ if _COLORS[color][hue] == tmp[0]:
+ stroke = (color, hue)
+ if _COLORS[color][hue] == tmp[1]:
+ fill = (color, hue)
+
+ if stroke is not None:
+ print 'stroke: color=%s hue=%s' % (stroke[0], stroke[1])
+ else:
+ print 'stroke: %s' % (tmp[0])
+ if fill is not None:
+ print 'fill: color=%s hue=%s' % (fill[0], fill[1])
+ else:
+ print 'fill: %s' % (tmp[1])
+
+def set_color(stroke, fill, modstroke='medium', modfill='medium'):
+ """Set the system color by setting a fill and stroke color.
+ fill : [red, orange, yellow, blue, purple]
+ stroke : [red, orange, yellow, blue, purple]
+ hue stroke : [dark, medium, light] (optional)
+ hue fill : [dark, medium, light] (optional)
+ """
+
+ if modstroke not in _MODIFIERS or modfill 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 modstroke == modfill:
+ if modfill == 'medium':
+ modfill = 'light'
+ else:
+ modfill = 'medium'
+
+ color = _COLORS[stroke][modstroke] + ',' + _COLORS[fill][modfill]
+ pro = profile.get_profile()
+ pro.color = XoColor(color)
+ pro.save()
+ return "RESTART"
+
+def set_color_xo(color):
+ """Set a color with an XoColor
+ """
+ pro = profile.get_profile()
+ pro.color = color
+ pro.save()
+ return "RESTART"
diff --git a/src/controlpanel/model/aboutxo.py b/src/controlpanel/model/aboutxo.py
new file mode 100644
index 0000000..1a63f32
--- /dev/null
+++ b/src/controlpanel/model/aboutxo.py
@@ -0,0 +1,22 @@
+# 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
+#
+
+def get_aboutxo():
+ return 'TODO: make info available here as well for the cml interface'
+
+def print_aboutxo():
+ print get_aboutxo()
diff --git a/src/controlpanel/model/language.py b/src/controlpanel/model/language.py
new file mode 100644
index 0000000..49bac07
--- /dev/null
+++ b/src/controlpanel/model/language.py
@@ -0,0 +1,123 @@
+# 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
+
+def readlocale():
+ fdp = subprocess.Popen(['locale', '-av'], stdout=subprocess.PIPE)
+ lines = fdp.stdout.read().split('\n')
+ locales = []
+ try:
+ for line in lines:
+ if line.find('locale:') != -1:
+ loc = line.lstrip('locale: ')
+ loc = loc.split('archive:')[0].strip()
+ elif line.find('language |') != -1:
+ lang = line.lstrip('language |')
+ elif line.find('territory |') != -1:
+ ter = line.lstrip('territory |')
+ if loc.endswith('utf8') and len(lang):
+ locales.append((lang, ter, loc))
+ except Exception, error:
+ print "Error reading locale: %s" % error
+ locales.sort()
+ return locales
+
+def _initialize():
+ languages = readlocale()
+ 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(_("Could not access %s. Create standard settings.") % path)
+ fd = open(path, 'w')
+ fd.write('LANG="en_US.utf8"\n')
+ 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="' + lang + '"\n'
+ 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(_("Could not access %s. Create standard settings.") % path)
+ fd = open(path, 'w')
+ default = 'en_US.utf8'
+ fd.write('LANG="%s"\n' % default)
+ fd.close()
+ return default
+
+ 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 = readlocale()
+ for lang in languages:
+ if lang[2] == code:
+ 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 "RESTART"
+ else:
+ languages = readlocale()
+ for lang in languages:
+ code = lang[0].replace(' ', '_') + '/' + lang[1].replace(' ', '_')
+ if code == language:
+ _write_i18n(lang[2])
+ return "RESTART"
+ print (_("Sorry I do not speak \'%s\'.") % language)
+
+# inilialize the docstrings for the language
+_initialize()
+
diff --git a/src/controlpanel/model/network.py b/src/controlpanel/model/network.py
new file mode 100644
index 0000000..6190a4d
--- /dev/null
+++ b/src/controlpanel/model/network.py
@@ -0,0 +1,86 @@
+# 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
+
+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'
+ """
+ if not server:
+ raise ValueError(_("You must enter a server."))
+ pro = profile.get_profile()
+ pro.jabber_server = server
+ pro.jabber_registered = False
+ pro.save()
+ return "RESTART"
+
+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 == 0:
+ return _('off')
+ elif state == 1:
+ return _('on')
+ else:
+ raise ReadError(_('State is unknown.'))
+
+def print_radio():
+ print get_radio()
+
+def set_radio(state):
+ """Turn Radio 'on' or 'off'
+ state : 'on/off'
+ """
+ if state == 'on':
+ 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':
+ 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."))
+
diff --git a/src/controlpanel/model/timezone.py b/src/controlpanel/model/timezone.py
new file mode 100644
index 0000000..5ebb9df
--- /dev/null
+++ b/src/controlpanel/model/timezone.py
@@ -0,0 +1,80 @@
+# 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
+
+def _initialize():
+ '''Initialize the docstring of the set function'''
+ timezones = read_timezones()
+ for timezone in timezones:
+ set_timezone.__doc__ += timezone + '\n'
+
+def read_timezones(fn='/usr/share/zoneinfo/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(-14, 13):
+ if offset < 0:
+ tz = 'GMT%d' % offset
+ elif offset > 0:
+ tz = 'GMT+%d' % offset
+ else:
+ tz = 'GMT'
+ 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
+ server : e.g. 'America/Los_Angeles'
+ """
+ timezones = read_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 'RESTART'
+
+# inilialize the docstrings for the timezone
+_initialize()
+
diff --git a/src/main.py b/src/main.py
index 76d753f..3a88a37 100644
--- a/src/main.py
+++ b/src/main.py
@@ -110,6 +110,9 @@ def main():
win.show_all()
gtk.main()
+ # set timezone
+ os.environ['TZ'] = get_profile().timezone
+
if os.environ.has_key("SUGAR_TP_DEBUG"):
# Allow the user time to start up telepathy connection managers
# using the Sugar DBus bus address
_______________________________________________
Sugar mailing list
[email protected]
http://lists.laptop.org/listinfo/sugar