[network-manager-netbook] Fix static IP settings.



commit 96b0745eff98a5952f3c4d0f26fb9a7e0903847b
Author: Tambet Ingo <tambet gmail com>
Date:   Fri Aug 28 16:04:42 2009 +0300

    Fix static IP settings.
    
    Rewrite the "Advanced" widget to: show IP information of active connections,
    keep it up to date, make it actually do something, replace the connection
    method box with radio buttons to work around the fact that mutter-moblin
    does not support windows on top of panel.

 src/nmn-connection-details.c |  617 ++++++++++++++++++++++++++----------------
 src/nmn-connection-details.h |   13 +-
 src/nmn-item-advanced.c      |    9 -
 src/nmn-item-advanced.h      |    2 -
 src/nmn-item.c               |   83 ++++--
 src/nmn-item.h               |    6 +-
 src/nmn-network-item.c       |  111 ++++++--
 7 files changed, 533 insertions(+), 308 deletions(-)
---
diff --git a/src/nmn-connection-details.c b/src/nmn-connection-details.c
index 101fec5..9f6e00b 100644
--- a/src/nmn-connection-details.c
+++ b/src/nmn-connection-details.c
@@ -1,72 +1,75 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
+#include <glib/gi18n.h>
 #include <string.h>
+#include <stdlib.h>
 #include <arpa/inet.h>
+#include <errno.h>
 #include <nm-utils.h>
 #include "nmn-connection-details.h"
 #include "nmn-item-advanced.h"
 
 static void item_advanced_init (NmnItemAdvanced *item_advanced_class);
+static gboolean verify (NmnItemAdvanced *item_advanced);
 
 G_DEFINE_TYPE_EXTENDED (NmnConnectionDetails, nmn_connection_details, GTK_TYPE_TABLE, 0,
                         G_IMPLEMENT_INTERFACE (NMN_TYPE_ITEM_ADVANCED, item_advanced_init))
 
-enum {
-    PROP_0,
-    PROP_EDITABLE,
-
-    LAST_PROP
-};
-
 #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NMN_TYPE_CONNECTION_DETAILS, NmnConnectionDetailsPrivate))
 
 typedef struct {
-    GtkComboBox *method_combo;
+    GtkWidget *method_auto;
+    GtkWidget *method_manual;
+    GtkWidget *method_link_local;
+
     GtkWidget *address;
     GtkWidget *netmask;
     GtkWidget *gateway;
     GtkWidget *dns;
+
     gboolean editable;
+    gboolean last_check_result;
 
     gboolean disposed;
 } NmnConnectionDetailsPrivate;
 
-#define METHOD_AUTO       0
-#define METHOD_MANUAL     1
-#define METHOD_LINK_LOCAL 2
-
-GtkWidget *
-nmn_connection_details_new (gboolean editable)
+NmnItemAdvanced *
+nmn_connection_details_new (void)
 {
-    return GTK_WIDGET (g_object_new (NMN_TYPE_CONNECTION_DETAILS,
-                                     NMN_CONNECTION_DETAILS_EDITABLE, editable,
-                                     NULL));
+    return NMN_ITEM_ADVANCED (g_object_new (NMN_TYPE_CONNECTION_DETAILS, NULL));
 }
 
-void
-nmn_connection_details_set_setting (NmnConnectionDetails *self,
-                                    NMSettingIP4Config *setting)
+static void
+editable_changed (NmnConnectionDetails *self,
+                  gboolean editable)
 {
-    NmnConnectionDetailsPrivate *priv;
-    const char *method;
-    int active_method;
-
-    g_return_if_fail (NMN_IS_CONNECTION_DETAILS (self));
-    g_return_if_fail (NM_IS_SETTING_IP4_CONFIG (setting));
+    NmnConnectionDetailsPrivate *priv = GET_PRIVATE (self);
+    gboolean entries_enabled;
 
-    priv = GET_PRIVATE (self);
+    priv->editable = editable;
+    gtk_widget_set_sensitive (priv->method_auto, editable);
+    gtk_widget_set_sensitive (priv->method_manual, editable);
+    gtk_widget_set_sensitive (priv->method_link_local, editable);
 
-    method = nm_setting_ip4_config_get_method (setting);
-    if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
-        active_method = METHOD_AUTO;
-    else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
-        active_method = METHOD_MANUAL;
-    else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
-        active_method = METHOD_LINK_LOCAL;
+    if (editable)
+        entries_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->method_manual));
     else
-        active_method = -1;
+        entries_enabled = FALSE;
+
+    gtk_widget_set_sensitive (priv->address, entries_enabled);
+    gtk_widget_set_sensitive (priv->netmask, entries_enabled);
+    gtk_widget_set_sensitive (priv->gateway, entries_enabled);
 
-    gtk_combo_box_set_active (priv->method_combo, active_method);
+    gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->dns), entries_enabled);
+}
+
+static void
+radio_toggled (GtkToggleButton *toggle,
+               gpointer user_data)
+{
+    NmnConnectionDetails *self = NMN_CONNECTION_DETAILS (user_data);
+
+    editable_changed (self, GET_PRIVATE (self)->editable);
 }
 
 static char *
@@ -78,146 +81,261 @@ ip4_address_as_string (guint32 ip)
     tmp_addr.s_addr = ip;
     ip_string = g_malloc0 (INET_ADDRSTRLEN + 1);
     if (!inet_ntop (AF_INET, &tmp_addr, ip_string, INET_ADDRSTRLEN))
-        strcpy (ip_string, "(none)");
+        strcpy (ip_string, _("(none)"));
 
     return ip_string;
 }
 
