Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSantiago Collazo <scollazo@activitycentral.com>2012-10-29 19:35:22 (GMT)
committer Santiago Collazo <scollazo@activitycentral.com>2012-10-29 19:35:22 (GMT)
commit295d9a217c605f21d9d4107b2e9c2d5d36513819 (patch)
tree430bec110ab45a7bc628bd9b2656e532ab62ed98
parent764047797d69a844b3f9b31c9687ecb78467b6b4 (diff)
parent2d204f6e449af15462bdbf24a1295b650061d8ac (diff)
Merge remote-tracking branch 'ajay/0.97.7-as-base' into devel
-rwxr-xr-xbin/sugar-session29
-rw-r--r--extensions/cpsection/datetime/view.py2
-rw-r--r--extensions/cpsection/network/view.py558
-rw-r--r--src/jarabe/desktop/homewindow.py11
-rw-r--r--src/jarabe/view/palettes.py18
5 files changed, 601 insertions, 17 deletions
diff --git a/bin/sugar-session b/bin/sugar-session
index 05493f2..0977b1f 100755
--- a/bin/sugar-session
+++ b/bin/sugar-session
@@ -289,6 +289,35 @@ def setup_accessibility_cb():
accessibility_manager = accessibility.AccessibilityManager()
accessibility_manager.setup_accessibility()
+def export_proxy_settings():
+ """
+ Export manual proxy settings from GConf as environment variables
+
+ 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
+ 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 = client.get_list('/system/http_proxy/ignore_hosts',
+ gconf.VALUE_STRING)
+ os.environ['no_proxy'] = ','.join(ignore_hosts)
+
def main():
try:
diff --git a/extensions/cpsection/datetime/view.py b/extensions/cpsection/datetime/view.py
index 4ad94ca..7f1e3b6 100644
--- a/extensions/cpsection/datetime/view.py
+++ b/extensions/cpsection/datetime/view.py
@@ -184,7 +184,7 @@ class TimeZone(SectionView):
self._treeview.set_search_equal_func(self._search, None)
self._treeview.set_search_column(0)
self._timezone_box = Gtk.VBox()
- self._scrolled_window.add(self._timezone_box)
+ self._scrolled_window.add_with_viewport(self._timezone_box)
self._timezone_box.show_all()
self._timezone_box.add(self._treeview)
self._treeview.show()
diff --git a/extensions/cpsection/network/view.py b/extensions/cpsection/network/view.py
index e4332e4..9b34337 100644
--- a/extensions/cpsection/network/view.py
+++ b/extensions/cpsection/network/view.py
@@ -16,10 +16,15 @@
from gi.repository import Gtk
from gi.repository import Gdk
-from gi.repository import GObject
from gi.repository import GConf
+from gi.repository import GObject
from gettext import gettext as _
+import os
+import subprocess
+import pango
+import logging
+
from sugar3.graphics import style
from jarabe.controlpanel.sectionview import SectionView
@@ -33,7 +38,399 @@ TITLE = _('Network')
_APPLY_TIMEOUT = 3000
EXPLICIT_REBOOT_MESSAGE = _('Please restart your computer for changes to take effect.')
-gconf_client = GConf.Client.get_default()
+client = GConf.Client.get_default()
+
+
+class GConfMixin(object):
+ """Mix-in class for GTK widgets backed by GConf"""
+ def __init__(self, gconf_key, widget=None, signal='changed'):
+ self._timeout_id = None
+ self._gconf_key = gconf_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
+ widget.connect(signal, self.__changed_cb)
+
+ 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 __changed_cb(self, widget):
+ if self._timeout_id is not None:
+ GObject.source_remove(self._timeout_id)
+ self._timeout_id = GObject.timeout_add(_APPLY_TIMEOUT, self._commit,
+ widget)
+
+ 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)
+
+ widget.handler_block_by_func(self.__changed_cb)
+ try:
+ self._set_gconf_value(new_value)
+ finally:
+ widget.handler_unblock_by_func(self.__changed_cb)
+
+ def _set_gconf_value(self, new_value):
+ gconf_type = client.get(self._gconf_key).type
+ if gconf_type == GConf.ValueType.STRING:
+ client.set_string(self._gconf_key, new_value)
+ elif gconf_type == GConf.ValueType.INT:
+ client.set_int(self._gconf_key, new_value)
+ elif gconf_type == GConf.ValueType.FLOAT:
+ client.set_float(self._gconf_key, new_value)
+ elif gconf_type == GConf.ValueType.BOOL:
+ client.set_bool(self._gconf_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 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()
+ 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):
+ Gtk.Entry.__init__(self)
+ GConfMixin.__init__(self, gconf_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, adjustment, climb_rate=0):
+ Gtk.SpinButton.__init__(self, adjustment=adjustment, climb_rate=climb_rate)
+ GConfMixin.__init__(self, gconf_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, separator=','):
+ self._separator = separator
+ GConfEntry.__init__(self, gconf_key)
+
+ def get_value_for_gconf(self):
+ entries = self.props.text.split(self._separator)
+ return [entry for entry in entries if entry]
+
+ 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, size_group=None):
+ SettingBox.__init__(self, name, size_group=size_group)
+ self.string_entry = GConfEntry(gconf_key)
+ self.string_entry.show()
+ self.pack_start(self.string_entry, True, True, 0)
+
+ def undo(self):
+ """Revert to original value if modified"""
+ self.string_entry.undo()
+
+ @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, size_group=None):
+ GConfStringSettingBox.__init__(self, name, gconf_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, size_group=None):
+ SettingBox.__init__(self, name, size_group=size_group)
+ self.hosts_entry = GConfStringListEntry(gconf_key)
+ self.hosts_entry.show()
+ self.pack_start(self.hosts_entry, True, True, 0)
+
+ def undo(self):
+ """Revert to original value if modified"""
+ self.hosts_entry.undo()
+
+ @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, size_group=None):
+ SettingBox.__init__(self, name, size_group=size_group)
+ self.host_name_entry = GConfEntry(host_key)
+ self.host_name_entry.show()
+ self.pack_start(self.host_name_entry, True, True, 0)
+
+ # port number 0 means n/a
+ adjustment = Gtk.Adjustment(0, 0, 65535, 1, 10)
+ self.port_spin_button = GConfIntegerSpinButton(port_key, adjustment,
+ climb_rate=0.1)
+ self.port_spin_button.show()
+ self.pack_start(self.port_spin_button, False, False, 0)
+
+ def undo(self):
+ """Revert to original values if modified"""
+ self.host_name_entry.undo()
+ self.port_spin_button.undo()
+
+ @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.ELLIPSIZE_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, option_sets, size_group=None):
+ """Initialize a GConfExclusiveOptionSetsBox instance
+
+ Arguments:
+
+ top_name -- text label used for the top-level selection
+ top_gconf_key -- key for the GConf entry to use for the
+ top-level selection
+ option_sets -- list of tuples containing text label, matching
+ GConf value as well as the GTK widget to display
+ for each of the option sets
+ size_group -- optional gtk.SizeGroup to use for the top-level label
+ """
+ display_sets = [(name, widget) for name, value, widget in option_sets]
+ self._top_mapping = dict([(name, value)
+ for name, value, widget in option_sets])
+ ExclusiveOptionSetsBox.__init__(self, top_name, display_sets,
+ size_group=size_group)
+ GConfMixin.__init__(self, top_gconf_key, self._top_combo_box)
+
+ def get_value_for_gconf(self):
+ giter = self._top_combo_box.get_active_iter()
+ if giter is None:
+ return None
+ 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 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, 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, 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):
@@ -48,6 +445,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)
@@ -183,7 +584,13 @@ class Network(SectionView):
workspace.pack_start(box_mesh, False, True, 0)
box_mesh.show()
- if gconf_client.get_bool('/desktop/sugar/extensions/network/show_nm_connection_editor') is True:
+ proxy_separator = Gtk.HSeparator()
+ workspace.pack_start(proxy_separator, False, False, 0)
+ proxy_separator.show()
+
+ self._add_proxy_section(workspace)
+
+ if client.get_bool('/desktop/sugar/extensions/network/show_nm_connection_editor') is True:
box_nm_connection_editor = self.add_nm_connection_editor_launcher(workspace)
self.setup()
@@ -231,6 +638,109 @@ class Network(SectionView):
workspace.pack_start(box_nm_connection_editor, False, True, 0)
box_nm_connection_editor.show_all()
+
+ 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',
+ 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',
+ 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', size_group)
+ user_name_box.show()
+ self._undo_objects.append(user_name_box)
+
+ password_box = GConfPasswordSettingBox(_('Password:'),
+ '/system/http_proxy/authentication_password', size_group)
+ password_box.show()
+ self._undo_objects.append(password_box)
+
+ auth_box = GConfOptionalSettingsBox(_('Use authentication'),
+ '/system/http_proxy/use_authentication',
+ [user_name_box, password_box])
+ auth_box.show()
+ manual_proxy_box.pack_start(auth_box, True, True, 0)
+ self._undo_objects.append(auth_box)
+
+ https_box = GConfHostPortSettingBox(_('HTTPS Proxy:'),
+ '/system/proxy/secure_host',
+ '/system/proxy/secure_port',
+ size_group)
+ https_box.show()
+ manual_proxy_box.pack_start(https_box, True, True, 0)
+ self._undo_objects.append(https_box)
+
+ ftp_box = GConfHostPortSettingBox(_('FTP Proxy:'),
+ '/system/proxy/ftp_host',
+ '/system/proxy/ftp_port',
+ size_group)
+ ftp_box.show()
+ manual_proxy_box.pack_start(ftp_box, True, True, 0)
+ self._undo_objects.append(ftp_box)
+
+ socks_box = GConfHostPortSettingBox(_('SOCKS Proxy:'),
+ '/system/proxy/socks_host',
+ '/system/proxy/socks_port',
+ size_group)
+ socks_box.show()
+ manual_proxy_box.pack_start(socks_box, 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 = GConfExclusiveOptionSetsBox(_('Method:'),
+ '/system/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', 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())
try:
@@ -258,6 +768,29 @@ class Network(SectionView):
self._model.undo()
self._jabber_alert.hide()
self._radio_alert.hide()
+ for setting in self._undo_objects:
+ setting.undo()
+
+ # pylint: disable=E0202
+ @property
+ def needs_restart(self):
+ # Some parts of Sugar as well as many non-Gnome applications
+ # use environment variables rather than gconf for proxy
+ # settings, so we need to restart for the changes to take
+ # _full_ effect.
+ for setting in self._undo_objects:
+ if setting.changed:
+ return True
+
+ return False
+
+ # pylint: disable=E0102,E1101
+ @needs_restart.setter
+ def needs_restart(self, value):
+ # needs_restart is a property (i.e. gets calculated) in this Control
+ # Panel, but SectionView.__init__() wants to initialise it to False,
+ # so we need to provide a (fake) setter.
+ pass
def _validate(self):
if self._jabber_valid and self._radio_valid:
@@ -302,6 +835,9 @@ class Network(SectionView):
self._jabber_valid = True
self._jabber_alert.hide()
+ for setting in self._undo_objects:
+ setting.undo()
+
self._validate()
return False
@@ -315,3 +851,19 @@ class Network(SectionView):
def __launch_button_clicked_cb(self, launch_button):
self._model.launch_nm_connection_editor()
+
+def _gconf_value_to_python(gconf_value):
+ if gconf_value.type == GConf.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/desktop/homewindow.py b/src/jarabe/desktop/homewindow.py
index 51873e9..fbb47d3 100644
--- a/src/jarabe/desktop/homewindow.py
+++ b/src/jarabe/desktop/homewindow.py
@@ -118,20 +118,23 @@ class HomeWindow(Gtk.Window):
systembus.add_signal_receiver(self.__relogin_cb, 'Relogin',
_DBUS_SYSTEM_IFACE)
- def _system_alert(self, replaces_id, app_icon, message):
+ def _system_alert(self, replaces_id, app_icon, summary, message):
service = notifications.get_service()
service.notification_received.send(self,app_name='system',
replaces_id=replaces_id, app_icon=app_icon,
- summary=_('System alert'), body=message,
+ summary=summary, body=message,
actions=[], hints={})
def __reboot_cb(self):
self._system_alert(_SYSTEM_REBOOT_ID, 'system-restart',
- _('Please, reboot your computer to take into account ' \
- 'new updates'))
+ _('Please restart your computer'),
+ _('System updates have been installed. Restarting ' \
+ 'your computer will ensure that they are ' \
+ 'applied correctly.'))
def __relogin_cb(self):
self._system_alert(_SYSTEM_RELOGIN_ID, 'system-logout',
+ _('Please restart Sugar'),
_('Please, restart Sugar to take into account ' \
'new updates'))
diff --git a/src/jarabe/view/palettes.py b/src/jarabe/view/palettes.py
index bbbf822..d8d8187 100644
--- a/src/jarabe/view/palettes.py
+++ b/src/jarabe/view/palettes.py
@@ -301,7 +301,7 @@ class RemoteSharePalette(Palette):
if show_unmount_option == True:
menu_item = PaletteMenuItem(pgettext('Share', 'Unmount'))
- icon = Icon(icon_name='media-eject', icon_size=gtk.ICON_SIZE_MENU)
+ icon = Icon(icon_name='media-eject', icon_size=Gtk.IconSize.MENU)
menu_item.set_image(icon)
icon.show()
@@ -333,30 +333,30 @@ class JournalVolumePalette(VolumePalette):
def __init__(self, mount):
VolumePalette.__init__(self, mount)
- journal_separator = gtk.SeparatorMenuItem()
+ journal_separator = PaletteMenuItemSeparator()
journal_separator.show()
- self.menu.prepend(journal_separator)
+ self.content_box.pack_start(journal_separator, True, True, 0)
- icon = Icon(icon_name='transfer-from', icon_size=gtk.ICON_SIZE_MENU)
+ icon = Icon(icon_name='transfer-from', icon_size=Gtk.IconSize.MENU)
icon.show()
- menu_item_journal_restore = MenuItem(_('Restore Journal'))
+ menu_item_journal_restore = PaletteMenuItem(_('Restore Journal'))
menu_item_journal_restore.set_image(icon)
menu_item_journal_restore.connect('activate', self.__journal_restore_activate_cb, mount.get_root().get_path())
menu_item_journal_restore.show()
- self.menu.prepend(menu_item_journal_restore)
+ self.content_box.pack_start(menu_item_journal_restore, True, True, 0)
- icon = Icon(icon_name='transfer-to', icon_size=gtk.ICON_SIZE_MENU)
+ icon = Icon(icon_name='transfer-to', icon_size=Gtk.IconSize.MENU)
icon.show()
- menu_item_journal_backup = MenuItem(_('Backup Journal'))
+ menu_item_journal_backup = PaletteMenuItem(_('Backup Journal'))
menu_item_journal_backup.set_image(icon)
menu_item_journal_backup.connect('activate', self.__journal_backup_activate_cb, mount.get_root().get_path())
menu_item_journal_backup.show()
- self.menu.prepend(menu_item_journal_backup)
+ self.content_box.pack_start(menu_item_journal_backup, True, True, 0)
def __journal_backup_activate_cb(self, menu_item, mount_path):
dialog = VolumeBackupDialog(mount_path)