Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions')
-rw-r--r--extensions/cpsection/Makefile.am3
-rw-r--r--extensions/cpsection/modemconfiguration/Makefile.am6
-rw-r--r--extensions/cpsection/modemconfiguration/__init__.py22
-rw-r--r--extensions/cpsection/modemconfiguration/model.py53
-rw-r--r--extensions/cpsection/modemconfiguration/view.py192
-rw-r--r--extensions/deviceicon/network.py214
6 files changed, 476 insertions, 14 deletions
diff --git a/extensions/cpsection/Makefile.am b/extensions/cpsection/Makefile.am
index dd0a6b8..a92b5dd 100644
--- a/extensions/cpsection/Makefile.am
+++ b/extensions/cpsection/Makefile.am
@@ -1,4 +1,5 @@
-SUBDIRS = aboutme aboutcomputer datetime frame keyboard language network power updater
+SUBDIRS = aboutme aboutcomputer datetime frame keyboard language \
+ modemconfiguration network power updater
sugardir = $(pkgdatadir)/extensions/cpsection
sugar_PYTHON = __init__.py
diff --git a/extensions/cpsection/modemconfiguration/Makefile.am b/extensions/cpsection/modemconfiguration/Makefile.am
new file mode 100644
index 0000000..3e2613e
--- /dev/null
+++ b/extensions/cpsection/modemconfiguration/Makefile.am
@@ -0,0 +1,6 @@
+sugardir = $(pkgdatadir)/extensions/cpsection/modemconfiguration
+
+sugar_PYTHON = \
+ __init__.py \
+ model.py \
+ view.py
diff --git a/extensions/cpsection/modemconfiguration/__init__.py b/extensions/cpsection/modemconfiguration/__init__.py
new file mode 100644
index 0000000..8a219dc
--- /dev/null
+++ b/extensions/cpsection/modemconfiguration/__init__.py
@@ -0,0 +1,22 @@
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+#
+# 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
+
+from gettext import gettext as _
+
+CLASS = 'ModemConfiguration'
+ICON = 'module-modemconfiguration'
+TITLE = _('Modem Configuration')
+
diff --git a/extensions/cpsection/modemconfiguration/model.py b/extensions/cpsection/modemconfiguration/model.py
new file mode 100644
index 0000000..f96e88f
--- /dev/null
+++ b/extensions/cpsection/modemconfiguration/model.py
@@ -0,0 +1,53 @@
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+#
+# 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
+
+import gconf
+
+from jarabe.model.network import GSM_USERNAME_PATH, GSM_PASSWORD_PATH, \
+ GSM_NUMBER_PATH, GSM_APN_PATH
+
+def get_username():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_USERNAME_PATH) or ''
+
+def get_password():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_PASSWORD_PATH) or ''
+
+def get_number():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_NUMBER_PATH) or ''
+
+def get_apn():
+ client = gconf.client_get_default()
+ return client.get_string(GSM_APN_PATH) or ''
+
+def set_username(username):
+ client = gconf.client_get_default()
+ client.set_string(GSM_USERNAME_PATH, username)
+
+def set_password(password):
+ client = gconf.client_get_default()
+ client.set_string(GSM_PASSWORD_PATH, password)
+
+def set_number(number):
+ client = gconf.client_get_default()
+ client.set_string(GSM_NUMBER_PATH, number)
+
+def set_apn(apn):
+ client = gconf.client_get_default()
+ client.set_string(GSM_APN_PATH, apn)
+
diff --git a/extensions/cpsection/modemconfiguration/view.py b/extensions/cpsection/modemconfiguration/view.py
new file mode 100644
index 0000000..d66f1d5
--- /dev/null
+++ b/extensions/cpsection/modemconfiguration/view.py
@@ -0,0 +1,192 @@
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
+#
+# 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
+
+import os
+import logging
+from gettext import gettext as _
+
+import gtk
+import gobject
+
+from sugar.graphics import style
+
+from jarabe.controlpanel.sectionview import SectionView
+
+APPLY_TIMEOUT = 1000
+
+class EntryWithLabel(gtk.HBox):
+ __gtype_name__ = "SugarEntryWithLabel"
+
+ def __init__(self, label_text):
+ gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING)
+
+ self._timeout_sid = 0
+ self._changed_handler = None
+ self._is_valid = True
+
+ label = gtk.Label(label_text)
+ label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ self.pack_start(label, True, True)
+ 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()
+
+ def __entry_changed_cb(self, widget, data=None):
+ if self._timeout_sid:
+ gobject.source_remove(self._timeout_sid)
+ self._timeout_sid = gobject.timeout_add(APPLY_TIMEOUT,
+ self.__timeout_cb)
+
+ def __timeout_cb(self):
+ self._timeout_sid = 0
+
+ if self._entry.get_text() == self.get_value():
+ return False
+
+ try:
+ self.set_value(self._entry.get_text())
+ except ValueError:
+ self._is_valid = False
+ else:
+ self._is_valid = True
+
+ self.notify('is-valid')
+
+ return False
+
+ def set_text_from_model(self):
+ self._entry.set_text(self.get_value())
+
+ def get_value(self):
+ raise NotImplementedError
+
+ def set_value(self):
+ 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:'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_username()
+
+ def set_value(self, username):
+ return self._model.set_username(username)
+
+class PasswordEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('Password:'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_password()
+
+ def set_value(self, password):
+ return self._model.set_password(password)
+
+class NumberEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('Number:'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_number()
+
+ def set_value(self, number):
+ return self._model.set_number(number)
+
+class ApnEntry(EntryWithLabel):
+ def __init__(self, model):
+ EntryWithLabel.__init__(self, _('APN:'))
+ self._model = model
+
+ def get_value(self):
+ return self._model.get_apn()
+
+ def set_value(self, apn):
+ return self._model.set_apn(apn)
+
+class ModemConfiguration(SectionView):
+ def __init__(self, model, alerts=None):
+ SectionView.__init__(self)
+
+ self._model = model
+ self.restart_alerts = alerts
+
+ self.set_border_width(style.DEFAULT_SPACING)
+ self.set_spacing(style.DEFAULT_SPACING)
+
+ self._username_entry = UsernameEntry(model)
+ self._username_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self.pack_start(self._username_entry, expand=False)
+ self._username_entry.show()
+
+ self._password_entry = PasswordEntry(model)
+ self._password_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self.pack_start(self._password_entry, expand=False)
+ self._password_entry.show()
+
+ self._number_entry = NumberEntry(model)
+ self._number_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self.pack_start(self._number_entry, expand=False)
+ self._number_entry.show()
+
+ self._apn_entry = ApnEntry(model)
+ self._apn_entry.connect('notify::is-valid',
+ self.__notify_is_valid_cb)
+ self.pack_start(self._apn_entry, expand=False)
+ self._apn_entry.show()
+
+ self.setup()
+
+ def setup(self):
+ self._username_entry.set_text_from_model()
+ self._password_entry.set_text_from_model()
+ self._number_entry.set_text_from_model()
+ self._apn_entry.set_text_from_model()
+
+ self.needs_restart = False
+
+ def undo(self):
+ self._model.undo()
+
+ def _validate(self):
+ if self._username_entry.is_valid and \
+ self._password_entry.is_valid and \
+ self._number_entry.is_valid and \
+ self._apn_entry.is_valid:
+ self.props.is_valid = True
+ else:
+ self.props.is_valid = False
+
+ def __notify_is_valid_cb(self, entry, pspec):
+ if entry.is_valid:
+ self.needs_restart = True
+ self._validate()
+
diff --git a/extensions/deviceicon/network.py b/extensions/deviceicon/network.py
index e40e196..2ca6a88 100644
--- a/extensions/deviceicon/network.py
+++ b/extensions/deviceicon/network.py
@@ -1,6 +1,7 @@
#
# Copyright (C) 2008 One Laptop Per Child
# Copyright (C) 2009 Tomeu Vizoso, Simon Schampijer
+# Copyright (C) 2009 Paraguay Educa, Martin Abente
#
# 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
@@ -55,16 +56,10 @@ _NM_OLPC_MESH_IFACE = 'org.freedesktop.NetworkManager.Device.OlpcMesh'
_NM_ACCESSPOINT_IFACE = 'org.freedesktop.NetworkManager.AccessPoint'
_NM_ACTIVE_CONN_IFACE = 'org.freedesktop.NetworkManager.Connection.Active'
-_NM_DEVICE_STATE_UNKNOWN = 0
-_NM_DEVICE_STATE_UNMANAGED = 1
-_NM_DEVICE_STATE_UNAVAILABLE = 2
-_NM_DEVICE_STATE_DISCONNECTED = 3
-_NM_DEVICE_STATE_PREPARE = 4
-_NM_DEVICE_STATE_CONFIG = 5
-_NM_DEVICE_STATE_NEED_AUTH = 6
-_NM_DEVICE_STATE_IP_CONFIG = 7
-_NM_DEVICE_STATE_ACTIVATED = 8
-_NM_DEVICE_STATE_FAILED = 9
+_GSM_STATE_NOT_READY = 0
+_GSM_STATE_DISCONNECTED = 1
+_GSM_STATE_CONNECTING = 2
+_GSM_STATE_CONNECTED = 3
def frequency_to_channel(frequency):
ftoc = { 2412: 1, 2417: 2, 2422: 3, 2427: 4,
@@ -215,6 +210,65 @@ class WiredPalette(Palette):
ip_address_text = ""
self._ip_address_label.set_text(ip_address_text)
+class GsmPalette(Palette):
+ __gtype_name__ = 'SugarGsmPalette'
+
+ __gsignals__ = {
+ 'gsm-connect' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ 'gsm-disconnect' : (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ }
+
+ def __init__(self):
+ Palette.__init__(self, label=_('Wireless modem'))
+
+ self._current_state = None
+
+ self._toggle_state_item = gtk.MenuItem('')
+ self._toggle_state_item.connect('activate', self.__toggle_state_cb)
+ self.menu.append(self._toggle_state_item)
+ self._toggle_state_item.show()
+
+ self.set_state(_GSM_STATE_NOT_READY)
+
+ def set_state(self, state):
+ self._current_state = state
+ self._update_label_and_text()
+
+ def _update_label_and_text(self):
+ if self._current_state == _GSM_STATE_NOT_READY:
+ self._toggle_state_item.get_child().set_label('...')
+ self.props.secondary_text = _('Please wait...')
+
+ elif self._current_state == _GSM_STATE_DISCONNECTED:
+ self._toggle_state_item.get_child().set_label(_('Connect'))
+ self.props.secondary_text = _('Disconnected')
+
+ elif self._current_state == _GSM_STATE_CONNECTING:
+ self._toggle_state_item.get_child().set_label(_('Cancel'))
+ self.props.secondary_text = _('Connecting...')
+
+ elif self._current_state == _GSM_STATE_CONNECTED:
+ self._toggle_state_item.get_child().set_label(_('Disconnect'))
+ self.props.secondary_text = _('Connected')
+ else:
+ raise ValueError('Invalid GSM state while updating label and ' \
+ 'text, %s' % str(self._current_state))
+
+ def __toggle_state_cb(self, menuitem):
+ if self._current_state == _GSM_STATE_NOT_READY:
+ pass
+ elif self._current_state == _GSM_STATE_DISCONNECTED:
+ self.emit('gsm-connect')
+ elif self._current_state == _GSM_STATE_CONNECTING:
+ self.emit('gsm-disconnect')
+ elif self._current_state == _GSM_STATE_CONNECTED:
+ self.emit('gsm-disconnect')
+ else:
+ raise ValueError('Invalid GSM state while emitting signal, %s' % \
+ str(self._current_state))
+
class WirelessDeviceView(ToolButton):
@@ -451,11 +505,11 @@ class WirelessDeviceView(ToolButton):
connection_name = format % nick
connection_name += color_suffix
- connection = network.find_connection(connection_name)
+ connection = network.find_connection_by_ssid(connection_name)
if connection is None:
settings = Settings()
settings.connection.id = 'Auto ' + connection_name
- settings.connection.uuid = unique_id()
+ uuid = settings.connection.uuid = unique_id()
settings.connection.type = '802-11-wireless'
settings.wireless.ssid = dbus.ByteArray(connection_name)
settings.wireless.band = 'bg'
@@ -463,7 +517,7 @@ class WirelessDeviceView(ToolButton):
settings.ip4_config = IP4Config()
settings.ip4_config.method = 'link-local'
- connection = network.add_connection(connection_name, settings)
+ connection = network.add_connection(uuid, settings)
obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
netmgr = dbus.Interface(obj, _NM_IFACE)
@@ -623,6 +677,122 @@ class WiredDeviceView(TrayIcon):
self._palette.set_connected(speed, address)
+class GsmDeviceView(TrayIcon):
+
+ _ICON_NAME = 'gsm-device'
+ FRAME_POSITION_RELATIVE = 303
+
+ def __init__(self, device):
+ client = gconf.client_get_default()
+ color = xocolor.XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ TrayIcon.__init__(self, icon_name=self._ICON_NAME, xo_color=color)
+
+ self._bus = dbus.SystemBus()
+ self._device = device
+ self._palette = None
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+
+ self._bus.add_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
+ def create_palette(self):
+ palette = GsmPalette()
+
+ palette.set_group_id('frame')
+ palette.connect('gsm-connect', self.__gsm_connect_cb)
+ palette.connect('gsm-disconnect', self.__gsm_disconnect_cb)
+
+ self._palette = palette
+
+ props = dbus.Interface(self._device, 'org.freedesktop.DBus.Properties')
+ props.GetAll(_NM_DEVICE_IFACE, byte_arrays=True,
+ reply_handler=self.__current_state_check_cb,
+ error_handler=self.__current_state_check_error_cb)
+
+ return palette
+
+ def __gsm_connect_cb(self, palette, data=None):
+ connection = network.find_gsm_connection()
+ if connection is not None:
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+ netmgr.ActivateConnection(network.SETTINGS_SERVICE,
+ connection.path,
+ self._device.object_path,
+ '/',
+ reply_handler=self.__connect_cb,
+ error_handler=self.__connect_error_cb)
+
+ def __connect_cb(self, active_connection):
+ logging.debug('Connected successfully to gsm device, %s',
+ active_connection)
+
+ def __connect_error_cb(self, error):
+ raise RuntimeError('Error when connecting to gsm device, %s' % error)
+
+ def __gsm_disconnect_cb(self, palette, data=None):
+ obj = self._bus.get_object(_NM_SERVICE, _NM_PATH)
+ netmgr = dbus.Interface(obj, _NM_IFACE)
+ netmgr_props = dbus.Interface(netmgr, 'org.freedesktop.DBus.Properties')
+ active_connections_o = netmgr_props.Get(_NM_IFACE, 'ActiveConnections')
+
+ for conn_o in active_connections_o:
+ obj = self._bus.get_object(_NM_IFACE, conn_o)
+ props = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
+ devices = props.Get(_NM_ACTIVE_CONN_IFACE, 'Devices')
+ if self._device.object_path in devices:
+ netmgr.DeactivateConnection(
+ conn_o,
+ reply_handler=self.__disconnect_cb,
+ error_handler=self.__disconnect_error_cb)
+ break
+
+ def __disconnect_cb(self):
+ logging.debug('Disconnected successfully gsm device')
+
+ def __disconnect_error_cb(self, error):
+ raise RuntimeError('Error when disconnecting gsm device, %s' % error)
+
+ def __state_changed_cb(self, new_state, old_state, reason):
+ self._update_state(int(new_state))
+
+ def __current_state_check_cb(self, properties):
+ self._update_state(int(properties['State']))
+
+ def __current_state_check_error_cb(self, error):
+ raise RuntimeError('Error when checking gsm device state, %s' % error)
+
+ def _update_state(self, state):
+ gsm_state = None
+
+ if state is network.DEVICE_STATE_ACTIVATED:
+ gsm_state = _GSM_STATE_CONNECTED
+
+ elif state is network.DEVICE_STATE_DISCONNECTED:
+ gsm_state = _GSM_STATE_DISCONNECTED
+
+ elif state in [network.DEVICE_STATE_UNMANAGED,
+ network.DEVICE_STATE_UNAVAILABLE,
+ network.DEVICE_STATE_UNKNOWN]:
+ gsm_state = _GSM_STATE_NOT_READY
+
+ elif state in [network.DEVICE_STATE_PREPARE,
+ network.DEVICE_STATE_CONFIG,
+ network.DEVICE_STATE_IP_CONFIG]:
+ gsm_state = _GSM_STATE_CONNECTING
+
+ if self._palette is not None:
+ self._palette.set_state(gsm_state)
+
+ def disconnect(self):
+ self._bus.remove_signal_receiver(self.__state_changed_cb,
+ signal_name='StateChanged',
+ path=self._device.object_path,
+ dbus_interface=_NM_DEVICE_IFACE)
+
class WirelessDeviceObserver(object):
def __init__(self, device, tray, device_type):
self._device = device
@@ -633,6 +803,8 @@ class WirelessDeviceObserver(object):
self._device_view = WirelessDeviceView(self._device)
elif device_type == network.DEVICE_TYPE_802_11_OLPC_MESH:
self._device_view = OlpcMeshDeviceView(self._device)
+ else:
+ raise ValueError('Unimplemented device type %d' % device_type)
self._tray.add_device(self._device_view)
@@ -691,6 +863,19 @@ class WiredDeviceObserver(object):
del self._device_view
self._device_view = None
+class GsmDeviceObserver(object):
+ def __init__(self, device, tray):
+ self._device = device
+ self._device_view = None
+ self._tray = tray
+
+ self._device_view = GsmDeviceView(device)
+ self._tray.add_device(self._device_view)
+
+ def disconnect(self):
+ self._device_view.disconnect()
+ self._tray.remove_device(self._device_view)
+ self._device_view = None
class NetworkManagerObserver(object):
def __init__(self, tray):
@@ -735,6 +920,9 @@ class NetworkManagerObserver(object):
network.DEVICE_TYPE_802_11_OLPC_MESH]:
device = WirelessDeviceObserver(nm_device, self._tray, device_type)
self._devices[device_op] = device
+ elif device_type == network.DEVICE_TYPE_GSM_MODEM:
+ device = GsmDeviceObserver(nm_device, self._tray)
+ self._devices[device_op] = device
def __device_added_cb(self, device_op):
self._check_device(device_op)