Ticket #1630: gsm-provider-db-v4-1630.patch

File gsm-provider-db-v4-1630.patch, 20.1 KB (added by aa, 9 years ago)
  • configure.ac

    diff --git a/configure.ac b/configure.ac
    index fb38cad..f3fa6c0 100644
    a b extensions/cpsection/frame/Makefile 
    5656extensions/cpsection/keyboard/Makefile
    5757extensions/cpsection/language/Makefile
    5858extensions/cpsection/modemconfiguration/Makefile
     59extensions/cpsection/modemconfiguration/config.py
    5960extensions/cpsection/Makefile
    6061extensions/cpsection/network/Makefile
    6162extensions/cpsection/power/Makefile
  • extensions/cpsection/modemconfiguration/Makefile.am

    diff --git a/extensions/cpsection/modemconfiguration/Makefile.am b/extensions/cpsection/modemconfiguration/Makefile.am
    index 3e2613e..525e02e 100644
    a b sugar_PYTHON = \ 
    44        __init__.py     \
    55        model.py        \
    66        view.py         
     7
     8nodist_sugar_PYTHON = config.py
  • new file extensions/cpsection/modemconfiguration/config.py.in

    diff --git a/extensions/cpsection/modemconfiguration/config.py.in b/extensions/cpsection/modemconfiguration/config.py.in
    new file mode 100644
    index 0000000..6fa688e
    - +  
     1# -*- encoding: utf-8 -*-
     2# Copyright (C) 2010 Andrés Ambrois
     3#
     4# This program is free software; you can redistribute it and/or modify
     5# it under the terms of the GNU General Public License as published by
     6# the Free Software Foundation; either version 2 of the License, or
     7# (at your option) any later version.
     8#
     9# This program is distributed in the hope that it will be useful,
     10# but WITHOUT ANY WARRANTY; without even the implied warranty of
     11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12# GNU General Public License for more details.
     13#
     14# You should have received a copy of the GNU General Public License
     15# along with this program; if not, write to the Free Software
     16# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  US
     17
     18PROVIDERS_PATH = "@prefix@/share/mobile-broadband-provider-info/serviceproviders.xml"
     19PROVIDERS_FORMAT_SUPPORTED = "2.0"
     20COUNTRY_CODES_PATH = "@prefix@/share/zoneinfo/iso3166.tab"
  • extensions/cpsection/modemconfiguration/model.py

    diff --git a/extensions/cpsection/modemconfiguration/model.py b/extensions/cpsection/modemconfiguration/model.py
    old mode 100755
    new mode 100644
    index 2545ce1..dbec47d
    a b  
    1515# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  US
    1616
    1717import gconf
     18import gtk
     19import os
     20import locale
     21import logging
     22
     23from xml.etree.cElementTree import ElementTree
     24from gettext import gettext as _
    1825
    1926from jarabe.model.network import GSM_USERNAME_PATH, GSM_PASSWORD_PATH, \
    2027                                 GSM_NUMBER_PATH, GSM_APN_PATH, GSM_PIN_PATH, \
    2128                                 GSM_PUK_PATH
    2229
     30from cpsection.modemconfiguration.config import PROVIDERS_PATH, \
     31                                                PROVIDERS_FORMAT_SUPPORTED, \
     32                                                COUNTRY_CODES_PATH
     33
    2334def get_username():
    2435    client = gconf.client_get_default()
    2536    return client.get_string(GSM_USERNAME_PATH) or ''
    def set_puk(puk): 
    6879    client = gconf.client_get_default()
    6980    client.set_string(GSM_PUK_PATH, puk)
    7081
     82def has_providers_db():
     83    if not os.path.isfile(COUNTRY_CODES_PATH):
     84        logging.debug("Mobile broadband provider database: Country " \
     85                          "codes path %s not found.", COUNTRY_CODES_PATH)
     86        return False
     87    try:
     88        tree = ElementTree(file=PROVIDERS_PATH)
     89    except (IOError, SyntaxError), e:
     90        logging.debug("Mobile broadband provider database: Could not read " \
     91                          "provider information %s error=%s", PROVIDERS_PATH)
     92        return False
     93    else:
     94        elem = tree.getroot()
     95        if elem is None or elem.get('format') != PROVIDERS_FORMAT_SUPPORTED:
     96            logging.debug("Mobile broadband provider database: Could not " \
     97                          "read provider information. %s is wrong format.",
     98                          elem.get('format'))
     99            return False
     100        return True
     101
     102
     103class CountryListStore(gtk.ListStore):
     104    COUNTRY_CODE = locale.getdefaultlocale()[0][3:5].lower()
     105
     106    def __init__(self):
     107        gtk.ListStore.__init__(self, str, object)
     108        codes = {}
     109        with open(COUNTRY_CODES_PATH) as codes_file:
     110            for line in codes_file:
     111                if line.startswith('#'):
     112                    continue
     113                code, name = line.split('\t')[:2]
     114                codes[code.lower()] = name.strip()
     115        etree = ElementTree(file=PROVIDERS_PATH).getroot()
     116        self._country_idx = None
     117        i = 0
     118        for elem in etree.findall('.//country'):
     119            code = elem.attrib['code']
     120            if code == self.COUNTRY_CODE:
     121                self._country_idx = i
     122            else:
     123                i += 1
     124            if code in codes:
     125                self.append((codes[code], elem))
     126            else:
     127                self.append((code, elem))
     128
     129    def get_row_providers(self, row):
     130        return self[row][1]
     131
     132    def guess_country_row(self):
     133        if self._country_idx is not None:
     134            return self._country_idx
     135        else:
     136            return -1
     137
     138class ProviderListStore(gtk.ListStore):
     139    def __init__(self, elem):
     140        gtk.ListStore.__init__(self, str, object)
     141        for provider_elem in elem.findall('.//provider'):
     142            apns = provider_elem.findall('.//apn')
     143            if not apns:
     144                # Skip carriers with CDMA entries only
     145                continue
     146            self.append((provider_elem.find('.//name').text, apns))
     147
     148    def get_row_plans(self, row):
     149        return self[row][1]
     150
     151class PlanListStore(gtk.ListStore):
     152    LANG_NS_ATTR = '{http://www.w3.org/XML/1998/namespace}lang'
     153    LANG = locale.getdefaultlocale()[0][:2]
     154    DEFAULT_NUMBER = '*99#'
     155
     156    def __init__(self, elems):
     157        gtk.ListStore.__init__(self, str, object)
     158        for apn_elem in elems:
     159            plan = {}
     160            names = apn_elem.findall('.//name')
     161            if names:
     162                for name in names:
     163                    if name.get(self.LANG_NS_ATTR) is None:
     164                        # serviceproviders.xml default value
     165                        plan['name'] = name.text
     166                    elif name.get(self.LANG_NS_ATTR) == self.LANG:
     167                        # Great! We found a name value for our locale!
     168                        plan['name'] = name.text
     169                        break
     170            else:
     171                plan['name'] = _('Default')
     172            plan['apn'] = apn_elem.get('value')
     173            user = apn_elem.find('.//username')
     174            if user is not None:
     175                plan['username'] = user.text
     176            else:
     177                plan['username'] = ''
     178            passwd = apn_elem.find('.//password')
     179            if passwd is not None:
     180                plan['password'] = passwd.text
     181            else:
     182                plan['password'] = ''
     183
     184            plan['number'] = self.DEFAULT_NUMBER
     185
     186            self.append((plan['name'], plan))
     187
     188    def get_row_plan(self, row):
     189        return self[row][1]
  • extensions/cpsection/modemconfiguration/view.py

    diff --git a/extensions/cpsection/modemconfiguration/view.py b/extensions/cpsection/modemconfiguration/view.py
    index b236f3f..3b03b3d 100644
    a b  
    1414# along with this program; if not, write to the Free Software
    1515# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  US
    1616
    17 import os
    18 import logging
    1917from gettext import gettext as _
    2018
    2119import gtk
    class EntryWithLabel(gtk.HBox): 
    3129    __gtype_name__ = "SugarEntryWithLabel"
    3230
    3331    def __init__(self, label_text):
    34         gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING)
     32        gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING * 2)
    3533
    3634        self._timeout_sid = 0
    3735        self._changed_handler = None
    class EntryWithLabel(gtk.HBox): 
    4442        self.pack_start(self.label, expand=False)
    4543        self.label.show()
    4644
    47         self._entry = gtk.Entry(25)
    48         self._entry.connect('changed', self.__entry_changed_cb)
    49         self._entry.set_width_chars(25)
    50         self.pack_start(self._entry, expand=False)
    51         self._entry.show()
     45        self.entry = gtk.Entry(25)
     46        self.entry.connect('changed', self.__entry_changed_cb)
     47        self.entry.set_width_chars(25)
     48        self.pack_start(self.entry, expand=False)
     49        self.entry.show()
    5250
    5351    def __entry_changed_cb(self, widget, data=None):
    5452        if self._timeout_sid:
    class EntryWithLabel(gtk.HBox): 
    5957    def __timeout_cb(self):
    6058        self._timeout_sid = 0
    6159
    62         if self._entry.get_text() == self.get_value():
     60        if self.entry.get_text() == self.get_value():
    6361            return False
    6462
    6563        try:
    66             self.set_value(self._entry.get_text())
     64            self.set_value(self.entry.get_text())
    6765        except ValueError:
    6866            self._is_valid = False
    6967        else:
    class EntryWithLabel(gtk.HBox): 
    7472        return False
    7573
    7674    def set_text_from_model(self):
    77         self._entry.set_text(self.get_value())
     75        self.entry.set_text(self.get_value())
    7876
    7977    def get_value(self):
    8078        raise NotImplementedError
    8179
    82     def set_value(self):
     80    def set_value(self, value):
    8381        raise NotImplementedError   
    8482
    8583    def _get_is_valid(self):
    8684        return self._is_valid
     85
    8786    is_valid = gobject.property(type=bool, getter=_get_is_valid, default=True)
    8887
     88
    8989class UsernameEntry(EntryWithLabel):
    9090    def __init__(self, model):
    9191        EntryWithLabel.__init__(self, _('Username:'))
    class UsernameEntry(EntryWithLabel): 
    9797    def set_value(self, username):
    9898        self._model.set_username(username)
    9999
     100
    100101class PasswordEntry(EntryWithLabel):
    101102    def __init__(self, model):
    102103        EntryWithLabel.__init__(self, _('Password:'))
    class PasswordEntry(EntryWithLabel): 
    108109    def set_value(self, password):
    109110        self._model.set_password(password)
    110111
     112
    111113class NumberEntry(EntryWithLabel):
    112114    def __init__(self, model):
    113115        EntryWithLabel.__init__(self, _('Number:'))
    class NumberEntry(EntryWithLabel): 
    119121    def set_value(self, number):
    120122        self._model.set_number(number)
    121123
     124
    122125class ApnEntry(EntryWithLabel):
    123126    def __init__(self, model):
    124127        EntryWithLabel.__init__(self, _('Access Point Name (APN):'))
    class ApnEntry(EntryWithLabel): 
    130133    def set_value(self, apn):
    131134        self._model.set_apn(apn)
    132135
     136
    133137class PinEntry(EntryWithLabel):
    134138    def __init__(self, model):
    135139        EntryWithLabel.__init__(self, _('Personal Identity Number (PIN):'))
    class PinEntry(EntryWithLabel): 
    141145    def set_value(self, pin):
    142146        self._model.set_pin(pin)
    143147
     148
    144149class PukEntry(EntryWithLabel):
    145150    def __init__(self, model):
    146151        EntryWithLabel.__init__(self, _('Personal Unblocking Key (PUK):'))
    class ModemConfiguration(SectionView): 
    160165        self._model = model
    161166        self.restart_alerts = alerts
    162167
    163         self.set_border_width(style.DEFAULT_SPACING)
    164168        self.set_spacing(style.DEFAULT_SPACING)
    165         self._group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
     169
     170        label_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
     171        combo_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
     172
     173        scrolled_win = gtk.ScrolledWindow()
     174        scrolled_win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
     175        scrolled_win.show()
     176        self.add(scrolled_win)
     177
     178        main_box = gtk.VBox(spacing=style.DEFAULT_SPACING)
     179        main_box.set_border_width(style.DEFAULT_SPACING)
     180        main_box.show()
     181        scrolled_win.add_with_viewport(main_box)
    166182
    167183        explanation = _("You will need to provide the following " \
    168184                            "information to set up a mobile " \
    169185                            "broadband connection to a cellular "\
    170186                            "(3G) network.")
    171187        self._text = gtk.Label(explanation)
    172         self._text.set_width_chars(100)
    173188        self._text.set_line_wrap(True)
    174189        self._text.set_alignment(0, 0)
    175         self.pack_start(self._text, False)
     190        main_box.pack_start(self._text, False)
    176191        self._text.show()
    177192
     193        if model.has_providers_db():
     194            self._upper_box = gtk.VBox(spacing=style.DEFAULT_SPACING)
     195            self._upper_box.set_border_width(style.DEFAULT_SPACING)
     196            main_box.pack_start(self._upper_box, expand=False)
     197            self._upper_box.show()
     198
     199
     200            box = gtk.HBox(spacing=style.DEFAULT_SPACING * 2)
     201            label = gtk.Label(_('Country:'))
     202            label.set_alignment(1, 0.5)
     203            label_group.add_widget(label)
     204            box.pack_start(label, False)
     205            label.show()
     206            country_store = model.CountryListStore()
     207            country_combo = gtk.ComboBox(country_store)
     208            combo_group.add_widget(country_combo)
     209            cell = gtk.CellRendererText()
     210            cell.props.xalign = 0.5
     211            country_combo.pack_start(cell)
     212            country_combo.add_attribute(cell, 'text', 0)
     213            country_combo.connect('changed', self.__country_selected_cb)
     214            box.pack_start(country_combo, False)
     215            country_combo.show()
     216            self._upper_box.pack_start(box, False)
     217            box.show()
     218
     219            box = gtk.HBox(spacing=style.DEFAULT_SPACING * 2)
     220            label = gtk.Label(_('Provider:'))
     221            label.set_alignment(1, 0.5)
     222            label_group.add_widget(label)
     223            box.pack_start(label, False)
     224            label.show()
     225            self._providers_combo = gtk.ComboBox()
     226            combo_group.add_widget(self._providers_combo)
     227            cell = gtk.CellRendererText()
     228            cell.props.xalign = 0.5
     229            self._providers_combo.pack_start(cell)
     230            self._providers_combo.add_attribute(cell, 'text', 0)
     231            self._providers_combo.connect('changed',
     232                                          self.__provider_selected_cb)
     233            box.pack_start(self._providers_combo, False)
     234            self._providers_combo.show()
     235            self._upper_box.pack_start(box, False)
     236            box.show()
     237
     238            box = gtk.HBox(spacing=style.DEFAULT_SPACING*2)
     239            label = gtk.Label(_('Plan:'))
     240            label.set_alignment(1, 0.5)
     241            label_group.add_widget(label)
     242            box.pack_start(label, False)
     243            label.show()
     244            self._plan_combo = gtk.ComboBox()
     245            combo_group.add_widget(self._plan_combo)
     246            cell = gtk.CellRendererText()
     247            cell.props.xalign = 0.5
     248            self._plan_combo.pack_start(cell)
     249            self._plan_combo.add_attribute(cell, 'text', 0)
     250            self._plan_combo.connect('changed', self.__plan_selected_cb)
     251            box.pack_start(self._plan_combo, False)
     252            self._plan_combo.show()
     253            self._upper_box.pack_start(box, False)
     254            box.show()
     255
     256            country_combo.set_active(country_store.guess_country_row())
     257
     258            separator = gtk.HSeparator()
     259            main_box.pack_start(separator, False)
     260            separator.show()
     261
     262        self._lower_box = gtk.VBox(spacing=style.DEFAULT_SPACING)
     263        self._lower_box.set_border_width(style.DEFAULT_SPACING)
     264        main_box.pack_start(self._lower_box, expand=False)
     265        self._lower_box.show()
     266
    178267        self._username_entry = UsernameEntry(model)
    179268        self._username_entry.connect('notify::is-valid',
    180269                                     self.__notify_is_valid_cb)
    181         self._group.add_widget(self._username_entry.label)
    182         self.pack_start(self._username_entry, expand=False)
     270        label_group.add_widget(self._username_entry.label)
     271        combo_group.add_widget(self._username_entry.entry)
     272        self._lower_box.pack_start(self._username_entry, fill=False)
    183273        self._username_entry.show()
    184274
    185275        self._password_entry = PasswordEntry(model)
    186276        self._password_entry.connect('notify::is-valid',
    187277                                     self.__notify_is_valid_cb)
    188         self._group.add_widget(self._password_entry.label)
    189         self.pack_start(self._password_entry, expand=False)
     278        label_group.add_widget(self._password_entry.label)
     279        combo_group.add_widget(self._password_entry.entry)
     280        self._lower_box.pack_start(self._password_entry, fill=False)
    190281        self._password_entry.show()
    191282
    192283        self._number_entry = NumberEntry(model)
    193284        self._number_entry.connect('notify::is-valid',
    194285                                   self.__notify_is_valid_cb)
    195         self._group.add_widget(self._number_entry.label)
    196         self.pack_start(self._number_entry, expand=False)
     286        label_group.add_widget(self._number_entry.label)
     287        combo_group.add_widget(self._number_entry.entry)
     288        self._lower_box.pack_start(self._number_entry, fill=False)
    197289        self._number_entry.show()
    198290
    199291        self._apn_entry = ApnEntry(model)
    200292        self._apn_entry.connect('notify::is-valid',
    201293                                self.__notify_is_valid_cb)
    202         self._group.add_widget(self._apn_entry.label)
    203         self.pack_start(self._apn_entry, expand=False)
     294        label_group.add_widget(self._apn_entry.label)
     295        combo_group.add_widget(self._apn_entry.entry)
     296        self._lower_box.pack_start(self._apn_entry, fill=False)
    204297        self._apn_entry.show()
    205298
    206299        self._pin_entry = PinEntry(model)
    207300        self._pin_entry.connect('notify::is-valid',
    208301                                self.__notify_is_valid_cb)
    209         self._group.add_widget(self._pin_entry.label)
    210         self.pack_start(self._pin_entry, expand=False)
     302        label_group.add_widget(self._pin_entry.label)
     303        self._lower_box.pack_start(self._pin_entry, fill=False)
    211304        self._pin_entry.show()
    212305       
    213306        self._puk_entry = PukEntry(model)
    214307        self._puk_entry.connect('notify::is-valid',
    215308                                self.__notify_is_valid_cb)
    216         self._group.add_widget(self._puk_entry.label)
    217         self.pack_start(self._puk_entry, expand=False)       
     309        label_group.add_widget(self._puk_entry.label)
     310        combo_group.add_widget(self._puk_entry.entry)
     311        self._lower_box.pack_start(self._puk_entry, fill=False)
    218312        self._puk_entry.show()
    219313
    220314        self.setup()
    class ModemConfiguration(SectionView): 
    232326    def undo(self):
    233327        self._model.undo()
    234328
     329    def __country_selected_cb(self, combo):
     330        model = combo.get_model()
     331        providers = model.get_row_providers(combo.get_active())
     332        self._providers_combo.set_model(
     333            self._model.ProviderListStore(providers))
     334
     335    def __provider_selected_cb(self, combo):
     336        model = combo.get_model()
     337        plans = model.get_row_plans(combo.get_active())
     338        self._plan_combo.set_model(self._model.PlanListStore(plans))
     339
     340    def __plan_selected_cb(self, combo):
     341        model = combo.get_model()
     342        plan = model.get_row_plan(combo.get_active())
     343        self._username_entry.set_value(plan['username'])
     344        self._username_entry.set_text_from_model()
     345        self._password_entry.set_value(plan['password'])
     346        self._password_entry.set_text_from_model()
     347        self._number_entry.set_value(plan['number'])
     348        self._number_entry.set_text_from_model()
     349        self._apn_entry.set_value(plan['apn'])
     350        self._apn_entry.set_text_from_model()
     351
    235352    def _validate(self):
    236353        if self._username_entry.is_valid and \
    237             self._password_entry.is_valid and \
     354                self._password_entry.is_valid and \
    238355                self._number_entry.is_valid and \
    239                     self._apn_entry.is_valid and \
    240                         self._pin_entry.is_valid and \
    241                             self._puk_entry.is_valid:
    242                                 self.props.is_valid = True
     356                self._apn_entry.is_valid and \
     357                self._pin_entry.is_valid and \
     358                self._puk_entry.is_valid:
     359            self.props.is_valid = True
    243360        else:
    244361            self.props.is_valid = False
    245362
    class ModemConfiguration(SectionView): 
    247364        if entry.is_valid:
    248365            self.needs_restart = True
    249366        self._validate()
    250