[Dextrose] [PATCH] au#704: Allow the configuration of NTP Servers from DateTime CP.

Ajay Garg ajay at activitycentral.com
Mon Feb 20 12:39:29 EST 2012


This patch provides a mechanism to specify (multiple) NTP Server URLs, that are
written to "/etc/ntp/step-tickers".





Pre-requisites :
----------------

1. "/etc/ntp" must have 0777 permissions.
2. "/etc/ntp/step-tickers" must have 0777 permissions.





Notes ::
--------

1. The synchronization is done via "sudo service ntpdate start".

2. The ntpdate script "/etc/rc.d/init.d/ntpdate" first looks for NTP Server URLs
   in the file "/etc/ntp/step-tickers". 
   If it finds at least one entry, it tries them in sequence; AND NO OTHER
   SERVER URLS ARE TRIED FOR.

3. If there is no server URL in "/etc/ntp/step-tickers", the script tries for URLs
   in "/etc/ntp.conf".
   If it finds at least one entry, it tries them in sequence; AND NO OTHER
   SERVER URLS ARE TRIED FOR.

4. If there are no URLs in "/etc/ntp/step-tickers" and "/etc/ntp.conf", the command
   "sudo service ntpdate start" fails, and shows the error :

      "NTP server not specified in /etc/ntp/step-tickers or /etc/ntp.conf"


 extensions/cpsection/datetime/model.py |   47 ++++++++
 extensions/cpsection/datetime/view.py  |  188 +++++++++++++++++++++++++++++++-
 2 files changed, 231 insertions(+), 4 deletions(-)

diff --git a/extensions/cpsection/datetime/model.py b/extensions/cpsection/datetime/model.py
index 84e1259..486bd6f 100644
--- a/extensions/cpsection/datetime/model.py
+++ b/extensions/cpsection/datetime/model.py
@@ -21,10 +21,16 @@
 #
 
 import os
+import logging
+
 from gettext import gettext as _
 import gconf
 
 _zone_tab = '/usr/share/zoneinfo/zone.tab'
+NTPDATE_PATH = '/etc/rc.d/init.d/ntpdate'
+NTP_SERVER_CONFIG_FILENAME = '/etc/ntp/step-tickers'
+
+_logger = logging.getLogger('ControlPanel - TimeZone')
 
 
 def _initialize():
@@ -92,5 +98,46 @@ def set_timezone(timezone):
         raise ValueError(_('Error timezone does not exist.'))
     return 1
 
+
+def is_ntp_servers_config_feature_available():
+    return os.path.exists(NTPDATE_PATH)
+
+
+def get_ntp_servers():
+    servers = []
+
+    # If the file does not exist, return.
+    if not os.path.exists(NTP_SERVER_CONFIG_FILENAME):
+        return servers
+
+    f = open(NTP_SERVER_CONFIG_FILENAME, 'r')
+    for server in f.readlines():
+        servers.append(server.rstrip('\n'))
+    f.close()
+
+    return servers
+
+
+def set_ntp_servers(servers):
+
+    # First remove the old ssid-file, if it exists.
+    if os.path.exists(NTP_SERVER_CONFIG_FILENAME):
+        try:
+            os.remove(NTP_SERVER_CONFIG_FILENAME)
+        except:
+            _logger.exception('Error removing file.')
+            return
+
+    # Do nothing and return, if the values-list is empty
+    if len(servers) == 0:
+        return
+
+    # If we reach here, we have a non-empty ssid-values-list.
+    f = open(NTP_SERVER_CONFIG_FILENAME, 'w')
+    for server in servers:
+        if len(server) > 0:
+            f.write(server + '\n')
+    f.close()
+
 # inilialize the docstrings for the timezone
 _initialize()
diff --git a/extensions/cpsection/datetime/view.py b/extensions/cpsection/datetime/view.py
index 1cef78f..bbf8571 100644
--- a/extensions/cpsection/datetime/view.py
+++ b/extensions/cpsection/datetime/view.py
@@ -20,11 +20,130 @@ from gettext import gettext as _
 
 from sugar.graphics import style
 from sugar.graphics import iconentry
