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