[Sugar-devel] [sugar PATCH] "Proxy" feature. Wiki page: http://wiki.sugarlabs.org/go/Features/Proxy_Settings
Ajay Garg
ajay at activitycentral.com
Tue Feb 19 23:44:34 EST 2013
On Tue, Feb 19, 2013 at 4:00 PM, Simon Schampijer <simon at schampijer.de>wrote:
> Hi Ajay,
>
> there are some questions open from the last time this feature was
> submitted for review: http://lists.sugarlabs.org/**
> archive/sugar-devel/2012-**August/038917.html<http://lists.sugarlabs.org/archive/sugar-devel/2012-August/038917.html>
>
> "There are two differences to the GNOME 3 design. There is a check box in
> the 'Manual' option that says 'Use authentication'.
It is used to specify credentials for the proxy-server, in cased it needs
them.
Not specifying these credentials (when a proxy-server demands them), causes
"network connection" failures in "Browse".
So this IS a required section.
> And there is an
> option 'Ignored Hosts'.
This supposedly bypasses the proxy for the mentioned hosts (though I have
been unable to get "http://www.facebook.com" to get bypassed using the
proxy as specified in http://wiki.sugarlabs.org/go/Features/Proxy_Settings).
On second thoughts, this option might actually do more bad than good, as it
might at first defeat the purpose of having all relays being done through a
proxy.
More thoughts welcome regarding this point !!
> Can you give a bit of background on those, why
> you did add those, what issue we have on the XO or discovered does it
> solve?"
>
>
> On 02/17/2013 11:28 AM, Ajay Garg wrote:
>
>> This patch is to be applied on the master-branch.
>>
>> Some details of this patch ::
>>
>> a)
>> The proxy-settings are stored both in the "gconf" schema; and "dconf"
>> schema.
>>
>
> Can you elaborate why you have chosen to also store into dconf? At one
> point Sugar wants to switch to Gsettings. Would that help for that case?
>
> Regards,
> Simon
>
>
>
> b)
>> The package "gnome-vfs2" is a pre-requisite for this patch to work,
>> since the settings are (also) stored in the dconf schema.
>>
>> c)
>> Also, a slightly unrelated change is the persistence of the values in
>> the "Network" control-panel.
>>
>> Earlier, there was a timeout involved (of 3000 milliseconds), which
>> would trigger the saving of the values (for eg., "Collaboration Server"
>> field was persisted this way).
>>
>> Now, the values are persisted SYNCHRONOUSLY, when the "tick"
>> toolbar-button is clicked (of course, all the changes are undone, if the
>> user instead decides to "Cancel changes").
>>
>> d)
>> All the use-cases of the proxy, are working, as per the wiki page
>> http://wiki.sugarlabs.org/go/**Features/Proxy_Settings<http://wiki.sugarlabs.org/go/Features/Proxy_Settings>
>>
>> Signed-off-by: Ajay Garg <ajay at activitycentral.com>
>> ---
>> extensions/cpsection/network/**view.py | 695
>> ++++++++++++++++++++++++++++++**+--
>> src/jarabe/controlpanel/gui.py | 2 +
>> src/jarabe/controlpanel/**sectionview.py | 8 +
>> src/jarabe/main.py | 36 ++
>> 4 files changed, 707 insertions(+), 34 deletions(-)
>>
>> diff --git a/extensions/cpsection/**network/view.py
>> b/extensions/cpsection/**network/view.py
>> index b360759..99b792b 100644
>> --- a/extensions/cpsection/**network/view.py
>> +++ b/extensions/cpsection/**network/view.py
>> @@ -16,10 +16,19 @@
>>
>> from gi.repository import Gtk
>> from gi.repository import Gdk
>> +from gi.repository import GConf
>> from gi.repository import GObject
>> +from gi.repository import Gio
>> +from gi.repository import Pango
>> from gettext import gettext as _
>>
>> +import os
>> +import subprocess
>> +import logging
>> +
>> from sugar3.graphics import style
>> +from sugar3.graphics.alert import Alert
>> +from sugar3.graphics.icon import Icon
>>
>> from jarabe.controlpanel.**sectionview import SectionView
>> from jarabe.controlpanel.**inlinealert import InlineAlert
>> @@ -31,6 +40,471 @@ TITLE = _('Network')
>>
>> _APPLY_TIMEOUT = 3000
>>
>> +# Please refer ::
>> +# http://developer.gnome.org/**ProxyConfiguration/<http://developer.gnome.org/ProxyConfiguration/>
>> +
>> +GSETTINGS_PROXY = Gio.Settings.new('org.gnome.**system.proxy')
>> +GSETTINGS_PROXY_FTP = Gio.Settings.new('org.gnome.**system.proxy.ftp')
>> +GSETTINGS_PROXY_HTTP = Gio.Settings.new('org.gnome.**
>> system.proxy.http')
>> +GSETTINGS_PROXY_HTTPS = Gio.Settings.new('org.gnome.**
>> system.proxy.https')
>> +GSETTINGS_PROXY_SOCKS = Gio.Settings.new('org.gnome.**
>> system.proxy.socks')
>> +
>> +
>> +client = GConf.Client.get_default()
>> +
>> +
>> +class GConfMixin(object):
>> + """Mix-in class for GTK widgets backed by GConf"""
>> + def __init__(self, gconf_key, gsettings_dconf, dconf_key,
>> widget=None, signal='changed'):
>> + self._gconf_key = gconf_key
>> + self._gsettings_dconf = gsettings_dconf
>> + self._dconf_key = dconf_key
>> + self._notify_id = client.notify_add(gconf_key,
>> self.__gconf_notify_cb, None)
>> + initial_value = self._get_gconf_value()
>> + self._undo_value = initial_value
>> + self.set_value_from_gconf(**initial_value)
>> + widget = widget or self
>> +
>> + def undo(self):
>> + """Revert to original value if modified"""
>> + if not self.changed:
>> + return
>> + logging.debug('Reverting %r to %r', self._gconf_key,
>> self._undo_value)
>> + self._set_gconf_value(self._**undo_value)
>> +
>> + 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()
>> +
>> + def set_value_from_gconf(self, value):
>> + """
>> + Set the current value of the widget based on a value from GConf
>> + MUST be implemented by subclasses.
>> + """
>> + raise NotImplementedError()
>> +
>> + 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)
>> +
>> + def _commit(self, widget):
>> + new_value = self.get_value_for_gconf()
>> + logging.debug('Setting %r to %r', self._gconf_key, new_value)
>> +
>> + self._set_gconf_value(new_**value)
>> +
>> + def _set_gconf_value(self, new_value):
>> + gconf_type = client.get(self._gconf_key).**type
>> + if gconf_type == GConf.ValueType.STRING:
>> + client.set_string(self._gconf_**key, new_value)
>> + self._gsettings_dconf.set_**string(self._dconf_key,
>> new_value)
>> + elif gconf_type == GConf.ValueType.INT:
>> + client.set_int(self._gconf_**key, new_value)
>> + self._gsettings_dconf.set_int(**self._dconf_key, new_value)
>> + elif gconf_type == GConf.ValueType.FLOAT:
>> + client.set_float(self._gconf_**key, new_value)
>> + self._gsettings_dconf.set_**double(self._dconf_key,
>> new_value)
>> + elif gconf_type == GConf.ValueType.BOOL:
>> + client.set_bool(self._gconf_**key, new_value)
>> + self._gsettings_dconf.set_**boolean(self._dconf_key,
>> new_value)
>> + elif gconf_type == GConf.ValueType.LIST:
>> + import traceback
>> + list_type = client.get(self._gconf_key).**get_list_type()
>> +
>> + # Persisting the value of a "LIST" via shell, unless and
>> + # until http://bugs.sugarlabs.org/**ticket/3926<http://bugs.sugarlabs.org/ticket/3926>gets solved.
>> + commit_list = []
>> + for value in new_value:
>> + translated_value = value.translate(None, "' ")
>> + commit_list.append(translated_**value)
>> +
>> + environment = os.environ.copy()
>> + try:
>> + process = subprocess.Popen(['gconftool-2 '
>> + '--type list '
>> + '--list-type string '
>> + '--set %s \'%s\'' %
>> (self._gconf_key,
>> +
>> commit_list)],
>> + stdout=subprocess.PIPE,
>> + env=environment,
>> + shell=True)
>> + process.wait()
>> +
>> + self._gsettings_dconf.set_**strv(self._dconf_key,
>> new_value)
>> + except Exception, e:
>> + logging.exception(e)
>> + #client.set_list(self._gconf_**key, list_type, new_value)
>> + else:
>> + raise TypeError('Cannot store %r in GConf' % (new_value, ))
>> +
>> + def _get_gconf_value(self):
>> + return _gconf_value_to_python(client.**get(self._gconf_key))
>> +
>> + def changed(self):
>> + return self._undo_value != self.get_value_for_gconf()
>> +
>> +
>> +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.
>> + """
>> +
>> + def __init__(self, gconf_key, gsettings_dconf, dconf_key):
>> + Gtk.Entry.__init__(self)
>> + GConfMixin.__init__(self, gconf_key, gsettings_dconf, dconf_key)
>> +
>> + def get_value_for_gconf(self):
>> + return self.props.text
>> +
>> + def set_value_from_gconf(self, value):
>> + self.props.text = value
>> +
>> +
>> +class GConfIntegerSpinButton(Gtk.**SpinButton, GConfMixin):
>> + """Integer SpinButton backed by GConf
>> + It is the callers responsibility to call GConfClient.add_dir() for
>> the
>> + GConf directory containing the key.
>> + """
>> +
>> + def __init__(self, gconf_key, gsettings_dconf, dconf_key,
>> adjustment, climb_rate=0):
>> + Gtk.SpinButton.__init__(self, adjustment=adjustment,
>> climb_rate=climb_rate)
>> + GConfMixin.__init__(self, gconf_key, gsettings_dconf, dconf_key)
>> +
>> + def get_value_for_gconf(self):
>> + return self.get_value_as_int()
>> +
>> + def set_value_from_gconf(self, value):
>> + self.set_value(value)
>> +
>> +
>> +class GConfStringListEntry(**GConfEntry):
>> + """Text entry backed by a GConf list of strings"""
>> +
>> + def __init__(self, gconf_key, gsettings_dconf, dconf_key,
>> separator=','):
>> + self._separator = separator
>> + GConfEntry.__init__(self, gconf_key, gsettings_dconf, dconf_key)
>> +
>> + def get_value_for_gconf(self):
>> + entries = self.props.text.split(self._**separator)
>> + return [entry for entry in entries if entry]
>> +
>> + def set_value_from_gconf(self, value):
>> + self.props.text = self._separator.join(value)
>> +
>> +
>> +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.**StateType.NORMAL,
>> + style.COLOR_SELECTION_GREY.**
>> get_gdk_color())
>> + self.label.set_alignment(1, 0.5)
>> + self.label.show()
>> + self.pack_start(self.label, False, False, 0)
>> +
>> + if size_group is not None:
>> + size_group.add_widget(self.**label)
>> +
>> +
>> +class GConfStringSettingBox(**SettingBox):
>> + """A configuration line for a GConf string setting"""
>> +
>> + def __init__(self, name, gconf_key, gsettings_dconf, dconf_key,
>> size_group=None):
>> + SettingBox.__init__(self, name, size_group=size_group)
>> + self.string_entry = GConfEntry(gconf_key, gsettings_dconf,
>> dconf_key)
>> + self.string_entry.show()
>> + self.pack_start(self.string_**entry, True, True, 0)
>> +
>> + def undo(self):
>> + """Revert to original value if modified"""
>> + self.string_entry.undo()
>> +
>> + def _commit(self, widget):
>> + self.string_entry._commit(**self.string_entry)
>> +
>> + @property
>> + def changed(self):
>> + return self.string_entry.changed
>> +
>> +
>> +class GConfPasswordSettingBox(**GConfStringSettingBox):
>> + """A configuration line for a GConf password setting"""
>> +
>> + def __init__(self, name, gconf_key, gsettings_dconf, dconf_key,
>> size_group=None):
>> + GConfStringSettingBox.__init__**(self, name, gconf_key,
>> + gsettings_dconf, dconf_key,
>> size_group)
>> + self.string_entry.set_**visibility(False)
>> +
>> +
>> +class GConfHostListSettingBox(**GConfStringSettingBox):
>> + """A configuration line for a host list GConf setting"""
>> +
>> + def __init__(self, name, gconf_key, gsettings_dconf, dconf_key,
>> size_group=None):
>> + SettingBox.__init__(self, name, size_group=size_group)
>> + self.hosts_entry = GConfStringListEntry(gconf_**key,
>> + gsettings_dconf,
>> dconf_key)
>> + self.hosts_entry.show()
>> + self.pack_start(self.hosts_**entry, True, True, 0)
>> +
>> + def undo(self):
>> + """Revert to original value if modified"""
>> + self.hosts_entry.undo()
>> +
>> + def _commit(self, widget):
>> + self.hosts_entry._commit(self.**hosts_entry)
>> +
>> + @property
>> + def changed(self):
>> + return self.hosts_entry.changed
>> +
>> +class GConfHostPortSettingBox(**SettingBox):
>> + """A configuration line for a combined host name and port GConf
>> setting"""
>> +
>> + def __init__(self, name, host_key, port_key, gsettings_dconf,
>> + dconf_host_key, dconf_port_key, size_group=None):
>> + SettingBox.__init__(self, name, size_group=size_group)
>> + self.host_name_entry = GConfEntry(host_key, gsettings_dconf,
>> + dconf_host_key)
>> + self.host_name_entry.show()
>> + self.pack_start(self.host_**name_entry, True, True, 0)
>> +
>> + # port number 0 means n/a
>> + adjustment = Gtk.Adjustment(0, 0, 65535, 1, 10)
>> + self.port_spin_button = GConfIntegerSpinButton(port_**key,
>> + gsettings_dconf,
>> + dconf_port_key,
>> + adjustment,
>> + climb_rate=0.1)
>> + self.port_spin_button.show()
>> + self.pack_start(self.port_**spin_button, False, False, 0)
>> +
>> + def undo(self):
>> + """Revert to original values if modified"""
>> + self.host_name_entry.undo()
>> + self.port_spin_button.undo()
>> +
>> + def _commit(self, widget):
>> + self.host_name_entry._commit(**self.host_name_entry)
>> + self.port_spin_button._commit(**self.port_spin_button)
>> +
>> + @property
>> + def changed(self):
>> + return self.host_name_entry.changed or
>> self.port_spin_button.changed
>> +
>> +
>> +class ExclusiveOptionSetsBox(Gtk.**VBox):
>> + """
>> + Container for sets of different settings selected by a top-level
>> setting
>> + Renders the top level setting as a ComboBox. Only the currently
>> + active set is shown on screen.
>> + """
>> + 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.**StateType.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, False, False, 0)
>> +
>> + 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.EllipsizeMode.MIDDLE
>> + cell_renderer.props.ellipsize_**set = True
>> + self._top_combo_box.pack_**start(cell_renderer, True)
>> + self._top_combo_box.add_**attribute(cell_renderer, 'text', 0)
>> + top_box.pack_start(self._top_**combo_box, True, True, 0)
>> + self.pack_start(top_box, False, False, 0)
>> +
>> + self._settings_box = Gtk.VBox()
>> + self._settings_box.show()
>> + self.pack_start(self._**settings_box, False, False, 0)
>> +
>> + 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 __init__(self, top_name, top_gconf_key, gsettings_dconf,
>> + dconf_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, gsettings_dconf,
>> + dconf_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
>> + 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, ))
>> +
>> +
>> +class SpecialGConfExclusiveOptionSet**sBox(**
>> GConfExclusiveOptionSetsBox):
>> + def __init__(self, top_name, top_gconf_key, gsettings_dconf,
>> + dconf_key, option_sets, size_group=None):
>> + GConfExclusiveOptionSetsBox.__**init__(self, top_name,
>> top_gconf_key,
>> + gsettings_dconf, dconf_key,
>> + option_sets, size_group)
>> + self._initial_enabled_value = True
>> + if self._undo_value == 'none':
>> + self._initial_enabled_value = False
>> +
>> + def undo(self):
>> + """Revert to original value if modified"""
>> + if not self.changed:
>> + return
>> + logging.debug('Reverting %r to %r', self._gconf_key,
>> self._undo_value)
>> + self._set_gconf_value(self._**undo_value)
>> +
>> + # Also, set the initial value for "org.gnome.system.proxy.http
>> enabled"
>> + logging.debug('Reverting org.gnome.system.proxy.http enabled to
>> %r', self._initial_enabled_value)
>> + GSETTINGS_PROXY_HTTP.set_**boolean('enabled',
>> self._initial_enabled_value)
>> +
>> + def _commit(self, widget):
>> + """Commit the base key."""
>> + super(**SpecialGConfExclusiveOptionSet**sBox,
>> self)._commit(None)
>> +
>> + """Plus commit the dconf key :: org.gnome.system.proxy.http
>> enabled"""
>> + # The logic to set the value is ::
>> + #
>> + # * If the mode is "none", the key is to be set to false.
>> + #
>> + # * If the mode is not "none" (in other words, it is "manual"
>> + # or "automatic"), the key is to be set to true.
>> + enabled_value = True
>> + mode = self.get_value_for_gconf()
>> + if mode == 'none':
>> + enabled_value = False
>> +
>> + logging.debug('Setting org.gnome.system.proxy.http enabled to
>> %r', enabled_value)
>> + GSETTINGS_PROXY_HTTP.set_**boolean('enabled', enabled_value)
>> +
>> + def changed(self):
>> + return self._undo_value != self.get_value_for_gconf()
>> +
>> +
>> +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 __init__(self, top_name, options):
>> + """Initialize an OptionalSettingsBox instance
>> + 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, True, True, 0)
>> + self._settings_box = Gtk.VBox(spacing=style.**DEFAULT_SPACING)
>> + for box in options:
>> + self._settings_box.pack_start(**box, True, True, 0)
>> +
>> + 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 __init__(self, top_name, top_gconf_key, gsettings_dconf,
>> + dconf_key, options):
>> + """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
>> + options -- list of GTK widgets to display for each of the
>> options
>> + """
>> + OptionalSettingsBox.__init__(**self, top_name, options)
>> + GConfMixin.__init__(self, top_gconf_key, gsettings_dconf,
>> + dconf_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)
>> + self.pack_start(self._**settings_box, False, False, 0)
>> +
>>
>> class Network(SectionView):
>> def __init__(self, model, alerts):
>> @@ -44,6 +518,10 @@ class Network(SectionView):
>> self._jabber_change_handler = None
>> self._radio_change_handler = None
>> self._network_configuration_**reset_handler = None
>> + self._undo_objects = []
>> +
>> + client.add_dir('/system/http_**proxy', GConf.ClientPreloadType.*
>> *PRELOAD_ONELEVEL)
>> + client.add_dir('/system/proxy'**, GConf.ClientPreloadType.**
>> PRELOAD_ONELEVEL)
>>
>> self.set_border_width(style.**DEFAULT_SPACING * 2)
>> self.set_spacing(style.**DEFAULT_SPACING)
>> @@ -174,10 +652,141 @@ class Network(SectionView):
>> workspace.pack_start(box_mesh, False, True, 0)
>> box_mesh.show()
>>
>> + proxy_separator = Gtk.HSeparator()
>> + workspace.pack_start(proxy_**separator, False, False, 0)
>> + proxy_separator.show()
>> +
>> + self._add_proxy_section(**workspace)
>> +
>> 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, False, False, 0)
>> +
>> + 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, True, True, 0)
>> +
>> + size_group = Gtk.SizeGroup(Gtk.**SizeGroupMode.HORIZONTAL)
>> +
>> + automatic_proxy_box = Gtk.VBox()
>> + automatic_proxy_box.set_**spacing(style.DEFAULT_SPACING)
>> +
>> + url_box = GConfStringSettingBox(_('**Configuration URL:'),
>> + '/system/proxy/autoconfig_url'**
>> ,
>> + GSETTINGS_PROXY,
>> + 'autoconfig-url',
>> + size_group)
>> + url_box.show()
>> + automatic_proxy_box.pack_**start(url_box, True, True, 0)
>> + 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 = Gtk.Label(wpad_help_text)
>> + automatic_proxy_help.set_**alignment(0, 0)
>> + automatic_proxy_help.set_line_**wrap(True)
>> + automatic_proxy_help.show()
>> + automatic_proxy_box.pack_**start(automatic_proxy_help, True,
>> True, 0)
>> +
>> + 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',
>> + GSETTINGS_PROXY_HTTP,
>> + 'host',
>> + 'port',
>> + size_group)
>> + http_box.show()
>> + manual_proxy_box.pack_start(**http_box, True, True, 0)
>> + self._undo_objects.append(**http_box)
>> +
>> + user_name_box = GConfStringSettingBox(_('**Username:'),
>> + '/system/http_proxy/**authentication_user',
>> + GSETTINGS_PROXY_HTTP, 'authentication-user', size_group)
>> + user_name_box.show()
>> + self._undo_objects.append(**user_name_box)
>> +
>> + password_box = GConfPasswordSettingBox(_('**Password:'),
>> + '/system/http_proxy/**authentication_password',
>> + GSETTINGS_PROXY_HTTP, 'authentication-password', size_group)
>> + password_box.show()
>> + self._undo_objects.append(**password_box)
>> +
>> + auth_box = GConfOptionalSettingsBox(_('**Use authentication'),
>> + '/system/http_proxy/use_**authentication',
>> + GSETTINGS_PROXY_HTTP,
>> + 'use-authentication',
>> + [user_name_box, password_box])
>> + auth_box.show()
>> + manual_proxy_box.pack_start(**auth_box, True, True, 0)
>> + self._undo_objects.append(**auth_box)
>> +
>> + https_box = GConfHostPortSettingBox(_('**HTTPS Proxy:'),
>> + '/system/proxy/secure_host',
>> + '/system/proxy/secure_port',
>> + GSETTINGS_PROXY_HTTPS,
>> + 'host',
>> + 'port',
>> + size_group)
>> + https_box.show()
>> + manual_proxy_box.pack_start(**https_box, True, True, 0)
>> + self._undo_objects.append(**https_box)
>> +
>> + ftp_box = GConfHostPortSettingBox(_('FTP Proxy:'),
>> + '/system/proxy/ftp_host',
>> + '/system/proxy/ftp_port',
>> + GSETTINGS_PROXY_FTP,
>> + 'host',
>> + 'port',
>> + size_group)
>> + ftp_box.show()
>> + manual_proxy_box.pack_start(**ftp_box, True, True, 0)
>> + self._undo_objects.append(ftp_**box)
>> +
>> + socks_box = GConfHostPortSettingBox(_('**SOCKS Proxy:'),
>> + '/system/proxy/socks_host',
>> + '/system/proxy/socks_port',
>> + GSETTINGS_PROXY_SOCKS,
>> + 'host',
>> + 'port',
>> + size_group)
>> + socks_box.show()
>> + manual_proxy_box.pack_start(**socks_box, True, True, 0)
>> + 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 = SpecialGConfExclusiveOptionSet**
>> sBox(_('Method:'),
>> +
>> '/system/proxy/mode',
>> + GSETTINGS_PROXY,
>> + 'mode',
>> + option_sets,
>> size_group)
>> + option_sets_box.show()
>> + proxy_box.pack_start(option_**sets_box, False, False, 0)
>> + self._undo_objects.append(**option_sets_box)
>> +
>> + no_proxy_box = GConfHostListSettingBox(_('**Ignored Hosts'),
>> + '/system/http_proxy/ignore_**hosts', GSETTINGS_PROXY,
>> + 'ignore-hosts', size_group)
>> + no_proxy_box.show()
>> + proxy_box.pack_start(no_proxy_**box, False, False, 0)
>> + self._undo_objects.append(no_**proxy_box)
>> +
>> +
>> def setup(self):
>> - self._entry.set_text(self._**model.get_jabber())
>> + self._old_jabber_entry = self._model.get_jabber()
>> + self._entry.set_text(self._**old_jabber_entry)
>> try:
>> radio_state = self._model.get_radio()
>> except self._model.ReadError, detail:
>> @@ -191,24 +800,42 @@ class Network(SectionView):
>> self.needs_restart = False
>> self._radio_change_handler = self._button.connect( \
>> 'toggled', self.__radio_toggled_cb)
>> - self._jabber_change_handler = self._entry.connect( \
>> - 'changed', self.__jabber_changed_cb)
>> self._network_configuration_**reset_handler = \
>> self._clear_history_button.**connect( \
>> 'clicked', self.__network_configuration_**
>> reset_cb)
>>
>> def undo(self):
>> self._button.disconnect(self._**radio_change_handler)
>> - self._entry.disconnect(self._**jabber_change_handler)
>> self._model.undo()
>> self._jabber_alert.hide()
>> + self._entry.set_text(self._**old_jabber_entry)
>> 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.
>> + if self._entry.get_text() != self._old_jabber_entry:
>> + return True
>> +
>> + for setting in self._undo_objects:
>> + if setting.changed():
>> + return True
>>
>> - def _validate(self):
>> - if self._jabber_valid and self._radio_valid:
>> - self.props.is_valid = True
>> - else:
>> - self.props.is_valid = False
>> + 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 __radio_toggled_cb(self, widget, data=None):
>> radio_state = widget.get_active()
>> @@ -225,34 +852,34 @@ class Network(SectionView):
>> self._validate()
>> return False
>>
>> - def __jabber_changed_cb(self, widget, data=None):
>> - if self._jabber_sid:
>> - GObject.source_remove(self._**jabber_sid)
>> - self._jabber_sid = GObject.timeout_add(_APPLY_**TIMEOUT,
>> - self.__jabber_timeout_cb,
>> - widget)
>> -
>> - def __jabber_timeout_cb(self, widget):
>> - self._jabber_sid = 0
>> - if widget.get_text() == self._model.get_jabber:
>> - return
>> - try:
>> - self._model.set_jabber(widget.**get_text())
>> - except self._model.ReadError, detail:
>> - self._jabber_alert.props.msg = detail
>> - self._jabber_valid = False
>> - self._jabber_alert.show()
>> - self.restart_alerts.append('**jabber')
>> - else:
>> - self._jabber_valid = True
>> - self._jabber_alert.hide()
>> -
>> - self._validate()
>> - return False
>> -
>> def __network_configuration_reset_**cb(self, widget):
>> # FIXME: takes effect immediately, not after CP is closed with
>> # confirmation button
>> self._model.clear_networks()
>> if not self._model.have_networks():
>> self._clear_history_button.**set_sensitive(False)
>> +
>> + def perform_accept_actions(self):
>> + current_jabber_entry = self._entry.get_text()
>> + if current_jabber_entry != self._old_jabber_entry:
>> + self._model.set_jabber(**current_jabber_entry)
>> +
>> + for setting in self._undo_objects:
>> + setting._commit(setting)
>> +
>> +
>> +def _gconf_value_to_python(gconf_**value):
>> + if gconf_value.type == GConf.ValueType.STRING:
>> + return gconf_value.get_string()
>> + elif gconf_value.type == GConf.ValueType.INT:
>> + return gconf_value.get_int()
>> + elif gconf_value.type == GConf.ValueType.FLOAT:
>> + return gconf_value.get_float()
>> + elif gconf_value.type == GConf.ValueType.BOOL:
>> + return gconf_value.get_bool()
>> + elif gconf_value.type == GConf.ValueType.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, ))
>> diff --git a/src/jarabe/controlpanel/gui.**py
>> b/src/jarabe/controlpanel/gui.**py
>> index f28b248..7805bb2 100644
>> --- a/src/jarabe/controlpanel/gui.**py
>> +++ b/src/jarabe/controlpanel/gui.**py
>> @@ -302,12 +302,14 @@ class ControlPanel(Gtk.Window):
>> return options
>>
>> def __cancel_clicked_cb(self, widget):
>> + self._section_view.perform_**cancel_actions()
>> self._section_view.undo()
>> self._options[self._current_**option]['alerts'] = []
>> self._section_toolbar.accept_**button.set_sensitive(True)
>> self._show_main_view()
>>
>> def __accept_clicked_cb(self, widget):
>> + self._section_view.perform_**accept_actions()
>> if self._section_view.needs_**restart:
>> self._section_toolbar.accept_**button.set_sensitive(False)
>> self._section_toolbar.cancel_**button.set_sensitive(False)
>> diff --git a/src/jarabe/controlpanel/**sectionview.py
>> b/src/jarabe/controlpanel/**sectionview.py
>> index cbf4768..bee64e0 100644
>> --- a/src/jarabe/controlpanel/**sectionview.py
>> +++ b/src/jarabe/controlpanel/**sectionview.py
>> @@ -52,3 +52,11 @@ class SectionView(Gtk.VBox):
>> def undo(self):
>> """Undo here the changes that have been made in this section."""
>> pass
>> +
>> + def perform_cancel_actions(self):
>> + """Perform additional actions, when the "Cancel" button is
>> clicked."""
>> + pass
>> +
>> + def perform_accept_actions(self):
>> + """Perform additional actions, when the "Ok" button is
>> clicked."""
>> + pass
>> diff --git a/src/jarabe/main.py b/src/jarabe/main.py
>> index 44880ba..e4893a1 100755
>> --- a/src/jarabe/main.py
>> +++ b/src/jarabe/main.py
>> @@ -230,6 +230,41 @@ def setup_theme():
>> icons_path = os.path.join(config.data_path, 'icons')
>> Gtk.IconTheme.get_default().**append_search_path(icons_path)
>>
>> +def export_proxy_settings():
>> + """
>> + Export manual proxy settings from GConf as environment variables
>> +
>> + Some applications and tools and even some parts of Sugar will use
>> + the http_proxy environment variable if set, but don't use the Gnome
>> + (GConf) proxy settings.
>> + """
>> + client = GConf.Client.get_default()
>> +
>> + # Note: See https://dev.laptop.org.au/**issues/1179#note-9<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')
>> + if use_auth:
>> + user = client.get_string('/system/**http_proxy/authentication_**
>> user')
>> + 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 = []
>> + ignore_hosts_list = client.get('/system/http_**proxy/ignore_hosts')
>> +
>> + # Process, only if the "ignore_hosts_list" is non-empty.
>> + if ignore_hosts_list:
>> + for entry in ignore_hosts_list.get_list():
>> + ignore_hosts.append(entry.get_**string())
>> + os.environ['no_proxy'] = ','.join(ignore_hosts)
>> +
>> def _start_intro():
>> window = IntroWindow()
>> window.connect('done', __intro_window_done_cb)
>> @@ -246,6 +281,7 @@ def main():
>>
>> _start_window_manager()
>>
>> + export_proxy_settings()
>> setup_locale()
>> setup_fonts()
>> setup_theme()
>>
>>
> ______________________________**_________________
> Sugar-devel mailing list
> Sugar-devel at lists.sugarlabs.**org <Sugar-devel at lists.sugarlabs.org>
> http://lists.sugarlabs.org/**listinfo/sugar-devel<http://lists.sugarlabs.org/listinfo/sugar-devel>
>
--
Regards,
Ajay Garg
Dextrose Developer
Activity Central: http://activitycentral.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sugarlabs.org/archive/sugar-devel/attachments/20130220/c37ffc18/attachment-0001.html>
More information about the Sugar-devel
mailing list