-static inline GtkWidget *
-aligned_label_new (const char *text)
+void
+nmn_connection_details_set_data (NmnConnectionDetails *self,
+                                 NMSettingIP4Config *setting,
+                                 NMIP4Config *config)
 {
-    GtkWidget *w;
+    NmnConnectionDetailsPrivate *priv;
+    GtkTextBuffer *buffer;
+    NMIP4Address *address = NULL;
+    GString *string;
+    char *str;
+    const char *method;
+    int i;
 
-    w = gtk_label_new (text);
-    g_object_set (w, "xalign", 0.0, NULL);
+    g_return_if_fail (NMN_IS_CONNECTION_DETAILS (self));
+    g_return_if_fail (NM_IS_SETTING_IP4_CONFIG (setting));
 
-    return w;
-}
+    priv = GET_PRIVATE (self);
 
-static GtkWidget *
-create_text_widget (GtkWidget *current_widget,
-                    GtkTable *table,
-                    int col,
-                    int row,
-                    gboolean editable)
-{
-    GtkWidget *w;
-    GType target_type;
+    method = nm_setting_ip4_config_get_method (setting);
+    if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO))
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->method_auto), TRUE);
+    else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL))
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->method_manual), TRUE);
+    else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL))
+        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->method_link_local), TRUE);
+    else
+        g_assert_not_reached ();
 
-    target_type = editable ? GTK_TYPE_ENTRY : GTK_TYPE_LABEL;
+    /* We're editable when we're not connected, ie, when
+       the active IP4 config is not present */
+    editable_changed (self, config == NULL);
 
-    if (current_widget && G_TYPE_CHECK_INSTANCE_TYPE (current_widget, target_type))
-        /* all well, nothing to do */
-        return current_widget;
+    /* We prefer config if it's present */
+    if (config) {
+        const GSList *list;
 
-    if (current_widget)
-        gtk_widget_destroy (current_widget);
+        list = nm_ip4_config_get_addresses (config);
+        address = list ? list->data : NULL;
+    }
 
-    if (editable)
-        w = gtk_entry_new ();
-    else
-        w = aligned_label_new ("");
+    if (!address)
+        address = nm_setting_ip4_config_get_address (setting, 0);
+
+    if (address) {
+        str = ip4_address_as_string (nm_ip4_address_get_address (address));
+        gtk_entry_set_text (GTK_ENTRY (priv->address), str);
+        g_free (str);
+
+        str = ip4_address_as_string (nm_utils_ip4_prefix_to_netmask (nm_ip4_address_get_prefix (address)));
+        gtk_entry_set_text (GTK_ENTRY (priv->netmask), str);
+        g_free (str);
+
+        str = ip4_address_as_string (nm_ip4_address_get_gateway (address));
+        gtk_entry_set_text (GTK_ENTRY (priv->gateway), str);
+        g_free (str);
+    } else {
+        gtk_entry_set_text (GTK_ENTRY (priv->address), "");
+        gtk_entry_set_text (GTK_ENTRY (priv->gateway), "");
+        gtk_entry_set_text (GTK_ENTRY (priv->gateway), "");
+    }
 
-    gtk_widget_show (w);
-    gtk_table_attach_defaults (table, w, col, col + 1, row, row + 1);
+    if (config) {
+        const GArray *array;
 
-    return w;
-}
+        string = g_string_sized_new (256);
+        array = nm_ip4_config_get_nameservers (config);
+        for (i = 0; array && i < array->len; i++) {
+            if (i > 0)
+                g_string_append_c (string, '\n');
 
-static void
-editable_changed (NmnConnectionDetails *self)
-{
-    NmnConnectionDetailsPrivate *priv = GET_PRIVATE (self);
-    GtkTable *table = GTK_TABLE (self);
+            str = ip4_address_as_string (g_array_index (array, guint32, i));
+            g_string_append (string, str);
+            g_free (str);
+        }
 
-    priv->editable = gtk_combo_box_get_active (priv->method_combo) == METHOD_MANUAL;
+        str = g_string_free (string, FALSE);
+    } else {
+        string = g_string_sized_new (256);
+        for (i = 0; i < nm_setting_ip4_config_get_num_dns (setting); i++) {
+            if (i > 0)
+                g_string_append_c (string, '\n');
 
-    priv->address = create_text_widget (priv->address, table, 1, 1, priv->editable);
-    priv->netmask = create_text_widget (priv->netmask, table, 1, 2, priv->editable);
-    priv->gateway = create_text_widget (priv->gateway, table, 1, 3, priv->editable);
+            str = ip4_address_as_string (nm_setting_ip4_config_get_dns (setting, i));
+            g_string_append (string, str);
+            g_free (str);
+        }
+
+        str = g_string_free (string, FALSE);
+    }
 
-    gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->dns), priv->editable);
+    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->dns));
+    gtk_text_buffer_set_text (buffer, str, -1);
+    g_free (str);
 }
 