+from sugar.graphics.icon import Icon
 
 from jarabe.controlpanel.sectionview import SectionView
 from jarabe.controlpanel.inlinealert import InlineAlert
 
 
+class AddRemoveWidget(gtk.HBox):
+
+    def __init__(self, label, add_button_clicked_cb,
+                 remove_button_clicked_cb, index):
+        gtk.Box.__init__(self)
+        self.set_homogeneous(False)
+        self.set_spacing(10)
+
+        self._index = index
+        self._add_button_added = False
+        self._remove_button_added = False
+
+        self._entry_box = gtk.Entry()
+        self._entry_box.set_text(label)
+        self.pack_start(self._entry_box, expand=False)
+        self._entry_box.show()
+
+        add_icon = Icon(icon_name='list-add')
+        self._add_button = gtk.Button()
+        self._add_button.set_image(add_icon)
+        self._add_button.connect('clicked',
+                                 add_button_clicked_cb,
+                                 self)
+
+        remove_icon = Icon(icon_name='list-remove')
+        self._remove_button = gtk.Button()
+        self._remove_button.set_image(remove_icon)
+        self._remove_button.connect('clicked',
+                                    remove_button_clicked_cb,
+                                    self)
+
+        self.__add_add_button()
+        self.__add_remove_button()
+
+    def _get_index(self):
+        return self._index
+
+    def _set_index(self, value):
+        self._index = value
+
+    def _get_entry(self):
+        return self._entry_box.get_text()
+
+    def __add_add_button(self):
+        self.pack_start(self._add_button, expand=False)
+        self._add_button.show()
+        self._add_button_added = True
+
+    def _remove_remove_button_if_not_already(self):
+        if self._remove_button_added:
+            self.__remove_remove_button()
+
+    def __remove_remove_button(self):
+        self.remove(self._remove_button)
+        self._remove_button_added = False
+
+    def _add_remove_button_if_not_already(self):
+        if not self._remove_button_added:
+            self.__add_remove_button()
+
+    def __add_remove_button(self):
+        self.pack_start(self._remove_button, expand=False)
+        self._remove_button.show()
+        self._remove_button_added = True
+
+
+class MultiWidget(gtk.VBox):
+
+    def __init__(self):
+        gtk.VBox.__init__(self)
+
+    def _add_widget(self, label):
+        new_widget = AddRemoveWidget(label,
+                                     self.__add_button_clicked_cb,
+                                     self.__remove_button_clicked_cb,
+                                     len(self.get_children()))
+        self.add(new_widget)
+        new_widget.show()
+        self.show()
+        self._update_remove_button_statuses()
+
+    def __add_button_clicked_cb(self, add_button,
+                                      add_button_container):
+        self._add_widget('')
+        self._update_remove_button_statuses()
+
+    def __remove_button_clicked_cb(self, remove_button,
+                                   remove_button_container):
+        for child in self.get_children():
+            if child._get_index() > remove_button_container._get_index():
+                child._set_index(child._get_index() - 1)
+
+        self.remove(remove_button_container)
+        self._update_remove_button_statuses()
+
+    def _update_remove_button_statuses(self):
+        children = self.get_children()
+
+        # Now, if there is only one entry, remove-button
+        # should not be shown.
+        if len(children) == 1:
+            children[0]._remove_remove_button_if_not_already()
+
+        # Alternatively, if there are more than 1 entries,
+        # remove-button should be shown for all.
+        if len(children) > 1:
+            for child in children:
+                child._add_remove_button_if_not_already()
+
+
+    def _get_entries(self):
+        entries = []
+        for child in self.get_children():
+            entries.append(child._get_entry())
+
+        return entries
+
+
 class TimeZone(SectionView):
     def __init__(self, model, alerts):
         SectionView.__init__(self)
@@ -64,7 +183,11 @@ class TimeZone(SectionView):
         self._treeview.set_search_entry(self._entry)
         self._treeview.set_search_equal_func(self._search)
         self._treeview.set_search_column(0)
