[Dextrose] [PATCH] Database support for 3G control panel
Anish Mangal
anishmangal2002 at gmail.com
Wed Feb 2 10:52:57 EST 2011
committed to dx/mainline
http://git.sugarlabs.org/dextrose/mainline/commit/c6d7845fce52a9b0c345aea103e2d3672426dd61
On Tue, Jan 11, 2011 at 11:52, Martin Abente
<martin.abente.lahaye at gmail.com> wrote:
> From: Andrés Ambrois <andresambrois at gmail.com>
>
> For more information please look at #1630
>
> ---
> configure.ac | 1 +
> .../cpsection/modemconfiguration/Makefile.am | 2 +
> .../cpsection/modemconfiguration/config.py.in | 20 ++
> extensions/cpsection/modemconfiguration/model.py | 119 +++++++++++++
> extensions/cpsection/modemconfiguration/view.py | 184 ++++++++++++++++----
> 5 files changed, 292 insertions(+), 34 deletions(-)
> create mode 100644 extensions/cpsection/modemconfiguration/config.py.in
> mode change 100755 => 100644 extensions/cpsection/modemconfiguration/model.py
>
> diff --git a/configure.ac b/configure.ac
> index 13a2f09..68a8bf3 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -56,6 +56,7 @@ extensions/cpsection/frame/Makefile
> extensions/cpsection/keyboard/Makefile
> extensions/cpsection/language/Makefile
> extensions/cpsection/modemconfiguration/Makefile
> +extensions/cpsection/modemconfiguration/config.py
> extensions/cpsection/Makefile
> extensions/cpsection/network/Makefile
> extensions/cpsection/power/Makefile
> diff --git a/extensions/cpsection/modemconfiguration/Makefile.am b/extensions/cpsection/modemconfiguration/Makefile.am
> index 3e2613e..525e02e 100644
> --- a/extensions/cpsection/modemconfiguration/Makefile.am
> +++ b/extensions/cpsection/modemconfiguration/Makefile.am
> @@ -4,3 +4,5 @@ sugar_PYTHON = \
> __init__.py \
> model.py \
> view.py
> +
> +nodist_sugar_PYTHON = config.py
> diff --git a/extensions/cpsection/modemconfiguration/config.py.in b/extensions/cpsection/modemconfiguration/config.py.in
> new file mode 100644
> index 0000000..6fa688e
> --- /dev/null
> +++ b/extensions/cpsection/modemconfiguration/config.py.in
> @@ -0,0 +1,20 @@
> +# -*- encoding: utf-8 -*-
> +# Copyright (C) 2010 Andrés Ambrois
> +#
> +# 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 US
> +
> +PROVIDERS_PATH = "@prefix@/share/mobile-broadband-provider-info/serviceproviders.xml"
> +PROVIDERS_FORMAT_SUPPORTED = "2.0"
> +COUNTRY_CODES_PATH = "@prefix@/share/zoneinfo/iso3166.tab"
> diff --git a/extensions/cpsection/modemconfiguration/model.py b/extensions/cpsection/modemconfiguration/model.py
> old mode 100755
> new mode 100644
> index 2545ce1..dbec47d
> --- a/extensions/cpsection/modemconfiguration/model.py
> +++ b/extensions/cpsection/modemconfiguration/model.py
> @@ -15,11 +15,22 @@
> # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 US
>
> import gconf
> +import gtk
> +import os
> +import locale
> +import logging
> +
> +from xml.etree.cElementTree import ElementTree
> +from gettext import gettext as _
>
> from jarabe.model.network import GSM_USERNAME_PATH, GSM_PASSWORD_PATH, \
> GSM_NUMBER_PATH, GSM_APN_PATH, GSM_PIN_PATH, \
> GSM_PUK_PATH
>
> +from cpsection.modemconfiguration.config import PROVIDERS_PATH, \
> + PROVIDERS_FORMAT_SUPPORTED, \
> + COUNTRY_CODES_PATH
> +
> def get_username():
> client = gconf.client_get_default()
> return client.get_string(GSM_USERNAME_PATH) or ''
> @@ -68,3 +79,111 @@ def set_puk(puk):
> client = gconf.client_get_default()
> client.set_string(GSM_PUK_PATH, puk)
>
> +def has_providers_db():
> + if not os.path.isfile(COUNTRY_CODES_PATH):
> + logging.debug("Mobile broadband provider database: Country " \
> + "codes path %s not found.", COUNTRY_CODES_PATH)
> + return False
> + try:
> + tree = ElementTree(file=PROVIDERS_PATH)
> + except (IOError, SyntaxError), e:
> + logging.debug("Mobile broadband provider database: Could not read " \
> + "provider information %s error=%s", PROVIDERS_PATH)
> + return False
> + else:
> + elem = tree.getroot()
> + if elem is None or elem.get('format') != PROVIDERS_FORMAT_SUPPORTED:
> + logging.debug("Mobile broadband provider database: Could not " \
> + "read provider information. %s is wrong format.",
> + elem.get('format'))
> + return False
> + return True
> +
> +
> +class CountryListStore(gtk.ListStore):
> + COUNTRY_CODE = locale.getdefaultlocale()[0][3:5].lower()
> +
> + def __init__(self):
> + gtk.ListStore.__init__(self, str, object)
> + codes = {}
> + with open(COUNTRY_CODES_PATH) as codes_file:
> + for line in codes_file:
> + if line.startswith('#'):
> + continue
> + code, name = line.split('\t')[:2]
> + codes[code.lower()] = name.strip()
> + etree = ElementTree(file=PROVIDERS_PATH).getroot()
> + self._country_idx = None
> + i = 0
> + for elem in etree.findall('.//country'):
> + code = elem.attrib['code']
> + if code == self.COUNTRY_CODE:
> + self._country_idx = i
> + else:
> + i += 1
> + if code in codes:
> + self.append((codes[code], elem))
> + else:
> + self.append((code, elem))
> +
> + def get_row_providers(self, row):
> + return self[row][1]
> +
> + def guess_country_row(self):
> + if self._country_idx is not None:
> + return self._country_idx
> + else:
> + return -1
> +
> +class ProviderListStore(gtk.ListStore):
> + def __init__(self, elem):
> + gtk.ListStore.__init__(self, str, object)
> + for provider_elem in elem.findall('.//provider'):
> + apns = provider_elem.findall('.//apn')
> + if not apns:
> + # Skip carriers with CDMA entries only
> + continue
> + self.append((provider_elem.find('.//name').text, apns))
> +
> + def get_row_plans(self, row):
> + return self[row][1]
> +
> +class PlanListStore(gtk.ListStore):
> + LANG_NS_ATTR = '{http://www.w3.org/XML/1998/namespace}lang'
> + LANG = locale.getdefaultlocale()[0][:2]
> + DEFAULT_NUMBER = '*99#'
> +
> + def __init__(self, elems):
> + gtk.ListStore.__init__(self, str, object)
> + for apn_elem in elems:
> + plan = {}
> + names = apn_elem.findall('.//name')
> + if names:
> + for name in names:
> + if name.get(self.LANG_NS_ATTR) is None:
> + # serviceproviders.xml default value
> + plan['name'] = name.text
> + elif name.get(self.LANG_NS_ATTR) == self.LANG:
> + # Great! We found a name value for our locale!
> + plan['name'] = name.text
> + break
> + else:
> + plan['name'] = _('Default')
> + plan['apn'] = apn_elem.get('value')
> + user = apn_elem.find('.//username')
> + if user is not None:
> + plan['username'] = user.text
> + else:
> + plan['username'] = ''
> + passwd = apn_elem.find('.//password')
> + if passwd is not None:
> + plan['password'] = passwd.text
> + else:
> + plan['password'] = ''
> +
> + plan['number'] = self.DEFAULT_NUMBER
> +
> + self.append((plan['name'], plan))
> +
> + def get_row_plan(self, row):
> + return self[row][1]
> diff --git a/extensions/cpsection/modemconfiguration/view.py b/extensions/cpsection/modemconfiguration/view.py
> index b236f3f..3b03b3d 100644
> --- a/extensions/cpsection/modemconfiguration/view.py
> +++ b/extensions/cpsection/modemconfiguration/view.py
> @@ -14,8 +14,6 @@
> # along with this program; if not, write to the Free Software
> # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 US
>
> -import os
> -import logging
> from gettext import gettext as _
>
> import gtk
> @@ -31,7 +29,7 @@ class EntryWithLabel(gtk.HBox):
> __gtype_name__ = "SugarEntryWithLabel"
>
> def __init__(self, label_text):
> - gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING)
> + gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING * 2)
>
> self._timeout_sid = 0
> self._changed_handler = None
> @@ -44,11 +42,11 @@ class EntryWithLabel(gtk.HBox):
> self.pack_start(self.label, expand=False)
> self.label.show()
>
> - self._entry = gtk.Entry(25)
> - self._entry.connect('changed', self.__entry_changed_cb)
> - self._entry.set_width_chars(25)
> - self.pack_start(self._entry, expand=False)
> - self._entry.show()
> + self.entry = gtk.Entry(25)
> + self.entry.connect('changed', self.__entry_changed_cb)
> + self.entry.set_width_chars(25)
> + self.pack_start(self.entry, expand=False)
> + self.entry.show()
>
> def __entry_changed_cb(self, widget, data=None):
> if self._timeout_sid:
> @@ -59,11 +57,11 @@ class EntryWithLabel(gtk.HBox):
> def __timeout_cb(self):
> self._timeout_sid = 0
>
> - if self._entry.get_text() == self.get_value():
> + if self.entry.get_text() == self.get_value():
> return False
>
> try:
> - self.set_value(self._entry.get_text())
> + self.set_value(self.entry.get_text())
> except ValueError:
> self._is_valid = False
> else:
> @@ -74,18 +72,20 @@ class EntryWithLabel(gtk.HBox):
> return False
>
> def set_text_from_model(self):
> - self._entry.set_text(self.get_value())
> + self.entry.set_text(self.get_value())
>
> def get_value(self):
> raise NotImplementedError
>
> - def set_value(self):
> + def set_value(self, value):
> raise NotImplementedError
>
> def _get_is_valid(self):
> return self._is_valid
> +
> is_valid = gobject.property(type=bool, getter=_get_is_valid, default=True)
>
> +
> class UsernameEntry(EntryWithLabel):
> def __init__(self, model):
> EntryWithLabel.__init__(self, _('Username:'))
> @@ -97,6 +97,7 @@ class UsernameEntry(EntryWithLabel):
> def set_value(self, username):
> self._model.set_username(username)
>
> +
> class PasswordEntry(EntryWithLabel):
> def __init__(self, model):
> EntryWithLabel.__init__(self, _('Password:'))
> @@ -108,6 +109,7 @@ class PasswordEntry(EntryWithLabel):
> def set_value(self, password):
> self._model.set_password(password)
>
> +
> class NumberEntry(EntryWithLabel):
> def __init__(self, model):
> EntryWithLabel.__init__(self, _('Number:'))
> @@ -119,6 +121,7 @@ class NumberEntry(EntryWithLabel):
> def set_value(self, number):
> self._model.set_number(number)
>
> +
> class ApnEntry(EntryWithLabel):
> def __init__(self, model):
> EntryWithLabel.__init__(self, _('Access Point Name (APN):'))
> @@ -130,6 +133,7 @@ class ApnEntry(EntryWithLabel):
> def set_value(self, apn):
> self._model.set_apn(apn)
>
> +
> class PinEntry(EntryWithLabel):
> def __init__(self, model):
> EntryWithLabel.__init__(self, _('Personal Identity Number (PIN):'))
> @@ -141,6 +145,7 @@ class PinEntry(EntryWithLabel):
> def set_value(self, pin):
> self._model.set_pin(pin)
>
> +
> class PukEntry(EntryWithLabel):
> def __init__(self, model):
> EntryWithLabel.__init__(self, _('Personal Unblocking Key (PUK):'))
> @@ -160,61 +165,150 @@ class ModemConfiguration(SectionView):
> self._model = model
> self.restart_alerts = alerts
>
> - self.set_border_width(style.DEFAULT_SPACING)
> self.set_spacing(style.DEFAULT_SPACING)
> - self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
> +
> + label_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
> + combo_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
> +
> + scrolled_win = gtk.ScrolledWindow()
> + scrolled_win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
> + scrolled_win.show()
> + self.add(scrolled_win)
> +
> + main_box = gtk.VBox(spacing=style.DEFAULT_SPACING)
> + main_box.set_border_width(style.DEFAULT_SPACING)
> + main_box.show()
> + scrolled_win.add_with_viewport(main_box)
>
> explanation = _("You will need to provide the following " \
> "information to set up a mobile " \
> "broadband connection to a cellular "\
> "(3G) network.")
> self._text = gtk.Label(explanation)
> - self._text.set_width_chars(100)
> self._text.set_line_wrap(True)
> self._text.set_alignment(0, 0)
> - self.pack_start(self._text, False)
> + main_box.pack_start(self._text, False)
> self._text.show()
>
> + if model.has_providers_db():
> + self._upper_box = gtk.VBox(spacing=style.DEFAULT_SPACING)
> + self._upper_box.set_border_width(style.DEFAULT_SPACING)
> + main_box.pack_start(self._upper_box, expand=False)
> + self._upper_box.show()
> +
> +
> + box = gtk.HBox(spacing=style.DEFAULT_SPACING * 2)
> + label = gtk.Label(_('Country:'))
> + label.set_alignment(1, 0.5)
> + label_group.add_widget(label)
> + box.pack_start(label, False)
> + label.show()
> + country_store = model.CountryListStore()
> + country_combo = gtk.ComboBox(country_store)
> + combo_group.add_widget(country_combo)
> + cell = gtk.CellRendererText()
> + cell.props.xalign = 0.5
> + country_combo.pack_start(cell)
> + country_combo.add_attribute(cell, 'text', 0)
> + country_combo.connect('changed', self.__country_selected_cb)
> + box.pack_start(country_combo, False)
> + country_combo.show()
> + self._upper_box.pack_start(box, False)
> + box.show()
> +
> + box = gtk.HBox(spacing=style.DEFAULT_SPACING * 2)
> + label = gtk.Label(_('Provider:'))
> + label.set_alignment(1, 0.5)
> + label_group.add_widget(label)
> + box.pack_start(label, False)
> + label.show()
> + self._providers_combo = gtk.ComboBox()
> + combo_group.add_widget(self._providers_combo)
> + cell = gtk.CellRendererText()
> + cell.props.xalign = 0.5
> + self._providers_combo.pack_start(cell)
> + self._providers_combo.add_attribute(cell, 'text', 0)
> + self._providers_combo.connect('changed',
> + self.__provider_selected_cb)
> + box.pack_start(self._providers_combo, False)
> + self._providers_combo.show()
> + self._upper_box.pack_start(box, False)
> + box.show()
> +
> + box = gtk.HBox(spacing=style.DEFAULT_SPACING*2)
> + label = gtk.Label(_('Plan:'))
> + label.set_alignment(1, 0.5)
> + label_group.add_widget(label)
> + box.pack_start(label, False)
> + label.show()
> + self._plan_combo = gtk.ComboBox()
> + combo_group.add_widget(self._plan_combo)
> + cell = gtk.CellRendererText()
> + cell.props.xalign = 0.5
> + self._plan_combo.pack_start(cell)
> + self._plan_combo.add_attribute(cell, 'text', 0)
> + self._plan_combo.connect('changed', self.__plan_selected_cb)
> + box.pack_start(self._plan_combo, False)
> + self._plan_combo.show()
> + self._upper_box.pack_start(box, False)
> + box.show()
> +
> + country_combo.set_active(country_store.guess_country_row())
> +
> + separator = gtk.HSeparator()
> + main_box.pack_start(separator, False)
> + separator.show()
> +
> + self._lower_box = gtk.VBox(spacing=style.DEFAULT_SPACING)
> + self._lower_box.set_border_width(style.DEFAULT_SPACING)
> + main_box.pack_start(self._lower_box, expand=False)
> + self._lower_box.show()
> +
> self._username_entry = UsernameEntry(model)
> self._username_entry.connect('notify::is-valid',
> self.__notify_is_valid_cb)
> - self._group.add_widget(self._username_entry.label)
> - self.pack_start(self._username_entry, expand=False)
> + label_group.add_widget(self._username_entry.label)
> + combo_group.add_widget(self._username_entry.entry)
> + self._lower_box.pack_start(self._username_entry, fill=False)
> self._username_entry.show()
>
> self._password_entry = PasswordEntry(model)
> self._password_entry.connect('notify::is-valid',
> self.__notify_is_valid_cb)
> - self._group.add_widget(self._password_entry.label)
> - self.pack_start(self._password_entry, expand=False)
> + label_group.add_widget(self._password_entry.label)
> + combo_group.add_widget(self._password_entry.entry)
> + self._lower_box.pack_start(self._password_entry, fill=False)
> self._password_entry.show()
>
> self._number_entry = NumberEntry(model)
> self._number_entry.connect('notify::is-valid',
> self.__notify_is_valid_cb)
> - self._group.add_widget(self._number_entry.label)
> - self.pack_start(self._number_entry, expand=False)
> + label_group.add_widget(self._number_entry.label)
> + combo_group.add_widget(self._number_entry.entry)
> + self._lower_box.pack_start(self._number_entry, fill=False)
> self._number_entry.show()
>
> self._apn_entry = ApnEntry(model)
> self._apn_entry.connect('notify::is-valid',
> self.__notify_is_valid_cb)
> - self._group.add_widget(self._apn_entry.label)
> - self.pack_start(self._apn_entry, expand=False)
> + label_group.add_widget(self._apn_entry.label)
> + combo_group.add_widget(self._apn_entry.entry)
> + self._lower_box.pack_start(self._apn_entry, fill=False)
> self._apn_entry.show()
>
> self._pin_entry = PinEntry(model)
> self._pin_entry.connect('notify::is-valid',
> self.__notify_is_valid_cb)
> - self._group.add_widget(self._pin_entry.label)
> - self.pack_start(self._pin_entry, expand=False)
> + label_group.add_widget(self._pin_entry.label)
> + self._lower_box.pack_start(self._pin_entry, fill=False)
> self._pin_entry.show()
>
> self._puk_entry = PukEntry(model)
> self._puk_entry.connect('notify::is-valid',
> self.__notify_is_valid_cb)
> - self._group.add_widget(self._puk_entry.label)
> - self.pack_start(self._puk_entry, expand=False)
> + label_group.add_widget(self._puk_entry.label)
> + combo_group.add_widget(self._puk_entry.entry)
> + self._lower_box.pack_start(self._puk_entry, fill=False)
> self._puk_entry.show()
>
> self.setup()
> @@ -232,14 +326,37 @@ class ModemConfiguration(SectionView):
> def undo(self):
> self._model.undo()
>
> + def __country_selected_cb(self, combo):
> + model = combo.get_model()
> + providers = model.get_row_providers(combo.get_active())
> + self._providers_combo.set_model(
> + self._model.ProviderListStore(providers))
> +
> + def __provider_selected_cb(self, combo):
> + model = combo.get_model()
> + plans = model.get_row_plans(combo.get_active())
> + self._plan_combo.set_model(self._model.PlanListStore(plans))
> +
> + def __plan_selected_cb(self, combo):
> + model = combo.get_model()
> + plan = model.get_row_plan(combo.get_active())
> + self._username_entry.set_value(plan['username'])
> + self._username_entry.set_text_from_model()
> + self._password_entry.set_value(plan['password'])
> + self._password_entry.set_text_from_model()
> + self._number_entry.set_value(plan['number'])
> + self._number_entry.set_text_from_model()
> + self._apn_entry.set_value(plan['apn'])
> + self._apn_entry.set_text_from_model()
> +
> def _validate(self):
> if self._username_entry.is_valid and \
> - self._password_entry.is_valid and \
> + self._password_entry.is_valid and \
> self._number_entry.is_valid and \
> - self._apn_entry.is_valid and \
> - self._pin_entry.is_valid and \
> - self._puk_entry.is_valid:
> - self.props.is_valid = True
> + self._apn_entry.is_valid and \
> + self._pin_entry.is_valid and \
> + self._puk_entry.is_valid:
> + self.props.is_valid = True
> else:
> self.props.is_valid = False
>
> @@ -247,4 +364,3 @@ class ModemConfiguration(SectionView):
> if entry.is_valid:
> self.needs_restart = True
> self._validate()
> -
> --
> 1.7.1
>
>
> _______________________________________________
> Dextrose mailing list
> Dextrose at lists.sugarlabs.org
> http://lists.sugarlabs.org/listinfo/dextrose
>
>
--
Anish
More information about the Dextrose
mailing list