-static inline void
-widget_set_text (GtkWidget *w, char *str)
-{
-    if (GTK_IS_LABEL (w))
-        gtk_label_set_text (GTK_LABEL (w), str);
-    else if (GTK_IS_ENTRY (w))
-        gtk_entry_set_text (GTK_ENTRY (w), str);
-    else
-        g_warning ("Invalid widget type '%s'", G_OBJECT_TYPE_NAME (w));
 
-    g_free (str);
+static gboolean
+parse_netmask (const char *str, guint32 *prefix)
+{
+	struct in_addr tmp_addr;
+	glong tmp_prefix;
+
+	errno = 0;
+
+	/* Is it a prefix? */
+	if (!strchr (str, '.')) {
+		tmp_prefix = strtol (str, NULL, 10);
+		if (!errno && tmp_prefix >= 0 && tmp_prefix <= 32) {
+			*prefix = tmp_prefix;
+			return TRUE;
+		}
+	}
+
+	/* Is it a netmask? */
+	if (inet_pton (AF_INET, str, &tmp_addr) > 0) {
+		*prefix = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr);
+		return TRUE;
+	}
+
+	return FALSE;
 }
 
-void
-nmn_connection_details_set_config (NmnConnectionDetails *self,
-                                   NMIP4Config *config)
+static gboolean
+parse_dns_list (GtkTextView *view, GSList **dns_list)
 {
-    NmnConnectionDetailsPrivate *priv;
-    const GSList *list;
-    const GArray *array;
-    char *str;
     GtkTextBuffer *buffer;
+    char **items;
+    char **iter;
+    char *str = NULL;
+    gboolean success = TRUE;
 
-    g_return_if_fail (NMN_IS_CONNECTION_DETAILS (self));
-    g_return_if_fail (NM_IS_IP4_CONFIG (config));
-
-    priv = GET_PRIVATE (self);
+    buffer = gtk_text_view_get_buffer (view);
+    g_object_get (buffer, "text", &str, NULL);
 
-    list = nm_ip4_config_get_addresses (config);
-    if (list) {
-        NMIP4Address *def_addr = (NMIP4Address *) list->data;
-        guint32 netmask;
+    items = g_strsplit (str, ", ;:\n", 0);
+    g_free (str);
 
-        str = ip4_address_as_string (nm_ip4_address_get_address (def_addr));
-        widget_set_text (priv->address, str);
+    for (iter = items; *iter; iter++) {
+        char *stripped = g_strstrip (*iter);
+        struct in_addr tmp_addr;
 
-        netmask = nm_utils_ip4_prefix_to_netmask (nm_ip4_address_get_prefix (def_addr));
-        str = ip4_address_as_string (netmask);
-        widget_set_text (priv->netmask, str);
+        if (strlen (stripped) < 1)
+            continue;
 
-        if (nm_ip4_address_get_gateway (def_addr)) {
-            str = ip4_address_as_string (nm_ip4_address_get_gateway (def_addr));
-            widget_set_text (priv->gateway, str);
+        if (inet_pton (AF_INET, stripped, &tmp_addr))
+            *dns_list = g_slist_prepend (*dns_list, GUINT_TO_POINTER (tmp_addr.s_addr));
+        else {
+            success = FALSE;
+            break;
         }
     }
 
-    array = nm_ip4_config_get_nameservers (config);
-	if (array) {
-        GString *string;
-        int i;
+    g_strfreev (items);
 
-        string = g_string_sized_new (50);
-        for (i = 0; i < array->len; i++) {
-            if (i > 0)
-                g_string_append_c (string, '\n');
+    if (success)
+        *dns_list = g_slist_reverse (*dns_list);
+    else {
+        g_slist_free (*dns_list);
+        *dns_list = NULL;
+    }
 
-            str = ip4_address_as_string (g_array_index (array, guint32, i));
-            g_string_append (string, str);
-            g_free (str);
-        }
+    return success;
+}
 
-        str = g_string_free (string, FALSE);
-	} else
-        str = NULL;
+static gboolean
+ui_to_setting (NmnConnectionDetails *self,
+               const char **method,
+               NMIP4Address **address,
+               GSList **dns_list)
+{
+    NmnConnectionDetailsPrivate *priv = GET_PRIVATE (self);
+    gboolean success = FALSE;
+
+    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->method_auto))) {
+        *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
+        *address = NULL;
+        success = TRUE;
+    } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->method_link_local))) {
+        *method = NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL;
+        *address = NULL;
+        success = TRUE;
+    } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->method_manual))) {
+        struct in_addr tmp_addr  = { 0 };
+        guint32 prefix;
+
+        *address = nm_ip4_address_new ();
+        
+        if (inet_aton (gtk_entry_get_text (GTK_ENTRY (priv->address)), &tmp_addr) == 0)
+            goto out;
+        nm_ip4_address_set_address (*address, tmp_addr.s_addr);
+
+        if (!parse_netmask (gtk_entry_get_text (GTK_ENTRY (priv->netmask)), &prefix))
+            goto out;
+        nm_ip4_address_set_prefix (*address, prefix);
+
+        if (inet_aton (gtk_entry_get_text (GTK_ENTRY (priv->gateway)), &tmp_addr) == 0)
+            goto out;
+        nm_ip4_address_set_gateway (*address, tmp_addr.s_addr);
+
+        if (!parse_dns_list (GTK_TEXT_VIEW (priv->dns), dns_list))
+            goto out;
+
+        *method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
+
+        success = TRUE;
+    } else
+        g_assert_not_reached ();
+
+ out:
+    if (!success && *address) {
+        nm_ip4_address_unref (*address);
+        *address = NULL;
+    }
 
-    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->dns));
-    gtk_text_buffer_set_text (buffer, str, -1);
-    g_free (str);
+    return success;
 }
 
