Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/sugar-session19
-rw-r--r--extensions/cpsection/network/view.py821
2 files changed, 486 insertions, 354 deletions
diff --git a/bin/sugar-session b/bin/sugar-session
index 248810c..bf140f6 100755
--- a/bin/sugar-session
+++ b/bin/sugar-session
@@ -212,7 +212,6 @@ def setup_accessibility_cb():
accessibility_manager = accessibility.AccessibilityManager()
accessibility_manager.setup_accessibility()
-
def export_proxy_settings():
"""Export manual proxy settings from GConf as environment variables
@@ -221,19 +220,25 @@ def export_proxy_settings():
(GConf) proxy settings.
"""
client = gconf.client_get_default()
- if client.get_string('/system/proxy/mode') != 'auto':
+
+ # Note: See https://dev.laptop.org.au/issues/1179#note-9
+ if client.get_string('/system/proxy/mode') == 'none':
return
http_host = client.get_string('/system/http_proxy/host')
http_port = client.get_int('/system/http_proxy/port')
use_auth = client.get_bool('/system/http_proxy/use_authentication')
- proxy_info = '%s:%d' % (http_host, http_port)
if use_auth:
user = client.get_string('/system/http_proxy/authentication_user')
- pword = client.get_string('/system/http_proxy/authentication_password')
- proxy_info = '%s:%s@%s' % (user, pword, proxy_info)
-
- os.environ['http_proxy'] = 'http://%s/' % proxy_info
+ pw = client.get_string('/system/http_proxy/authentication_password')
+ http_proxy = 'http://%s:%s@%s:%d/' % (user, pw, http_host, http_port)
+ else:
+ http_proxy = 'http://%s:%d/' % (http_host, http_port)
+
+ os.environ['http_proxy'] = http_proxy
+ ignore_hosts = client.get_list('/system/http_proxy/ignore_hosts',
+ gconf.VALUE_STRING)
+ os.environ['no_proxy'] = ','.join(ignore_hosts)
def main():
diff --git a/extensions/cpsection/network/view.py b/extensions/cpsection/network/view.py
index a7d723f..5bfe01c 100644
--- a/extensions/cpsection/network/view.py
+++ b/extensions/cpsection/network/view.py
@@ -14,9 +14,14 @@
# 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 _
+import logging
+
+import gconf
+import gobject
+import gtk
+import pango
from sugar.graphics import style
from sugar.graphics.alert import Alert
@@ -54,397 +59,389 @@ class WrappedLabel(gtk.Label):
widget.set_size_request(rect.width, -1)
+class GConfMixin(object):
+ """Mix-in class for GTK widgets backed by GConf
-# "Proxy" feature merged into "Network"
-#################################################################################################################
+ It is the callers responsibility to call GConfClient.add_dir() for the
+ GConf directory containing the key.
+ """
-# Copyright (C) 2011, Aleksey Lim
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
+ def __init__(self, gconf_key, widget=None, signal='changed'):
+ self._timeout_id = None
+ self._gconf_key = gconf_key
+ client = gconf.client_get_default()
+ self._notify_id = client.notify_add(gconf_key, self.__gconf_notify_cb)
+ initial_value = self._get_gconf_value()
+ self._undo_value = initial_value
+ self.set_value_from_gconf(initial_value)
+ widget = widget or self
+ widget.connect(signal, self.__changed_cb)
-from gettext import gettext as _
-import re
+ def undo(self):
+ """Revert to original value if modified"""
+ if not self.changed:
+ return
-import gconf
+ logging.debug('Reverting %r to %r', self._gconf_key, self._undo_value)
+ self._set_gconf_value(self._undo_value)
-_widget_sensitivies = {}
-_gconf_origin_values = {}
+ def get_value_for_gconf(self):
+ """
+ Return the current value of the widget in a format suitable for GConf
+ MUST be implemented by subclasses.
+ """
+ raise NotImplementedError()
-class Proxy(SectionView):
+ def set_value_from_gconf(self, value):
+ """
+ Set the current value of the widget based on a value from GConf
- def __init__(self):
- SectionView.__init__(self)
- self.set_border_width(style.DEFAULT_SPACING * 2)
- self.set_spacing(style.DEFAULT_SPACING)
- self.setup()
-
- def setup(self):
- for i in self.get_children():
- self.remove(i)
- # Destroy all widgets and connection to avoid any interfering
- i.destroy()
+ MUST be implemented by subclasses.
+ """
+ raise NotImplementedError()
- _widget_sensitivies.clear()
+ def __changed_cb(self, widget):
+ if self._timeout_id is not None:
+ gobject.source_remove(self._timeout_id)
- workspace = gtk.VBox()
- workspace.show()
- self.add(workspace)
-
- def add_section(section, label_text):
- separator = gtk.HSeparator()
- separator.show()
- workspace.pack_start(separator, expand=False)
+ self._timeout_id = gobject.timeout_add(_APPLY_TIMEOUT, self._commit,
+ widget)
- label = gtk.Label(label_text)
- label.set_alignment(0, 0)
- label.show()
- workspace.pack_start(label, expand=False)
+ def __gconf_notify_cb(self, client, transaction_id_, entry, user_data_):
+ new_value = _gconf_value_to_python(entry.value)
+ self.set_value_from_gconf(new_value)
- section.set_border_width(style.DEFAULT_SPACING * 2)
- section.show()
- workspace.pack_start(section, expand=False)
+ def _commit(self, widget):
+ new_value = self.get_value_for_gconf()
+ logging.debug('Setting %r to %r', self._gconf_key, new_value)
- add_section(_ProxySection(),
- _('Configure proxies to access the internet'))
- add_section(_IgnoreSection(), _('Ignore host list'))
+ widget.handler_block_by_func(self.__changed_cb)
+ try:
+ self._set_gconf_value(new_value)
+ finally:
+ widget.handler_unblock_by_func(self.__changed_cb)
+
+ def _set_gconf_value(self, new_value):
+ client = gconf.client_get_default()
+ gconf_type = client.get(self._gconf_key).type
+ if gconf_type == gconf.VALUE_STRING:
+ client.set_string(self._gconf_key, new_value)
+ elif gconf_type == gconf.VALUE_INT:
+ client.set_int(self._gconf_key, new_value)
+ elif gconf_type == gconf.VALUE_FLOAT:
+ client.set_float(self._gconf_key, new_value)
+ elif gconf_type == gconf.VALUE_BOOL:
+ client.set_bool(self._gconf_key, new_value)
+ elif gconf_type == gconf.VALUE_LIST:
+ list_type = client.get(self._gconf_key).get_list_type()
+ client.set_list(self._gconf_key, list_type, new_value)
+ else:
+ raise TypeError('Cannot store %r in GConf' % (new_value, ))
- def undo(self):
- conf = gconf.client_get_default()
- for key, value in _gconf_origin_values.items():
- if value is None:
- conf.unset(key)
- else:
- conf.set(key, value)
+ def _get_gconf_value(self):
+ client = gconf.client_get_default()
+ return _gconf_value_to_python(client.get(self._gconf_key))
@property
- def needs_restart(self):
- conf = gconf.client_get_default()
- for key, value in _gconf_origin_values.items():
- if ((value is None and conf.get_without_default(key) is not None) or
- (value is not None and value.to_string() != conf.get(key).to_string())):
- return True
+ def changed(self):
+ return self._undo_value != self.get_value_for_gconf()
- return False
- @needs_restart.setter
- def needs_restart(self, value):
- # needs_restart is a property (i.e. gets calculated) in this Control
- # Panel, but SectionView.__init__() wants to initialise it to False,
- # so we need to provide a (fake) setter.
- pass
+class GConfEntry(gtk.Entry, GConfMixin):
+ """Text entry backed by GConf
+ It is the callers responsibility to call GConfClient.add_dir() for the
+ GConf directory containing the key.
+ """
-class _ProxySection(gtk.VBox):
+ def __init__(self, gconf_key):
+ gtk.Entry.__init__(self)
+ GConfMixin.__init__(self, gconf_key)
- def __init__(self):
- gtk.VBox.__init__(self)
- self._common_hosts = {}
- self._common_ports = {}
-
- group = gtk.RadioButton()
- group.props.label = _('Direct internet connection')
- group.show()
- self.pack_start(group, expand=False)
- _register_selector_key('/system/proxy/mode', group, 'none')
- _register_bool_key('/system/http_proxy/use_http_proxy', group, True)
-
- manual_proxy = gtk.RadioButton(group)
- manual_proxy.props.label = _('Manual proxy configuration')
- manual_proxy.show()
- self.pack_start(manual_proxy, expand=False)
- _register_selector_key('/system/proxy/mode', manual_proxy, 'manual')
-
- widgets = self._add_protos()
- manual_proxy.connect('toggled', _set_sensitive, False, widgets)
- _set_sensitive(manual_proxy, False, widgets)
-
- auto_proxy = gtk.RadioButton(group)
- auto_proxy.props.label = _('Automatic proxy configuration')
- auto_proxy.show()
- self.pack_start(auto_proxy, expand=False)
- _register_selector_key('/system/proxy/mode', auto_proxy, 'auto')
-
- grid = self._sub_section_new()
- grid.attach_label(_('Autoconfiguration URL (leave empty to use WPAD):'),
- 0, 1, 0, 1)
- entry = grid.attach_entry(1, 2, 0, 1)
- _register_string_key('/system/proxy/autoconfig_url', entry)
- auto_proxy.connect('toggled', _set_sensitive, False, [grid])
- _set_sensitive(auto_proxy, False, [grid])
-
- print 'aa toh raha hai'
-
- def _add_protos(self):
- commons = gtk.CheckButton()
- commons.props.label = _('Use the same proxy for all protocols')
- commons.show()
- self.pack_start(commons)
- _register_bool_key('/system/http_proxy/use_same_proxy', commons)
-
- grid = self._sub_section_new()
-
- def add_proto(row, is_common, label_text, host_key, port_key):
- host_label = grid.attach_label(label_text, 0, 1, row, row + 1)
- host = grid.attach_entry(1, 2, row, row + 1)
-
- port_label = grid.attach_label(_('Port:'), 2, 3, row, row + 1)
- port_value = gtk.Adjustment(8080, 0, 65536, 1, 10)
- port = gtk.SpinButton()
- port.configure(port_value, .1, 0)
- port.show()
- grid.attach(port, 3, 4, row, row + 1,
- gtk.SHRINK | gtk.FILL, gtk.SHRINK)
-
- if is_common:
- _widget_sensitivies.update([
- (host_label, None), (host, None),
- (port_label, None), (port, None)])
- self._common_hosts[host] = host.props.buffer
- self._common_ports[port] = port.props.adjustment
-
- _register_string_key(host_key, host)
- _register_int_key(port_key, port)
-
- return host, port
-
- http_host, http_port = add_proto(1, False, _('HTTP proxy:'),
- '/system/http_proxy/host', '/system/http_proxy/port')
-
- auth_widget = _AuthWidget()
- auth_widget.show()
- grid.attach(auth_widget, 1, 2, 2, 3, gtk.SHRINK | gtk.FILL, gtk.SHRINK)
-
- add_proto(3, True, _('Secure HTTP proxy:'),
- '/system/proxy/secure_host', '/system/proxy/secure_port')
- add_proto(4, True, _('FTP proxy:'),
- '/system/proxy/ftp_host', '/system/proxy/ftp_port')
- add_proto(5, True, _('Socks proxy:'),
- '/system/proxy/socks_host', '/system/proxy/socks_port')
-
- def commons_toggled_cb(sender):
- for widget in _widget_sensitivies.keys():
- _widget_sensitivies[widget] = not sender.props.active
- _set_sensitive(sender, True, _widget_sensitivies.keys())
-
- for widget, orig_buffer in self._common_hosts.items():
- widget.props.buffer = http_host.props.buffer if \
- sender.props.active else orig_buffer
-
- for widget, orig_adjustment in self._common_ports.items():
- widget.props.adjustment = http_port.props.adjustment if \
- sender.props.active else orig_adjustment
- widget.props.value = widget.props.adjustment.value
-
- commons.connect('toggled', commons_toggled_cb)
- commons_toggled_cb(commons)
-
- return [commons, grid]
-
- def _sub_section_new(self):
- grid = _Grid(1, 1, False)
- grid.props.column_spacing = style.DEFAULT_SPACING
- grid.props.row_spacing = style.DEFAULT_SPACING
- grid.show()
-
- alignment = gtk.Alignment(0, 0, 1, 1)
- alignment.props.left_padding = style.STANDARD_ICON_SIZE
- alignment.props.right_padding = style.GRID_CELL_SIZE
- alignment.add(grid)
- alignment.show()
- self.pack_start(alignment)
-
- return grid
-
-
-class _IgnoreSection(gtk.VBox):
+ def get_value_for_gconf(self):
+ return self.props.text
- def __init__(self):
- gtk.VBox.__init__(self)
+ def set_value_from_gconf(self, value):
+ self.props.text = value
- entry = gtk.Entry()
- entry.show()
- self.pack_start(entry, expand=False)
- _register_list_key('/system/http_proxy/ignore_hosts', entry)
+class GConfIntegerSpinButton(gtk.SpinButton, GConfMixin):
+ """Integer SpinButton backed by GConf
-class _AuthWidget(gtk.VBox):
+ It is the callers responsibility to call GConfClient.add_dir() for the
+ GConf directory containing the key.
+ """
- def __init__(self):
- gtk.VBox.__init__(self)
+ def __init__(self, gconf_key, adjustment, climb_rate=0):
+ gtk.SpinButton.__init__(self, adjustment, climb_rate=climb_rate)
+ GConfMixin.__init__(self, gconf_key)
- enable = gtk.CheckButton()
- enable.props.label = _('Use authentication')
- enable.show()
- self.pack_start(enable, expand=False)
- _register_bool_key('/system/http_proxy/use_authentication', enable)
+ def get_value_for_gconf(self):
+ return self.get_value_as_int()
- grid = _Grid(2, 2, False)
- grid.props.column_spacing = style.DEFAULT_SPACING
- grid.props.row_spacing = style.DEFAULT_SPACING
- self.pack_start(grid)
+ def set_value_from_gconf(self, value):
+ self.set_value(value)
- grid.attach_label(_('Username:'), 0, 1, 0, 1)
- entry = grid.attach_entry(1, 2, 0, 1)
- _register_string_key('/system/http_proxy/authentication_user', entry)
- grid.attach_label(_('Password:'), 0, 1, 1, 2)
- entry = grid.attach_entry(1, 2, 1, 2)
- entry.props.visibility = False
- _register_string_key(
- '/system/http_proxy/authentication_password', entry)
+class GConfStringListEntry(GConfEntry):
+ """Text entry backed by a GConf list of strings"""
- enable.connect('toggled', lambda sender:
- grid.show() if sender.props.active else grid.hide())
- if enable.props.active:
- grid.show()
+ def __init__(self, gconf_key, separator=','):
+ self._separator = separator
+ GConfEntry.__init__(self, gconf_key)
+ def get_value_for_gconf(self):
+ entries = self.props.text.split(self._separator)
+ return [entry for entry in entries if entry]
-class _Grid(gtk.Table):
+ def set_value_from_gconf(self, value):
+ self.props.text = self._separator.join(value)
- def attach_label(self, label, left_attach, right_attach,
- top_attach, bottom_attach):
- widget = gtk.Label(label)
- widget.set_alignment(0, 0)
- widget.set_line_wrap(True)
- self.attach(widget, left_attach, right_attach,
- top_attach, bottom_attach, gtk.SHRINK | gtk.FILL, gtk.SHRINK)
- widget.show()
- return widget
- def attach_entry(self, left_attach, right_attach,
- top_attach, bottom_attach):
- widget = gtk.Entry()
- self.attach(widget, left_attach, right_attach,
- top_attach, bottom_attach, gtk.EXPAND | gtk.FILL, gtk.SHRINK)
- widget.show()
- return widget
+class SettingBox(gtk.HBox):
+ """
+ Base class for "lines" on the screen representing configuration settings
+ """
+ def __init__(self, name, size_group=None):
+ gtk.HBox.__init__(self, spacing=style.DEFAULT_SPACING)
+ self.label = gtk.Label(name)
+ self.label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ self.label.set_alignment(1, 0.5)
+ self.label.show()
+ self.pack_start(self.label, expand=False)
-def _set_sensitive(sender, reverse, widgets):
- is_sensitive = sender.props.active
- if reverse:
- is_sensitive = not is_sensitive
+ if size_group is not None:
+ size_group.add_widget(self.label)
- for i in widgets:
- if isinstance(i, gtk.Container):
- _set_sensitive(sender, reverse, i.get_children())
- i.props.sensitive = is_sensitive and _widget_sensitivies.get(i, True)
+class GConfStringSettingBox(SettingBox):
+ """A configuration line for a GConf string setting"""
-def _register_bool_key(key, widget, reverse=False):
+ def __init__(self, name, gconf_key, size_group=None):
+ SettingBox.__init__(self, name, size_group=size_group)
+ self.string_entry = GConfEntry(gconf_key)
+ self.string_entry.show()
+ self.pack_start(self.string_entry, expand=True)
- def set_cb(widget, x, reverse):
- value = x.get_bool()
- if reverse:
- value = not value
- widget.props.active = value
+ def undo(self):
+ """Revert to original value if modified"""
+ self.string_entry.undo()
- def get_cb(widget, reverse):
- x = gconf.Value(gconf.VALUE_BOOL)
- value = widget.props.active
- if reverse:
- value = not value
- x.set_bool(value)
- return x
+ @property
+ def changed(self):
+ return self.string_entry.changed
- _register_key(key, widget, 'toggled', set_cb, get_cb, reverse)
+class GConfHostListSettingBox(GConfStringSettingBox):
+ """A configuration line for a host list GConf setting"""
-def _register_string_key(key, widget):
+ def __init__(self, name, gconf_key, size_group=None):
+ SettingBox.__init__(self, name, size_group=size_group)
+ self.hosts_entry = GConfStringListEntry(gconf_key)
+ self.hosts_entry.show()
+ self.pack_start(self.hosts_entry, expand=True)
- def set_cb(widget, x):
- widget.props.text = x.get_string()
+ def undo(self):
+ """Revert to original value if modified"""
+ self.hosts_entry.undo()
+
+ @property
+ def changed(self):
+ return self.hosts_entry.changed
- def get_cb(widget):
- x = gconf.Value(gconf.VALUE_STRING)
- x.set_string(widget.props.text)
- return x
- _register_key(key, widget, 'changed', set_cb, get_cb)
+class GConfHostPortSettingBox(SettingBox):
+ """A configuration line for a combined host name and port GConf setting"""
+ def __init__(self, name, host_key, port_key, size_group=None):
+ SettingBox.__init__(self, name, size_group=size_group)
+ self.host_name_entry = GConfEntry(host_key)
+ self.host_name_entry.show()
+ self.pack_start(self.host_name_entry, expand=True)
-def _register_int_key(key, widget):
+ # port number 0 means n/a
+ adjustment = gtk.Adjustment(0, 0, 65535, 1, 10)
+ self.port_spin_button = GConfIntegerSpinButton(port_key, adjustment,
+ climb_rate=0.1)
+ self.port_spin_button.show()
+ self.pack_start(self.port_spin_button, expand=False)
- def set_cb(widget, x):
- widget.props.value = x.get_int()
+ def undo(self):
+ """Revert to original values if modified"""
+ self.host_name_entry.undo()
+ self.port_spin_button.undo()
- def get_cb(widget):
- x = gconf.Value(gconf.VALUE_INT)
- x.set_int(int(widget.props.value))
- return x
+ @property
+ def changed(self):
+ return self.host_name_entry.changed or self.port_spin_button.changed
- _register_key(key, widget.props.adjustment, 'value_changed',
- set_cb, get_cb)
+class ExclusiveOptionSetsBox(gtk.VBox):
+ """
+ Container for sets of different settings selected by a top-level setting
-def _register_selector_key(key, widget, value):
+ Renders the top level setting as a ComboBox. Only the currently
+ active set is shown on screen.
+ """
- def set_cb(widget, x, value):
- widget.props.active = x.get_string() == value
+ def __init__(self, top_name, option_sets, size_group=None):
+ """Initialize an ExclusiveOptionSetsBox instance
+
+ Arguments:
+
+ top_name -- text label used for the top-level selection
+ option_sets -- list of tuples containing text label and GTK
+ widget to display for each of the option sets
+ size_group -- optional gtk.SizeGroup to use for the top-level label
+ """
+ gtk.VBox.__init__(self, spacing=style.DEFAULT_SPACING)
+ self.label_size_group = size_group
+ top_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
+ top_box.show()
+ top_label = gtk.Label(top_name)
+ top_label.modify_fg(gtk.STATE_NORMAL,
+ style.COLOR_SELECTION_GREY.get_gdk_color())
+ top_label.set_alignment(1, 0.5)
+ top_label.show()
+ self.label_size_group.add_widget(top_label)
+ top_box.pack_start(top_label, expand=False)
+
+ model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_OBJECT)
+ self._top_combo_box = gtk.ComboBox(model=model)
+ self._top_combo_box.connect('changed', self.__combo_changed_cb)
+ self._top_combo_box.show()
+
+ cell_renderer = gtk.CellRendererText()
+ cell_renderer.props.ellipsize = pango.ELLIPSIZE_MIDDLE
+ cell_renderer.props.ellipsize_set = True
+ self._top_combo_box.pack_start(cell_renderer)
+ self._top_combo_box.add_attribute(cell_renderer, 'text', 0)
+ top_box.pack_start(self._top_combo_box, expand=True)
+ self.pack_start(top_box, expand=False)
+
+ self._settings_box = gtk.VBox()
+ self._settings_box.show()
+ self.pack_start(self._settings_box, expand=False)
+
+ for name, box in option_sets:
+ model.append((name, box))
+
+ def __combo_changed_cb(self, combobox):
+ giter = combobox.get_active_iter()
+ new_box = combobox.get_model().get(giter, 1)[0]
+ current_box = self._settings_box.get_children()
+ if current_box:
+ self._settings_box.remove(current_box[0])
+
+ self._settings_box.add(new_box)
+ new_box.show()
+
+
+class GConfExclusiveOptionSetsBox(ExclusiveOptionSetsBox, GConfMixin):
+ """
+ Container for sets of GConf settings based on a top-level setting
+ """
- def get_cb(widget, value):
- if not widget.props.active:
+ def __init__(self, top_name, top_gconf_key, option_sets, size_group=None):
+ """Initialize a GConfExclusiveOptionSetsBox instance
+
+ Arguments:
+
+ top_name -- text label used for the top-level selection
+ top_gconf_key -- key for the GConf entry to use for the
+ top-level selection
+ option_sets -- list of tuples containing text label, matching
+ GConf value as well as the GTK widget to display
+ for each of the option sets
+ size_group -- optional gtk.SizeGroup to use for the top-level label
+ """
+ display_sets = [(name, widget) for name, value, widget in option_sets]
+ self._top_mapping = dict([(name, value)
+ for name, value, widget in option_sets])
+ ExclusiveOptionSetsBox.__init__(self, top_name, display_sets,
+ size_group=size_group)
+ GConfMixin.__init__(self, top_gconf_key, self._top_combo_box)
+
+ def get_value_for_gconf(self):
+ giter = self._top_combo_box.get_active_iter()
+ if giter is None:
return None
- x = gconf.Value(gconf.VALUE_STRING)
- x.set_string(value)
- return x
- _register_key(key, widget, 'toggled', set_cb, get_cb, value)
+ name = self._top_combo_box.get_model().get(giter, 0)[0]
+ return self._top_mapping[name]
+
+ def set_value_from_gconf(self, value):
+ for idx, (name, widget_) in enumerate(self._top_combo_box.get_model()):
+ if self._top_mapping[name] == value:
+ self._top_combo_box.set_active(idx)
+ return
+ raise ValueError('Invalid value %r' % (value, ))
-def _register_list_key(key, widget):
- def set_cb(widget, x):
- hosts = [i.get_string() for i in x.get_list()]
- widget.props.text = ', '.join(hosts)
+class OptionalSettingsBox(gtk.VBox):
+ """
+ Container for settings (de)activated by a top-level setting
+
+ Renders the top level setting as a CheckButton. The settings are only
+ shown on screen if the top-level setting is enabled.
+ """
- def get_cb(widget):
- hosts = []
- for i in re.split('[\s,;:]+', widget.props.text or ''):
- if not i.strip():
- continue
- value = gconf.Value(gconf.VALUE_STRING)
- value.set_string(i.strip())
- hosts.append(value)
- x = gconf.Value(gconf.VALUE_LIST)
- x.set_list_type(gconf.VALUE_STRING)
- x.set_list(hosts)
- return x
+ def __init__(self, top_name, options):
+ """Initialize an OptionalSettingsBox instance
- _register_key(key, widget, 'changed', set_cb, get_cb)
+ Arguments:
+ top_name -- text label used for the top-level selection
+ options -- list of GTK widgets to display for each of the options
+ """
+ gtk.VBox.__init__(self, spacing=style.DEFAULT_SPACING)
+ self._top_check_button = gtk.CheckButton()
+ self._top_check_button.props.label = top_name
+ self._top_check_button.connect('toggled', self.__button_changed_cb)
+ self._top_check_button.show()
+ self.pack_start(self._top_check_button, expand=True)
-def _register_key(key, widget, signal, set_cb, get_cb, *args):
- conf = gconf.client_get_default()
- value = conf.get(key)
- if value is not None:
- set_cb(widget, value, *args)
+ self._settings_box = gtk.VBox(spacing=style.DEFAULT_SPACING)
+ self.pack_start(self._settings_box, expand=False)
- _gconf_origin_values[key] = value
+ for box in options:
+ self._settings_box.pack_start(box)
+
+ def __button_changed_cb(self, check_button):
+ if check_button.get_active():
+ self._settings_box.show()
+ else:
+ self._settings_box.hide()
+
+
+class GConfOptionalSettingsBox(OptionalSettingsBox, GConfMixin):
+ """
+ Container for GConf settings (de)activated by a top-level setting
+ """
- def signal_cb(sender, key, widget, get_cb, *args):
- value = get_cb(widget, *args)
- if value is not None:
- conf = gconf.client_get_default()
- conf.set(key, value)
+ def __init__(self, top_name, top_gconf_key, options):
+ """Initialize a GConfExclusiveOptionSetsBox instance
- widget.connect(signal, signal_cb, key, widget, get_cb, *args)
-#################################################################################################################
-# "Proxy" code-merging finished !!
+ Arguments:
+ top_name -- text label used for the top-level selection
+ top_gconf_key -- key for the GConf entry to use for the
+ top-level selection
+ options -- list of GTK widgets to display for each of the options
+ """
+ OptionalSettingsBox.__init__(self, top_name, options)
+ GConfMixin.__init__(self, top_gconf_key, self._top_check_button,
+ signal='toggled')
+ def get_value_for_gconf(self):
+ return self._top_check_button.get_active()
+
+ def set_value_from_gconf(self, value):
+ self._top_check_button.set_active(value)
class AddRemoveWidget(gtk.HBox):
@@ -577,6 +574,11 @@ class Network(SectionView):
self._jabber_change_handler = None
self._radio_change_handler = None
self._network_configuration_reset_handler = None
+ self._undo_objects = []
+
+ client = gconf.client_get_default()
+ client.add_dir('/system/http_proxy', gconf.CLIENT_PRELOAD_ONELEVEL)
+ client.add_dir('/system/proxy', gconf.CLIENT_PRELOAD_ONELEVEL)
self.set_border_width(style.DEFAULT_SPACING * 2)
self.set_spacing(style.DEFAULT_SPACING)
@@ -703,6 +705,12 @@ class Network(SectionView):
workspace.pack_start(box_mesh, expand=False)
box_mesh.show()
+ proxy_separator = gtk.HSeparator()
+ workspace.pack_start(proxy_separator, False)
+ proxy_separator.show()
+
+ self._add_proxy_section(workspace)
+
if self._model.is_hidden_network_connect_package_available():
separator_hidden_network = gtk.HSeparator()
workspace.pack_start(separator_hidden_network, False)
@@ -752,30 +760,6 @@ class Network(SectionView):
box_hidden_network.show()
- separator_proxy = gtk.HSeparator()
- workspace.pack_start(separator_proxy, False)
- separator_proxy.show()
-
- label_proxy = gtk.Label(_('Proxy'))
- label_proxy.set_alignment(0, 0)
- workspace.pack_start(label_proxy, expand=False)
- label_proxy.show()
-
- box_proxy = gtk.VBox()
- box_proxy.set_border_width(style.DEFAULT_SPACING * 2)
- box_proxy.set_spacing(style.DEFAULT_SPACING)
- proxy_info = gtk.Label(_("<Enter suitable info>"))
- proxy_info.set_alignment(0, 0)
- proxy_info.set_line_wrap(True)
- box_proxy.pack_start(proxy_info, expand=False)
- proxy_info.show()
- workspace.pack_start(box_proxy, expand=False)
- box_proxy.show()
-
- proxy = Proxy()
- workspace.pack_start(proxy, expand=False)
- proxy.show()
-
separator_nm_connection_editor = gtk.HSeparator()
workspace.pack_start(separator_nm_connection_editor, False)
separator_nm_connection_editor.show()
@@ -817,6 +801,107 @@ class Network(SectionView):
self.setup()
+ def _add_proxy_section(self, workspace):
+ proxy_title = gtk.Label(_('Proxy'))
+ proxy_title.set_alignment(0, 0)
+ proxy_title.show()
+ workspace.pack_start(proxy_title, expand=False)
+
+ proxy_box = gtk.VBox()
+ proxy_box.set_border_width(style.DEFAULT_SPACING * 2)
+ proxy_box.set_spacing(style.DEFAULT_SPACING)
+ proxy_box.show()
+
+ workspace.pack_start(proxy_box)
+
+ size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+ automatic_proxy_box = gtk.VBox()
+ automatic_proxy_box.set_spacing(style.DEFAULT_SPACING)
+
+ url_box = GConfStringSettingBox(_('Configuration URL:'),
+ '/system/proxy/autoconfig_url',
+ size_group)
+ url_box.show()
+ automatic_proxy_box.pack_start(url_box)
+ self._undo_objects.append(url_box)
+
+ wpad_help_text = _('Web Proxy Autodiscovery (WPAD) is used when a'
+ ' Configuration URL is not provided. This is not'
+ ' recommended for untrusted public networks.')
+ automatic_proxy_help = WrappedLabel(wpad_help_text)
+ automatic_proxy_help.set_alignment(0, 0)
+ automatic_proxy_help.show()
+ automatic_proxy_box.pack_start(automatic_proxy_help)
+
+ manual_proxy_box = gtk.VBox()
+ manual_proxy_box.set_spacing(style.DEFAULT_SPACING)
+
+ http_box = GConfHostPortSettingBox(_('HTTP Proxy:'),
+ '/system/http_proxy/host',
+ '/system/http_proxy/port',
+ size_group)
+ http_box.show()
+ manual_proxy_box.pack_start(http_box)
+ self._undo_objects.append(http_box)
+
+ user_name_box = GConfStringSettingBox(_('Username:'),
+ '/system/http_proxy/authentication_user', size_group)
+ user_name_box.show()
+ self._undo_objects.append(user_name_box)
+
+ password_box = GConfStringSettingBox(_('Password:'),
+ '/system/http_proxy/authentication_password', size_group)
+ password_box.show()
+ self._undo_objects.append(password_box)
+
+ auth_box = GConfOptionalSettingsBox(_('Use authentication'),
+ '/system/http_proxy/use_authentication',
+ [user_name_box, password_box])
+ auth_box.show()
+ manual_proxy_box.pack_start(auth_box)
+ self._undo_objects.append(auth_box)
+
+ https_box = GConfHostPortSettingBox(_('HTTPS Proxy:'),
+ '/system/proxy/secure_host',
+ '/system/proxy/secure_port',
+ size_group)
+ https_box.show()
+ manual_proxy_box.pack_start(https_box)
+ self._undo_objects.append(https_box)
+
+ ftp_box = GConfHostPortSettingBox(_('FTP Proxy:'),
+ '/system/proxy/ftp_host',
+ '/system/proxy/ftp_port',
+ size_group)
+ ftp_box.show()
+ manual_proxy_box.pack_start(ftp_box)
+ self._undo_objects.append(ftp_box)
+
+ socks_box = GConfHostPortSettingBox(_('SOCKS Proxy:'),
+ '/system/proxy/socks_host',
+ '/system/proxy/socks_port',
+ size_group)
+ socks_box.show()
+ manual_proxy_box.pack_start(socks_box)
+ self._undo_objects.append(socks_box)
+
+ option_sets = [('None', 'none', gtk.VBox()),
+ ('Automatic', 'auto', automatic_proxy_box),
+ ('Manual', 'manual', manual_proxy_box)]
+ option_sets_box = GConfExclusiveOptionSetsBox(_('Method:'),
+ '/system/proxy/mode',
+ option_sets, size_group)
+ option_sets_box.show()
+ proxy_box.pack_start(option_sets_box, expand=False)
+ self._undo_objects.append(option_sets_box)
+
+ no_proxy_box = GConfHostListSettingBox(_('Ignored Hosts'),
+ '/system/http_proxy/ignore_hosts', size_group)
+ no_proxy_box.show()
+ proxy_box.pack_start(no_proxy_box, expand=False)
+ self._undo_objects.append(no_proxy_box)
+
def setup(self):
self._entry.set_text(self._model.get_jabber())
try:
@@ -829,7 +914,6 @@ class Network(SectionView):
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( \
@@ -853,6 +937,29 @@ class Network(SectionView):
self._model.undo()
self._jabber_alert.hide()
self._radio_alert.hide()
+ for setting in self._undo_objects:
+ setting.undo()
+
+ # pylint: disable=E0202
+ @property
+ def needs_restart(self):
+ # Some parts of Sugar as well as many non-Gnome applications
+ # use environment variables rather than gconf for proxy
+ # settings, so we need to restart for the changes to take
+ # _full_ effect.
+ for setting in self._undo_objects:
+ if setting.changed:
+ return True
+
+ return False
+
+ # pylint: disable=E0102,E1101
+ @needs_restart.setter
+ def needs_restart(self, value):
+ # needs_restart is a property (i.e. gets calculated) in this Control
+ # Panel, but SectionView.__init__() wants to initialise it to False,
+ # so we need to provide a (fake) setter.
+ pass
def _validate(self):
if self._jabber_valid and self._radio_valid:
@@ -897,6 +1004,9 @@ class Network(SectionView):
self._jabber_valid = True
self._jabber_alert.hide()
+ for setting in self._undo_objects:
+ setting.undo()
+
self._validate()
return False
@@ -913,3 +1023,20 @@ class Network(SectionView):
def __launch_button_clicked_cb(self, launch_button):
self._model.launch_nm_connection_editor()
+
+
+def _gconf_value_to_python(gconf_value):
+ if gconf_value.type == gconf.VALUE_STRING:
+ return gconf_value.get_string()
+ elif gconf_value.type == gconf.VALUE_INT:
+ return gconf_value.get_int()
+ elif gconf_value.type == gconf.VALUE_FLOAT:
+ return gconf_value.get_float()
+ elif gconf_value.type == gconf.VALUE_BOOL:
+ return gconf_value.get_bool()
+ elif gconf_value.type == gconf.VALUE_LIST:
+ return [_gconf_value_to_python(entry)
+ for entry in gconf_value.get_list()]
+ else:
+ raise TypeError("Don't know how to handle GConf value"
+ " type %r" % (gconf_value.type, ))