[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