-static gboolean
-verify (NmnItemAdvanced *item_advanced)
+NMSettingIP4Config *
+nmn_connection_details_get_data (NmnConnectionDetails *self)
 {
-    return FALSE;
+    NMSettingIP4Config *setting;
+    const char *method;
+    NMIP4Address *address;
+    GSList *dns_list = NULL;
+    GSList *iter;
+
+    g_return_val_if_fail (NMN_IS_CONNECTION_DETAILS (self), NULL);
+
+    if (!ui_to_setting (self, &method, &address, &dns_list))
+        return NULL;
+
+    setting = NM_SETTING_IP4_CONFIG (nm_setting_ip4_config_new ());
+    g_object_set (setting, NM_SETTING_IP4_CONFIG_METHOD, method, NULL);
+    if (address) {
+        nm_setting_ip4_config_add_address (setting, address);
+        nm_ip4_address_unref (address);
+    }
+
+    for (iter = dns_list; iter; iter = iter->next)
+        nm_setting_ip4_config_add_dns (setting, GPOINTER_TO_UINT (iter->data));
+
+    g_slist_free (dns_list);
+
+    return setting;
 }
 
-static void
-save (NmnItemAdvanced *item_advanced)
+static gboolean
+verify (NmnItemAdvanced *item_advanced)
 {
+    return GET_PRIVATE (item_advanced)->last_check_result;
 }
 
 static void
@@ -225,7 +343,95 @@ item_advanced_init (NmnItemAdvanced *item_advanced_class)
 {
     /* interface implementation */
     item_advanced_class->verify = verify;
-    item_advanced_class->save = save;
+}
+
+static void
+ip_filter_cb (GtkEditable *editable,
+              gchar *text,
+              gint length,
+              gint *position,
+              gpointer user_data)
+{
+    gchar *result;
+    int i;
+    int count = 0;
+
+    result = g_new (gchar, length);
+    for (i = 0; i < length; i++) {
+        int c = text[i];
+
+        if ((c >= '0' && c <= '9') || c == '.')
+            result[count++] = c;
+    }
+
+    if (count > 0) {
+        g_signal_handlers_block_by_func (editable, G_CALLBACK (ip_filter_cb), user_data);
+        gtk_editable_insert_text (editable, result, count, position);
+        g_signal_handlers_unblock_by_func (editable, G_CALLBACK (ip_filter_cb), user_data);
+    }
+
+    g_signal_stop_emission_by_name (editable, "insert-text");
+    g_free (result);
+}
+
+static void
+dns_filter_cb (GtkTextBuffer *textbuffer,
+               GtkTextIter *location,
+               gchar *text,
+               gint length,
+               gpointer user_data)
+{
+    gchar *result;
+    int i;
+    int count = 0;
+
+    result = g_new (gchar, length);
+    for (i = 0; i < length; i++) {
+        char c = text[i];
+
+        if ((c >= '0' && c <= '9') || c == '.' || c == '\n' || c == ' ' || c == ';' || c == ':')
+            result[count++] = c;
+    }
+
+    if (count > 0) {
+        g_signal_handlers_block_by_func (textbuffer, G_CALLBACK (dns_filter_cb), user_data);
+        gtk_text_buffer_insert_at_cursor (textbuffer, result, count);
+        g_signal_handlers_unblock_by_func (textbuffer, G_CALLBACK (dns_filter_cb), user_data);
+    }
+
+    g_signal_stop_emission_by_name (textbuffer, "insert-text");
+    g_free (result);
+}
+
+static void
+stuff_changed (NmnConnectionDetails *self)
+{
+    NmnConnectionDetailsPrivate *priv = GET_PRIVATE (self);
+    const char *method;
+    NMIP4Address *address;
+    GSList *dns_list = NULL;
+    gboolean verified;
+
+    verified = ui_to_setting (self, &method, &address, &dns_list);
+    if (address)
+        nm_ip4_address_unref (address);
+    g_slist_free (dns_list);
+
+    if (verified != priv->last_check_result) {
+        priv->last_check_result = verified;
+        g_signal_emit_by_name (self, "changed", verified);
+    }
+}
+
+static inline GtkWidget *
+aligned_label_new (const char *text)
+{
+    GtkWidget *w;
+
+    w = gtk_label_new (text);
+    g_object_set (w, "xalign", 0.0, NULL);
+
+    return w;
 }
 
 static void
@@ -234,9 +440,10 @@ nmn_connection_details_init (NmnConnectionDetails *details)
     NmnConnectionDetailsPrivate *priv = GET_PRIVATE (details);
     GtkTable *table;
     GtkWidget *w;
+    GtkTextBuffer *buffer;
 
     g_object_set (details,
-                  "n-rows", 5,
+                  "n-rows", 7,
                   "n-columns", 2,
                   "homogeneous", FALSE,
                   "row-spacing", 6,
@@ -245,98 +452,67 @@ nmn_connection_details_init (NmnConnectionDetails *details)
 
     table = GTK_TABLE (details);
 
-    w = aligned_label_new ("Connect by:");
+    /* Connect by: */
+    w = aligned_label_new (_("Connect by:"));
     gtk_table_attach_defaults (table, w, 0, 1, 0, 1);
 
-    w = aligned_label_new ("IP Address:");
-    gtk_table_attach_defaults (table, w, 0, 1, 1, 2);
-
-    w = aligned_label_new ("Subnet mask:");
-    gtk_table_attach_defaults (table, w, 0, 1, 2, 3);
-
-    w = aligned_label_new ("Router:");
-    gtk_table_attach_defaults (table, w, 0, 1, 3, 4);
-
-    w = aligned_label_new ("DNS:");
-    gtk_table_attach_defaults (table, w, 0, 1, 4, 5);
-
-    priv->dns = gtk_text_view_new ();
-    gtk_table_attach_defaults (table, priv->dns, 1, 2, 4, 5);
-
-    priv->method_combo = GTK_COMBO_BOX (gtk_combo_box_new_text ());
-    gtk_combo_box_append_text (priv->method_combo, "DHCP");
-    gtk_combo_box_append_text (priv->method_combo, "Manual");
-    gtk_combo_box_append_text (priv->method_combo, "Link Local");
-    gtk_table_attach_defaults (table, GTK_WIDGET (priv->method_combo), 1, 2, 0, 1);
-    g_signal_connect_swapped (priv->method_combo, "changed", G_CALLBACK (editable_changed), details);
-    gtk_combo_box_set_active (priv->method_combo, METHOD_AUTO);
-}
+    priv->method_auto = gtk_radio_button_new_with_label (NULL, _("DHCP"));
+    gtk_table_attach_defaults (table, priv->method_auto, 1, 2, 0, 1);
+    g_signal_connect (priv->method_auto, "toggled", G_CALLBACK (radio_toggled), details);
+    g_signal_connect_swapped (priv->method_auto, "toggled", G_CALLBACK (stuff_changed), details);
 