-        self._scrolled_window.add(self._treeview)
+
+        self._timezone_box = gtk.VBox()
+        self._scrolled_window.add_with_viewport(self._timezone_box)
+        self._timezone_box.show_all()
+        self._timezone_box.add(self._treeview)
         self._treeview.show()
 
         self._timezone_column = gtk.TreeViewColumn(_('Timezone'))
@@ -74,11 +197,15 @@ class TimeZone(SectionView):
         self._timezone_column.set_sort_column_id(0)
         self._treeview.append_column(self._timezone_column)
 
-        self.pack_start(self._scrolled_window)
-        self._scrolled_window.show()
+        self._container = gtk.VBox()
+        self._container.set_homogeneous(False)
+        self._container.pack_start(self._scrolled_window)
+        self._container.set_spacing(style.DEFAULT_SPACING)
+        self._container.show_all()
+        self.pack_start(self._container, expand=True)
 
         self._zone_alert_box = gtk.HBox(spacing=style.DEFAULT_SPACING)
-        self.pack_start(self._zone_alert_box, False)
+        self._timezone_box.pack_start(self._zone_alert_box, False)
 
         self._zone_alert = InlineAlert()
         self._zone_alert_box.pack_start(self._zone_alert)
@@ -103,6 +230,55 @@ class TimeZone(SectionView):
         self._cursor_change_handler = self._treeview.connect( \
                 'cursor-changed', self.__zone_changed_cd)
 
+        if self._model.is_ntp_servers_config_feature_available():
+            self.setup_ui_for_ntp_server_config()
+
+    def setup_ui_for_ntp_server_config(self):
+        self._ntp_scrolled_window = gtk.ScrolledWindow()
+        self._ntp_scrolled_window.set_policy(gtk.POLICY_NEVER,
+                                         gtk.POLICY_AUTOMATIC)
+        box_ntp_servers_config = gtk.VBox()
+        box_ntp_servers_config.set_spacing(style.DEFAULT_SPACING)
+
+        separator_ntp_servers_config= gtk.HSeparator()
+        self._container.pack_start(separator_ntp_servers_config,
+                                   expand=False)
+        separator_ntp_servers_config.show()
+
+        label_ntp_servers_config = gtk.Label(_('NTP Servers Configuration'))
+        label_ntp_servers_config.set_alignment(0, 0)
+        self._container.pack_start(label_ntp_servers_config,
+                                          expand=False)
+        label_ntp_servers_config.show()
+
+        self._ntp_servers_save_button = gtk.Button()
+        self._ntp_servers_save_button.set_alignment(0, 0)
+        self._ntp_servers_save_button.set_label(_('Save'))
+        self._ntp_servers_save_button.connect('clicked',
+                self.__ntp_servers_save_button_clicked_cb)
+
+        box_save_button = gtk.HBox()
+        box_save_button.set_homogeneous(False)
+        box_save_button.pack_start(self._ntp_servers_save_button,
+                                   expand=False)
+        self._ntp_servers_save_button.show()
+
+        self._widget_table = MultiWidget()
+        box_ntp_servers_config.pack_start(self._widget_table, expand=False)
+        box_ntp_servers_config.pack_start(box_save_button, expand=False)
+        box_ntp_servers_config.show_all()
+
+        self._ntp_scrolled_window.add_with_viewport(box_ntp_servers_config)
+        self._container.pack_start(self._ntp_scrolled_window)
+        self._ntp_scrolled_window.show_all()
+
+        ntp_servers = self._model.get_ntp_servers()
+        if len(ntp_servers) == 0:
+            self._widget_table._add_widget('')
+        else:
+            for server in ntp_servers:
+                self._widget_table._add_widget(server)
+
     def undo(self):
         self._treeview.disconnect(self._cursor_change_handler)
         self._model.undo()
@@ -138,3 +314,7 @@ class TimeZone(SectionView):
         self._zone_alert.props.msg = self.restart_msg
         self._zone_alert.show()
         return False
+
+    def __ntp_servers_save_button_clicked_cb(self, save_button):
+        self._model.set_ntp_servers(self._widget_table._get_entries())
+        save_button.set_sensitive(False)
-- 
1.7.4.4



More information about the Dextrose mailing list