diff options
-rwxr-xr-x | bin/sugar-session | 19 | ||||
-rw-r--r-- | extensions/cpsection/network/view.py | 821 |
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, )) |