-static GObject*
-constructor (GType type,
-             guint n_construct_params,
-             GObjectConstructParam *construct_params)
-{
-    GObject *object;
-    NmnConnectionDetailsPrivate *priv;
+    priv->method_manual = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (priv->method_auto), _("Manual"));
+    gtk_table_attach_defaults (table, priv->method_manual, 1, 2, 1, 2);
+    g_signal_connect (priv->method_manual, "toggled", G_CALLBACK (radio_toggled), details);
+    g_signal_connect_swapped (priv->method_manual, "toggled", G_CALLBACK (stuff_changed), details);
 
-    object = G_OBJECT_CLASS (nmn_connection_details_parent_class)->constructor
-        (type, n_construct_params, construct_params);
+    priv->method_link_local = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (priv->method_auto), _("Link Local"));
+    gtk_table_attach_defaults (table, priv->method_link_local, 1, 2, 2, 3);
+    g_signal_connect (priv->method_link_local, "toggled", G_CALLBACK (radio_toggled), details);
+    g_signal_connect_swapped (priv->method_link_local, "toggled", G_CALLBACK (stuff_changed), details);
 
-    if (!object)
-        return NULL;
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->method_auto), TRUE);
 
-    priv = GET_PRIVATE (object);
+    /* Address */
+    w = aligned_label_new (_("IP Address:"));
+    gtk_table_attach_defaults (table, w, 0, 1, 3, 4);
 
-    gtk_widget_set_sensitive (GTK_WIDGET (priv->method_combo), priv->editable);
-    gtk_widget_show_all (GTK_WIDGET (object));
+    priv->address = gtk_entry_new ();
+    gtk_table_attach_defaults (table, priv->address, 1, 2, 3, 4);
+    g_signal_connect (priv->address, "insert-text", G_CALLBACK (ip_filter_cb), NULL);
+    g_signal_connect_swapped (priv->address, "changed", G_CALLBACK (stuff_changed), details);
 
-    return object;
-}
+    /* Netmask */
+    w = aligned_label_new (_("Subnet mask:"));
+    gtk_table_attach_defaults (table, w, 0, 1, 4, 5);
 
-static void
-set_property (GObject *object, guint prop_id,
-              const GValue *value, GParamSpec *pspec)
-{
-    NmnConnectionDetailsPrivate *priv = GET_PRIVATE (object);
-
-    switch (prop_id) {
-    case PROP_EDITABLE:
-        priv->editable = g_value_get_boolean (value);
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-        break;
-    }
-}
+    priv->netmask = gtk_entry_new ();
+    gtk_table_attach_defaults (table, priv->netmask, 1, 2, 4, 5);
+    g_signal_connect (priv->netmask, "insert-text", G_CALLBACK (ip_filter_cb), NULL);
+    g_signal_connect_swapped (priv->netmask, "changed", G_CALLBACK (stuff_changed), details);
 
-static void
-get_property (GObject *object, guint prop_id,
-              GValue *value, GParamSpec *pspec)
-{
-    NmnConnectionDetailsPrivate *priv = GET_PRIVATE (object);
-
-    switch (prop_id) {
-    case PROP_EDITABLE:
-        g_value_set_boolean (value, priv->editable);
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-        break;
-    }
-}
+    /* Gateway */
+    w = aligned_label_new (_("Router:"));
+    gtk_table_attach_defaults (table, w, 0, 1, 5, 6);
 
-static void
-dispose (GObject *object)
-{
-    NmnConnectionDetailsPrivate *priv = GET_PRIVATE (object);
+    priv->gateway = gtk_entry_new ();
+    gtk_table_attach_defaults (table, priv->gateway, 1, 2, 5, 6);
+    g_signal_connect (priv->gateway, "insert-text", G_CALLBACK (ip_filter_cb), NULL);
+    g_signal_connect_swapped (priv->gateway, "changed", G_CALLBACK (stuff_changed), details);
 
-    if (priv->disposed)
-        return;
+    /* DNS */
+    w = aligned_label_new (_("DNS:"));
+    gtk_table_attach_defaults (table, w, 0, 1, 6, 7);
 
-    priv->disposed = TRUE;
+    priv->dns = gtk_text_view_new ();
+    gtk_table_attach_defaults (table, priv->dns, 1, 2, 6, 7);
+    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->dns));
+    g_signal_connect (buffer, "insert-text", G_CALLBACK (dns_filter_cb), NULL);
+    g_signal_connect_swapped (buffer, "changed", G_CALLBACK (stuff_changed), details);
 
-    G_OBJECT_CLASS (nmn_connection_details_parent_class)->dispose (object);
+    editable_changed (details, TRUE);
+    stuff_changed (details);
+    gtk_widget_show_all (GTK_WIDGET (details));
 }
 
 static void
@@ -345,19 +521,4 @@ nmn_connection_details_class_init (NmnConnectionDetailsClass *class)
     GObjectClass *object_class = G_OBJECT_CLASS (class);
 
     g_type_class_add_private (object_class, sizeof (NmnConnectionDetailsPrivate));
-
-    object_class->constructor = constructor;
-    object_class->set_property = set_property;
-    object_class->get_property = get_property;
-    object_class->dispose = dispose;
-
-    /* properties */
-    g_object_class_install_property
-        (object_class, PROP_EDITABLE,
-         g_param_spec_boolean (NMN_CONNECTION_DETAILS_EDITABLE,
-                               "Editable",
-                               "Editable",
-                               FALSE,
-                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
 }
diff --git a/src/nmn-connection-details.h b/src/nmn-connection-details.h
index bea4f4d..e1585eb 100644
--- a/src/nmn-connection-details.h
+++ b/src/nmn-connection-details.h
@@ -6,6 +6,7 @@
 #include <gtk/gtk.h>
 #include <nm-setting-ip4-config.h>
 #include <nm-ip4-config.h>
+#include "nmn-item-advanced.h"
 
 #define NMN_TYPE_CONNECTION_DETAILS            (nmn_connection_details_get_type ())
 #define NMN_CONNECTION_DETAILS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_CONNECTION_DETAILS, NmnConnectionDetails))
@@ -14,8 +15,6 @@
 #define NMN_IS_CONNECTION_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NMN_TYPE_CONNECTION_DETAILS))
 #define NMN_CONNECTION_DETAILS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMN_TYPE_CONNECTION_DETAILS, NmnConnectionDetailsClass))
 
-#define NMN_CONNECTION_DETAILS_EDITABLE "editable"
-
 typedef struct {
     GtkTable parent;
 } NmnConnectionDetails;
@@ -26,11 +25,11 @@ typedef struct {
 
 GType nmn_connection_details_get_type (void);
 
-GtkWidget *nmn_connection_details_new         (gboolean editable);
-void       nmn_connection_details_set_setting (NmnConnectionDetails *self,
-                                               NMSettingIP4Config *setting);
+NmnItemAdvanced    *nmn_connection_details_new      (void);
+void                nmn_connection_details_set_data (NmnConnectionDetails *self,
+                                                     NMSettingIP4Config *setting,
+                                                     NMIP4Config *config);
 
-void       nmn_connection_details_set_config  (NmnConnectionDetails *self,
-                                               NMIP4Config *config);
+NMSettingIP4Config *nmn_connection_details_get_data (NmnConnectionDetails *self);
 
 #endif /* NMN_CONNECTION_DETAILS_H */
diff --git a/src/nmn-item-advanced.c b/src/nmn-item-advanced.c
index caa36b8..fd881c4 100644
--- a/src/nmn-item-advanced.c
+++ b/src/nmn-item-advanced.c
@@ -26,15 +26,6 @@ nmn_item_advanced_verify (NmnItemAdvanced *self)
     return verified;
 }
 
-void
-nmn_item_advanced_save (NmnItemAdvanced *self)
-{
-    g_return_if_fail (NMN_IS_ITEM_ADVANCED (self));
-
-    if (NMN_ITEM_ADVANCED_GET_INTERFACE (self)->save)
-        NMN_ITEM_ADVANCED_GET_INTERFACE (self)->save (self);
-}
-
 /*****************************************************************************/
 
 static void
diff --git a/src/nmn-item-advanced.h b/src/nmn-item-advanced.h
index a8a1d2a..37ae7c9 100644
--- a/src/nmn-item-advanced.h
+++ b/src/nmn-item-advanced.h
@@ -17,7 +17,6 @@ struct _NmnItemAdvanced {
 
     /* Methods */
     gboolean (*verify) (NmnItemAdvanced *self);
-    void (*save) (NmnItemAdvanced *self);
 
     /* Signals */
     void (*changed) (NmnItemAdvanced *self,
@@ -27,6 +26,5 @@ struct _NmnItemAdvanced {
 GType nmn_item_advanced_get_type (void);
 
 gboolean nmn_item_advanced_verify (NmnItemAdvanced *self);
-void     nmn_item_advanced_save   (NmnItemAdvanced *self);
 
 #endif /* NMN_ITEM_ADVANCED_H */
diff --git a/src/nmn-item.c b/src/nmn-item.c
index 2a2f7cc..2319d36 100644
--- a/src/nmn-item.c
+++ b/src/nmn-item.c
@@ -28,7 +28,8 @@ typedef struct {
     GtkWidget *status_separator;
     GtkLabel *status_label;
     GtkLabel *security;
-    GtkWidget *advanced;
+    GtkWidget *expander;
+    NmnItemAdvanced *advanced;
     GtkButton *connect;
     GtkWidget *remove;
     NmnItemStatus status;
@@ -232,40 +233,62 @@ nmn_item_priority_changed (NmnItem *self)
 }
 
 static void
-advanced_expanded (GtkExpander *expander,
-                   GParamSpec *param_spec,
-                   gpointer user_data)
+advanced_changed (NmnItemAdvanced *advanced,
+                  gboolean complete,
+                  gpointer user_data)
 {
-    NmnItem *self = NMN_ITEM (user_data);
-    NmnItemPrivate *priv = NMN_ITEM_GET_PRIVATE (self);
-    GtkWidget *child;
+    NmnItemPrivate *priv = NMN_ITEM_GET_PRIVATE (user_data);
 
-    if (gtk_expander_get_expanded (expander)) {
-        /* create widgets */
+    gtk_widget_set_sensitive (GTK_WIDGET (priv->connect), complete);
+}
 
-        if (NMN_ITEM_GET_CLASS (self)->create_advanced_information)
-            child = NMN_ITEM_GET_CLASS (self)->create_advanced_information (self);
-        else
-            child = NULL;
+gboolean
+nmn_item_has_advanced (NmnItem *item)
+{
+    g_return_val_if_fail (NMN_IS_ITEM (item), NULL);
+
+    return NMN_ITEM_GET_PRIVATE (item)->advanced != NULL;
+}
 
-        if (child) {
-            GtkWidget *alignment;
+NmnItemAdvanced *
+nmn_item_get_advanced (NmnItem *item)
+{
+    NmnItemPrivate *priv;
+    GtkWidget *alignment;
 
-            alignment = gtk_alignment_new (0, 0, 0, 0);
-            gtk_container_add (GTK_CONTAINER (alignment), child);
-            gtk_widget_show (alignment);
+    g_return_val_if_fail (NMN_IS_ITEM (item), NULL);
 
-            gtk_box_pack_end (priv->vbox, alignment, FALSE, FALSE, 0);
-            g_object_set_data (G_OBJECT (priv->vbox), "expanded-child", alignment);
-        }
-    } else {
-        /* Hide or destroy widgets */
-        child = GTK_WIDGET (g_object_get_data (G_OBJECT (priv->vbox), "expanded-child"));
-        if (child) {
-            g_object_set_data (G_OBJECT (priv->vbox), "expanded-child", NULL);
-            gtk_container_remove (GTK_CONTAINER (priv->vbox), child);
-        }
-    }
+    priv = NMN_ITEM_GET_PRIVATE (item);
+    if (priv->advanced)
+        return priv->advanced;
+
+    if (NMN_ITEM_GET_CLASS (item)->create_advanced_information)
+        priv->advanced = NMN_ITEM_GET_CLASS (item)->create_advanced_information (item);
+
+    if (!priv->advanced)
+        return NULL;
+
+    alignment = gtk_alignment_new (0, 0, 0, 0);
+    gtk_container_add (GTK_CONTAINER (alignment), GTK_WIDGET (priv->advanced));
+    gtk_widget_show (alignment);
+    gtk_box_pack_end (priv->vbox, alignment, FALSE, FALSE, 0);
+
+    g_signal_connect (priv->advanced, "changed", G_CALLBACK (advanced_changed), item);
+    advanced_changed (priv->advanced, nmn_item_advanced_verify (priv->advanced), item);
+
+    return priv->advanced;
+}
+
+static void
+advanced_expanded (GtkExpander *expander,
+                   GParamSpec *param_spec,
+                   gpointer user_data)
+{
+    NmnItemAdvanced *advanced;
+
+    advanced = nmn_item_get_advanced (NMN_ITEM (user_data));
+    if (advanced)
+        g_object_set (advanced, "visible", gtk_expander_get_expanded (expander), NULL);
 }
 
 static void
@@ -342,7 +365,7 @@ nmn_item_init (NmnItem *item)
 
     w = gtk_expander_new (_("Advanced"));
     gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
-    priv->advanced = w;
+    priv->expander = w;
     g_signal_connect (w, "notify::expanded", G_CALLBACK (advanced_expanded), item);
 
     w = gtk_button_new_with_label (_("Connect"));
diff --git a/src/nmn-item.h b/src/nmn-item.h
index e4334b7..0753383 100644
--- a/src/nmn-item.h
+++ b/src/nmn-item.h
@@ -4,6 +4,7 @@
 #define NMN_ITEM_H
 
 #include <gtk/gtk.h>
+#include "nmn-item-advanced.h"
 
 #define NMN_TYPE_ITEM            (nmn_item_get_type ())
 #define NMN_ITEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMN_TYPE_ITEM, NmnItem))
@@ -23,7 +24,7 @@ typedef struct {
     void (*connect) (NmnItem *self);
     void (*disconnect) (NmnItem *self);
     guint (*get_priority) (NmnItem *self);
-    GtkWidget *(*create_advanced_information) (NmnItem *self);
+    NmnItemAdvanced *(*create_advanced_information) (NmnItem *self);
 
     /* Signals */
     void (*connect_requested) (NmnItem *self);
@@ -70,4 +71,7 @@ void       nmn_item_remove_request (NmnItem *self);
 guint      nmn_item_get_priority (NmnItem *self);
 void       nmn_item_priority_changed (NmnItem *self);
 
+gboolean         nmn_item_has_advanced (NmnItem *item);
+NmnItemAdvanced *nmn_item_get_advanced (NmnItem *item);
+
 #endif /* NMN_ITEM_H */
diff --git a/src/nmn-network-item.c b/src/nmn-network-item.c
index 4c2e180..8e97187 100644
--- a/src/nmn-network-item.c
+++ b/src/nmn-network-item.c
@@ -65,10 +65,35 @@ nmn_network_item_get_active_connection (NmnNetworkItem *self)
 }
 
 static void
+update_details (NmnNetworkItem *self,
+                NmnConnectionDetails *details)
+{
+    NmnNetworkItemPrivate *priv = GET_PRIVATE (self);
+    NMSettingIP4Config *setting = NULL;
+
+    if (priv->connection) {
+        NMConnection *connection;
+
+        connection = nm_exported_connection_get_connection (priv->connection);
+        setting = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
+    }
+
+    if (setting) {
+        NMIP4Config *config = NULL;
+
+        if (nm_device_get_state (priv->device) == NM_DEVICE_STATE_ACTIVATED)
+            config = nm_device_get_ip4_config (priv->device);
+
+        nmn_connection_details_set_data (details, setting, config);
+    }
+}
+
+static void
 ac_state_changed (NMActiveConnection *ac,
                   GParamSpec *pspec,
                   gpointer user_data)
 {
+    NmnItem *item = NMN_ITEM (user_data);
     NmnItemStatus status;
 
     if (ac) {
@@ -86,8 +111,11 @@ ac_state_changed (NMActiveConnection *ac,
     } else
         status = NMN_ITEM_STATUS_DISCONNECTED;
 
-    nmn_item_set_status (NMN_ITEM (user_data), status);
-    nmn_item_priority_changed (NMN_ITEM (user_data));
+    nmn_item_set_status (item, status);
+    nmn_item_priority_changed (item);
+
+    if (nmn_item_has_advanced (item))
+        update_details (NMN_NETWORK_ITEM (item), NMN_CONNECTION_DETAILS (nmn_item_get_advanced (item)));
 }
 
 void
@@ -131,6 +159,9 @@ update_item (NmnNetworkItem *self)
     s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (wrapped, NM_TYPE_SETTING_CONNECTION));
 
     nmn_item_set_name (item, nm_setting_connection_get_id (s_con));
+
+    if (nmn_item_has_advanced (item))
+        update_details (self, NMN_CONNECTION_DETAILS (nmn_item_get_advanced (item)));
 }
 
 static void
@@ -179,9 +210,10 @@ connect_cb (gpointer user_data,
     /* FIXME: Report the error somewhere */
 }
 
-static void
-connect (NmnItem *item)
+static gboolean
+delayed_connect (gpointer data)
 {
+    NmnItem *item = NMN_ITEM (data);
     NmnNetworkItemPrivate *priv = GET_PRIVATE (item);
     NMConnection *wrapped;
     const char *path;
@@ -189,11 +221,6 @@ connect (NmnItem *item)
     const char *specific_object;
     NMConnectionScope scope;
 
-    if (!priv->connection) {
-        g_warning ("Connection not set");
-        return;
-    }
-
     wrapped = nm_exported_connection_get_connection (priv->connection);
     path = nm_connection_get_path (wrapped);
     scope = nm_connection_get_scope (wrapped);
@@ -213,6 +240,46 @@ connect (NmnItem *item)
                                    specific_object,
                                    connect_cb,
                                    NULL);
+
+    return FALSE;
+}
+
+static void
+connect (NmnItem *item)
+{
+    NmnNetworkItemPrivate *priv = GET_PRIVATE (item);
+
+    if (!priv->connection) {
+        g_warning ("Connection not set");
+        return;
+    }
+
+    if (nmn_item_has_advanced (item)) {
+        NmnItemAdvanced *advanced = nmn_item_get_advanced (item);
+        NMConnection *wrapped;
+        NMSetting *current_config;
+        NMSetting *new_config;
+
+        wrapped = nm_exported_connection_get_connection (priv->connection);
+        current_config = nm_connection_get_setting (wrapped, NM_TYPE_SETTING_IP4_CONFIG);
+        new_config = NM_SETTING (nmn_connection_details_get_data (NMN_CONNECTION_DETAILS (advanced)));
+        g_assert (new_config);
+
+        if (current_config == NULL || nm_setting_compare (current_config, new_config, 0) == FALSE) {
+            GHashTable *new_settings;
+
+            nm_connection_add_setting (wrapped, new_config);
+            new_settings = nm_connection_to_hash (wrapped);
+            nm_exported_connection_update (priv->connection, new_settings, NULL);
+            g_hash_table_unref (new_settings);
+
+            /* Ugh... Give NM a bit of time to get the new values */
+            g_timeout_add_seconds (1, delayed_connect, item);
+            return;
+        }
+    }
+
+    g_idle_add (delayed_connect, item);
 }
 
 static void
@@ -300,31 +367,13 @@ get_priority (NmnItem *item)
     return priority;
 }
 
-static GtkWidget *
+static NmnItemAdvanced *
 create_advanced_information (NmnItem *item)
 {
-    NmnNetworkItemPrivate *priv = GET_PRIVATE (item);
-    GtkWidget *details;
-
-    details = nmn_connection_details_new (nmn_item_get_status (item) == NMN_ITEM_STATUS_DISCONNECTED);
-
-    if (priv->connection) {
-        NMConnection *connection;
-        NMSettingIP4Config *setting;
+    NmnItemAdvanced *details;
 
-        connection = nm_exported_connection_get_connection (priv->connection);
-        setting = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
-        if (setting)
-            nmn_connection_details_set_setting (NMN_CONNECTION_DETAILS (details), setting);
-    }
-
-    if (nm_device_get_state (priv->device) == NM_DEVICE_STATE_ACTIVATED) {
-        NMIP4Config *config;
-
-        config = nm_device_get_ip4_config (priv->device);
-        if (config)
-            nmn_connection_details_set_config (NMN_CONNECTION_DETAILS (details), config);
-    }
+    details = nmn_connection_details_new ();
+    update_details (NMN_NETWORK_ITEM (item), NMN_CONNECTION_DETAILS (details));
 
     return details;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]