[network-manager-applet] editor: improve color-indication for bad addresses and routes (bgo #660915)



commit 975181df307cbd25d6b86d48138457e8a461ed5a
Author: Jiří Klimeš <jklimes redhat com>
Date:   Tue Mar 3 14:27:05 2015 +0100

    editor: improve color-indication for bad addresses and routes (bgo #660915)
    
    Incorrect values are already indicated while they are edited. However, this
    commit also makes the incorrect values visible afterwards by setting cell
    background to red. It uses the pango markup which has the advantage of being
    visible even if the row is selected. When there's no value in the cell, the
    cell-background property is used instead.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=660915

 src/connection-editor/ip4-routes-dialog.c |   90 +++++++++++++++++++++++------
 src/connection-editor/ip6-routes-dialog.c |   79 +++++++++++++++++++++-----
 src/connection-editor/page-ip4.c          |   42 +++++++++++++-
 src/connection-editor/page-ip6.c          |   89 +++++++++++++++++++++--------
 src/utils/utils.c                         |   22 +++++++
 src/utils/utils.h                         |    3 +
 6 files changed, 269 insertions(+), 56 deletions(-)
---
diff --git a/src/connection-editor/ip4-routes-dialog.c b/src/connection-editor/ip4-routes-dialog.c
index 9265446..1d1f271 100644
--- a/src/connection-editor/ip4-routes-dialog.c
+++ b/src/connection-editor/ip4-routes-dialog.c
@@ -54,15 +54,19 @@ get_one_int (GtkTreeModel *model,
              int column,
              guint32 max_value,
              gboolean fail_if_missing,
-             guint32 *out)
+             guint32 *out,
+             char **out_raw)
 {
        char *item = NULL;
        gboolean success = FALSE;
        long int tmp_int;
 
        gtk_tree_model_get (model, iter, column, &item, -1);
+       if (out_raw)
+               *out_raw = item;
        if (!item || !strlen (item)) {
-               g_free (item);
+               if (!out_raw)
+                       g_free (item);
                return fail_if_missing ? FALSE : TRUE;
        }
 
@@ -75,7 +79,8 @@ get_one_int (GtkTreeModel *model,
        success = TRUE;
 
 out:
-       g_free (item);
+       if (!out_raw)
+               g_free (item);
        return success;
 }
 
@@ -84,7 +89,8 @@ get_one_prefix (GtkTreeModel *model,
                 GtkTreeIter *iter,
                 int column,
                 gboolean fail_if_missing,
-                guint32 *out)
+                guint32 *out,
+                char **out_raw)
 {
        char *item = NULL;
        struct in_addr tmp_addr = { 0 };
@@ -92,8 +98,11 @@ get_one_prefix (GtkTreeModel *model,
        glong tmp_prefix;
 
        gtk_tree_model_get (model, iter, column, &item, -1);
+       if (out_raw)
+               *out_raw = item;
        if (!item || !strlen (item)) {
-               g_free (item);
+               if (!out_raw)
+                       g_free (item);
                return fail_if_missing ? FALSE : TRUE;
        }
 
@@ -116,7 +125,8 @@ get_one_prefix (GtkTreeModel *model,
        }
 
 out:
-       g_free (item);
+       if (!out_raw)
+               g_free (item);
        return success;
 }
 
@@ -125,14 +135,18 @@ get_one_addr (GtkTreeModel *model,
               GtkTreeIter *iter,
               int column,
               gboolean fail_if_missing,
-              char **out)
+              char **out,
+              char **out_raw)
 {
        char *item = NULL;
        struct in_addr tmp_addr = { 0 };
 
        gtk_tree_model_get (model, iter, column, &item, -1);
+       if (out_raw)
+               *out_raw = item;
        if (!item || !strlen (item)) {
-               g_free (item);
+               if (!out_raw)
+                       g_free (item);
                return fail_if_missing ? FALSE : TRUE;
        }
 
@@ -140,7 +154,8 @@ get_one_addr (GtkTreeModel *model,
                return FALSE;
 
        if (tmp_addr.s_addr == 0) {
-               g_free (item);
+               if (!out_raw)
+                       g_free (item);
                return fail_if_missing ? FALSE : TRUE;
        }
 
@@ -172,24 +187,24 @@ validate (GtkWidget *dialog)
                guint32 prefix = 0, metric = 0;
 
                /* Address */
-               if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &addr))
+               if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &addr, NULL))
                        goto done;
                g_free (addr);
 
                /* Prefix */
-               if (!get_one_prefix (model, &tree_iter, COL_PREFIX, TRUE, &prefix))
+               if (!get_one_prefix (model, &tree_iter, COL_PREFIX, TRUE, &prefix, NULL))
                        goto done;
                /* Don't allow zero prefix for now - that's not supported in libnm-util */
                if (prefix == 0)
                        goto done;
 
                /* Next hop (optional) */
-               if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop))
+               if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop, NULL))
                        goto done;
                g_free (next_hop);
 
                /* Metric (optional) */
-               if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric))
+               if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, NULL))
                        goto done;
 
                iter_valid = gtk_tree_model_iter_next (model, &tree_iter);
@@ -632,6 +647,39 @@ tree_view_button_pressed_cb (GtkWidget *widget,
        return FALSE;
 }
 
+static void
+cell_error_data_func (GtkTreeViewColumn *tree_column,
+                      GtkCellRenderer *cell,
+                      GtkTreeModel *tree_model,
+                      GtkTreeIter *iter,
+                      gpointer data)
+{
+       guint32 col = GPOINTER_TO_UINT (data);
+       char *value = NULL;
+       char *addr, *next_hop;
+       guint32 prefix, metric;
+       const char *color = "red";
+       gboolean invalid = FALSE;
+
+       if (col == COL_ADDRESS)
+               invalid = !get_one_addr (tree_model, iter, COL_ADDRESS, TRUE, &addr, &value);
+       else if (col == COL_PREFIX)
+               invalid =    !get_one_prefix (tree_model, iter, COL_PREFIX, TRUE, &prefix, &value)
+                         || prefix == 0;
+       else if (col == COL_NEXT_HOP)
+               invalid = !get_one_addr (tree_model, iter, COL_NEXT_HOP, FALSE, &next_hop, &value);
+       else if (col == COL_METRIC)
+               invalid = !get_one_int (tree_model, iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, &value);
+       else
+               g_warn_if_reached ();
+
+       if (invalid)
+               utils_set_cell_background (cell, color, value);
+       else
+               utils_set_cell_background (cell, NULL, NULL);
+       g_free (value);
+}
+
 GtkWidget *
 ip4_routes_dialog_new (NMSettingIPConfig *s_ip4, gboolean automatic)
 {
@@ -726,6 +774,8 @@ ip4_routes_dialog_new (NMSettingIPConfig *s_ip4, gboolean automatic)
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_ADDRESS), NULL);
 
        /* Prefix column */
        renderer = gtk_cell_renderer_text_new ();
@@ -743,6 +793,8 @@ ip4_routes_dialog_new (NMSettingIPConfig *s_ip4, gboolean automatic)
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_PREFIX), NULL);
 
        /* Gateway column */
        renderer = gtk_cell_renderer_text_new ();
@@ -760,6 +812,8 @@ ip4_routes_dialog_new (NMSettingIPConfig *s_ip4, gboolean automatic)
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_NEXT_HOP), NULL);
 
        /* Metric column */
        renderer = gtk_cell_renderer_text_new ();
@@ -777,6 +831,8 @@ ip4_routes_dialog_new (NMSettingIPConfig *s_ip4, gboolean automatic)
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_METRIC), NULL);
 
        g_object_set_data_full (G_OBJECT (dialog), "renderers", renderers, (GDestroyNotify) g_slist_free);
 
@@ -837,27 +893,27 @@ ip4_routes_dialog_update_setting (GtkWidget *dialog, NMSettingIPConfig *s_ip4)
                NMIPRoute *route;
 
                /* Address */
-               if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &addr)) {
+               if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &addr, NULL)) {
                        g_warning ("%s: IPv4 address missing or invalid!", __func__);
                        goto next;
                }
 
                /* Prefix */
-               if (!get_one_prefix (model, &tree_iter, COL_PREFIX, TRUE, &prefix)) {
+               if (!get_one_prefix (model, &tree_iter, COL_PREFIX, TRUE, &prefix, NULL)) {
                        g_warning ("%s: IPv4 prefix/netmask missing or invalid!", __func__);
                        g_free (addr);
                        goto next;
                }
 
                /* Next hop (optional) */
-               if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop)) {
+               if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop, NULL)) {
                        g_warning ("%s: IPv4 next hop invalid!", __func__);
                        g_free (addr);
                        goto next;
                }
 
                /* Metric (optional) */
-               if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric)) {
+               if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, NULL)) {
                        g_warning ("%s: IPv4 metric invalid!", __func__);
                        g_free (addr);
                        g_free (next_hop);
diff --git a/src/connection-editor/ip6-routes-dialog.c b/src/connection-editor/ip6-routes-dialog.c
index 29108c7..1a3242f 100644
--- a/src/connection-editor/ip6-routes-dialog.c
+++ b/src/connection-editor/ip6-routes-dialog.c
@@ -56,15 +56,19 @@ get_one_int (GtkTreeModel *model,
              int column,
              guint32 max_value,
              gboolean fail_if_missing,
-             guint *out)
+             guint *out,
+             char **out_raw)
 {
        char *item = NULL;
        gboolean success = FALSE;
        long int tmp_int;
 
        gtk_tree_model_get (model, iter, column, &item, -1);
+       if (out_raw)
+               *out_raw = item;
        if (!item || !strlen (item)) {
-               g_free (item);
+               if (!out_raw)
+                       g_free (item);
                return fail_if_missing ? FALSE : TRUE;
        }
 
@@ -77,7 +81,8 @@ get_one_int (GtkTreeModel *model,
        success = TRUE;
 
 out:
-       g_free (item);
+       if (!out_raw)
+               g_free (item);
        return success;
 }
 
@@ -86,14 +91,18 @@ get_one_addr (GtkTreeModel *model,
               GtkTreeIter *iter,
               int column,
               gboolean fail_if_missing,
-              char **out)
+              char **out,
+              char **out_raw)
 {
        char *item = NULL;
        struct in6_addr tmp_addr;
 
        gtk_tree_model_get (model, iter, column, &item, -1);
+       if (out_raw)
+               *out_raw = item;
        if (!item || !strlen (item)) {
-               g_free (item);
+               if (!out_raw)
+                       g_free (item);
                return fail_if_missing ? FALSE : TRUE;
        }
 
@@ -101,7 +110,8 @@ get_one_addr (GtkTreeModel *model,
                return FALSE;
 
        if (IN6_IS_ADDR_UNSPECIFIED (&tmp_addr)) {
-               g_free (item);
+               if (!out_raw)
+                       g_free (item);
                return fail_if_missing ? FALSE : TRUE;
        }
 
@@ -133,22 +143,22 @@ validate (GtkWidget *dialog)
                guint prefix = 0, metric = 0;
 
                /* Address */
-               if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &dest))
+               if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &dest, NULL))
                        goto done;
                g_free (dest);
 
                /* Prefix */
-               if (   !get_one_int (model, &tree_iter, COL_PREFIX, 128, TRUE, &prefix)
+               if (   !get_one_int (model, &tree_iter, COL_PREFIX, 128, TRUE, &prefix, NULL)
                    || prefix == 0)
                        goto done;
 
                /* Next hop (optional) */
-               if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop))
+               if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop, NULL))
                        goto done;
                g_free (next_hop);
 
                /* Metric (optional) */
-               if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric))
+               if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, NULL))
                        goto done;
 
                iter_valid = gtk_tree_model_iter_next (model, &tree_iter);
@@ -581,6 +591,39 @@ tree_view_button_pressed_cb (GtkWidget *widget,
        return FALSE;
 }
 
+static void
+cell_error_data_func (GtkTreeViewColumn *tree_column,
+                      GtkCellRenderer *cell,
+                      GtkTreeModel *tree_model,
+                      GtkTreeIter *iter,
+                      gpointer data)
+{
+       guint32 col = GPOINTER_TO_UINT (data);
+       char *value = NULL;
+       char *addr, *next_hop;
+       guint32 prefix, metric;
+       const char *color = "red";
+       gboolean invalid = FALSE;
+
+       if (col == COL_ADDRESS)
+               invalid = !get_one_addr (tree_model, iter, COL_ADDRESS, TRUE, &addr, &value);
+       else if (col == COL_PREFIX)
+               invalid =    !get_one_int (tree_model, iter, COL_PREFIX, 128, TRUE, &prefix, &value)
+                         || prefix == 0;
+       else if (col == COL_NEXT_HOP)
+               invalid = !get_one_addr (tree_model, iter, COL_NEXT_HOP, FALSE, &next_hop, &value);
+       else if (col == COL_METRIC)
+               invalid = !get_one_int (tree_model, iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, &value);
+       else
+               g_warn_if_reached ();
+
+       if (invalid)
+               utils_set_cell_background (cell, color, value);
+       else
+               utils_set_cell_background (cell, NULL, NULL);
+       g_free (value);
+}
+
 GtkWidget *
 ip6_routes_dialog_new (NMSettingIPConfig *s_ip6, gboolean automatic)
 {
@@ -672,6 +715,8 @@ ip6_routes_dialog_new (NMSettingIPConfig *s_ip6, gboolean automatic)
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_ADDRESS), NULL);
 
        /* Prefix column */
        renderer = gtk_cell_renderer_text_new ();
@@ -689,6 +734,8 @@ ip6_routes_dialog_new (NMSettingIPConfig *s_ip6, gboolean automatic)
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_PREFIX), NULL);
 
        /* Gateway column */
        renderer = gtk_cell_renderer_text_new ();
@@ -706,6 +753,8 @@ ip6_routes_dialog_new (NMSettingIPConfig *s_ip6, gboolean automatic)
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_NEXT_HOP), NULL);
 
        /* Metric column */
        renderer = gtk_cell_renderer_text_new ();
@@ -723,6 +772,8 @@ ip6_routes_dialog_new (NMSettingIPConfig *s_ip6, gboolean automatic)
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_METRIC), NULL);
 
        g_object_set_data_full (G_OBJECT (dialog), "renderers", renderers, (GDestroyNotify) g_slist_free);
 
@@ -783,13 +834,13 @@ ip6_routes_dialog_update_setting (GtkWidget *dialog, NMSettingIPConfig *s_ip6)
                NMIPRoute *route;
 
                /* Address */
-               if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &dest)) {
+               if (!get_one_addr (model, &tree_iter, COL_ADDRESS, TRUE, &dest, NULL)) {
                        g_warning ("%s: IPv6 address missing or invalid!", __func__);
                        goto next;
                }
 
                /* Prefix */
-               if (   !get_one_int (model, &tree_iter, COL_PREFIX, 128, TRUE, &prefix)
+               if (   !get_one_int (model, &tree_iter, COL_PREFIX, 128, TRUE, &prefix, NULL)
                    || prefix == 0) {
                        g_warning ("%s: IPv6 prefix missing or invalid!", __func__);
                        g_free (dest);
@@ -797,14 +848,14 @@ ip6_routes_dialog_update_setting (GtkWidget *dialog, NMSettingIPConfig *s_ip6)
                }
 
                /* Next hop (optional) */
-               if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop)) {
+               if (!get_one_addr (model, &tree_iter, COL_NEXT_HOP, FALSE, &next_hop, NULL)) {
                        g_warning ("%s: IPv6 next hop invalid!", __func__);
                        g_free (dest);
                        goto next;
                }
 
                /* Metric (optional) */
-               if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric)) {
+               if (!get_one_int (model, &tree_iter, COL_METRIC, G_MAXUINT32, FALSE, &metric, NULL)) {
                        g_warning ("%s: IPv6 metric invalid!", __func__);
                        g_free (dest);
                        g_free (next_hop);
diff --git a/src/connection-editor/page-ip4.c b/src/connection-editor/page-ip4.c
index 66e2085..07d4eac 100644
--- a/src/connection-editor/page-ip4.c
+++ b/src/connection-editor/page-ip4.c
@@ -662,6 +662,9 @@ parse_netmask (const char *str, guint32 *prefix)
        struct in_addr tmp_addr;
        glong tmp_prefix;
 
+       if (!str || !*str)
+               return FALSE;
+
        errno = 0;
 
        /* Is it a prefix? */
@@ -882,6 +885,37 @@ tree_view_button_pressed_cb (GtkWidget *widget,
 }
 
 static void
+cell_error_data_func (GtkTreeViewColumn *tree_column,
+                      GtkCellRenderer *cell,
+                      GtkTreeModel *tree_model,
+                      GtkTreeIter *iter,
+                      gpointer data)
+{
+       guint32 col = GPOINTER_TO_UINT (data);
+       char *value = NULL;
+       const char *color = "red";
+       guint32 prefix;
+       gboolean invalid = FALSE;
+
+       gtk_tree_model_get (tree_model, iter, col, &value, -1);
+
+       if (col == COL_ADDRESS)
+               invalid = !value || !*value || !nm_utils_ipaddr_valid (AF_INET, value);
+       else if (col == COL_PREFIX)
+               invalid = !parse_netmask (value, &prefix);
+       else if (col == COL_GATEWAY)
+               invalid = value && *value && !nm_utils_ipaddr_valid (AF_INET, value);
+       else
+               g_warn_if_reached ();
+
+       if (invalid)
+               utils_set_cell_background (cell, color, value);
+       else
+               utils_set_cell_background (cell, NULL, NULL);
+       g_free (value);
+}
+
+static void
 finish_setup (CEPageIP4 *self, gpointer unused, GError *error, gpointer user_data)
 {
        CEPageIP4Private *priv = CE_PAGE_IP4_GET_PRIVATE (self);
@@ -911,6 +945,8 @@ finish_setup (CEPageIP4 *self, gpointer unused, GError *error, gpointer user_dat
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_ADDRESS), NULL);
 
        /* Prefix/netmask column */
        renderer = gtk_cell_renderer_text_new ();
@@ -928,6 +964,8 @@ finish_setup (CEPageIP4 *self, gpointer unused, GError *error, gpointer user_dat
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_PREFIX), NULL);
 
        /* Gateway column */
        renderer = gtk_cell_renderer_text_new ();
@@ -945,6 +983,8 @@ finish_setup (CEPageIP4 *self, gpointer unused, GError *error, gpointer user_dat
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_GATEWAY), NULL);
 
        g_signal_connect (priv->addr_list, "button-press-event", G_CALLBACK (tree_view_button_pressed_cb), 
self);
 
@@ -1091,7 +1131,7 @@ ui_to_setting (CEPageIP4 *self)
                        goto out;
                }
 
-               if (!netmask || !parse_netmask (netmask, &prefix)) {
+               if (!parse_netmask (netmask, &prefix)) {
                        g_warning ("%s: IPv4 prefix '%s' missing or invalid!",
                                   __func__, netmask ? netmask : "<none>");
                        g_free (addr);
diff --git a/src/connection-editor/page-ip6.c b/src/connection-editor/page-ip6.c
index 7c031a0..4e71712 100644
--- a/src/connection-editor/page-ip6.c
+++ b/src/connection-editor/page-ip6.c
@@ -455,6 +455,25 @@ populate_ui (CEPageIP6 *self)
                                      !nm_setting_ip_config_get_may_fail (setting));
 }
 
+static gboolean
+is_prefix_valid (const char *prefix_str, guint32 *out_prefix)
+{
+       guint32 prefix;
+       char *end;
+
+       if (!prefix_str || !*prefix_str)
+               return FALSE;
+
+       prefix = strtoul (prefix_str, &end, 10);
+       if (!end || *end || prefix == 0 || prefix > 128)
+               return FALSE;
+       else {
+               if (out_prefix)
+                       *out_prefix = prefix;
+               return TRUE;
+       }
+}
+
 static void
 addr_add_clicked (GtkButton *button, gpointer user_data)
 {
@@ -676,18 +695,11 @@ cell_changed_cb (GtkEditable *editable,
 
        cell_text = gtk_editable_get_chars (editable, 0, -1);
 
-       /* The Prefix column is 0..128 */
+       /* The Prefix column is 1..128 */
        column = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (user_data), "column"));
-       if (column == COL_PREFIX) {
-               guint32 prefix;
-               char *end;
-
-               prefix = strtoul (cell_text, &end, 10);
-               if (!end || *end || prefix == 0 || prefix > 128)
-                       value_valid = FALSE;
-               else
-                       value_valid = TRUE;
-       } else {
+       if (column == COL_PREFIX)
+               value_valid = is_prefix_valid (cell_text, NULL);
+       else {
                struct in6_addr tmp_addr;
 
                if (inet_pton (AF_INET6, cell_text, &tmp_addr))
@@ -874,6 +886,36 @@ tree_view_button_pressed_cb (GtkWidget *widget,
 }
 
 static void
+cell_error_data_func (GtkTreeViewColumn *tree_column,
+                      GtkCellRenderer *cell,
+                      GtkTreeModel *tree_model,
+                      GtkTreeIter *iter,
+                      gpointer data)
+{
+       guint32 col = GPOINTER_TO_UINT (data);
+       char *value = NULL;
+       const char *color = "red";
+       gboolean invalid = FALSE;
+
+       gtk_tree_model_get (tree_model, iter, col, &value, -1);
+
+       if (col == COL_ADDRESS)
+               invalid = !value || !*value || !nm_utils_ipaddr_valid (AF_INET6, value);
+       else if (col == COL_PREFIX)
+               invalid = !is_prefix_valid (value, NULL);
+       else if (col == COL_GATEWAY)
+               invalid = value && *value && !nm_utils_ipaddr_valid (AF_INET6, value);
+       else
+               g_warn_if_reached ();
+
+       if (invalid)
+               utils_set_cell_background (cell, color, value);
+       else
+               utils_set_cell_background (cell, NULL, NULL);
+       g_free (value);
+}
+
+static void
 finish_setup (CEPageIP6 *self, gpointer unused, GError *error, gpointer user_data)
 {
        CEPageIP6Private *priv = CE_PAGE_IP6_GET_PRIVATE (self);
@@ -903,6 +945,8 @@ finish_setup (CEPageIP6 *self, gpointer unused, GError *error, gpointer user_dat
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_ADDRESS), NULL);
 
        /* Prefix column */
        renderer = gtk_cell_renderer_text_new ();
@@ -920,6 +964,8 @@ finish_setup (CEPageIP6 *self, gpointer unused, GError *error, gpointer user_dat
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_PREFIX), NULL);
 
        /* Gateway column */
        renderer = gtk_cell_renderer_text_new ();
@@ -937,6 +983,8 @@ finish_setup (CEPageIP6 *self, gpointer unused, GError *error, gpointer user_dat
        column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->addr_list), offset - 1);
        gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
        gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
+       gtk_tree_view_column_set_cell_data_func (column, renderer, cell_error_data_func,
+                                                GUINT_TO_POINTER (COL_GATEWAY), NULL);
 
        g_signal_connect (priv->addr_list, "button-press-event", G_CALLBACK (tree_view_button_pressed_cb), 
self);
 
@@ -1060,7 +1108,7 @@ ui_to_setting (CEPageIP6 *self)
        model = gtk_tree_view_get_model (priv->addr_list);
        iter_valid = gtk_tree_model_get_iter_first (model, &tree_iter);
        while (iter_valid) {
-               char *addr_str = NULL, *prefix_str = NULL, *addr_gw_str = NULL, *end;
+               char *addr_str = NULL, *prefix_str = NULL, *addr_gw_str = NULL;
                NMIPAddress *addr;
                guint32 prefix;
 
@@ -1079,18 +1127,11 @@ ui_to_setting (CEPageIP6 *self)
                        goto out;
                }
 
-               if (!prefix_str) {
-                       g_warning ("%s: IPv6 prefix missing!", __func__);
-                       g_free (addr_str);
-                       g_free (prefix_str);
-                       g_free (addr_gw_str);
-                       goto out;
-               }
-
-               prefix = strtoul (prefix_str, &end, 10);
-               if (!end || *end || prefix == 0 || prefix > 128) {
-                       g_warning ("%s: IPv6 prefix '%s' invalid!",
-                                  __func__, prefix_str);
+               if (!is_prefix_valid (prefix_str, &prefix)) {
+                       if (!prefix_str)
+                               g_warning ("%s: IPv6 prefix missing!", __func__);
+                       else
+                               g_warning ("%s: IPv6 prefix '%s' invalid!", __func__, prefix_str);
                        g_free (addr_str);
                        g_free (prefix_str);
                        g_free (addr_gw_str);
diff --git a/src/utils/utils.c b/src/utils/utils.c
index c9301fe..64ceee8 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -517,3 +517,25 @@ utils_override_bg_color (GtkWidget *widget, GdkRGBA *rgba)
                gtk_css_provider_load_from_data (provider, "", -1, NULL);
 }
 
+void
+utils_set_cell_background (GtkCellRenderer *cell,
+                           const char *color,
+                           const char *value)
+{
+       if (color) {
+               if (!value || !*value) {
+                       g_object_set (G_OBJECT (cell),
+                                     "cell-background-set", TRUE,
+                                     "cell-background", color,
+                                     NULL);
+               } else {
+                       char *markup;
+                       markup = g_markup_printf_escaped ("<span background='%s'>%s</span>",
+                                                         color, value);
+                       g_object_set (G_OBJECT (cell), "markup", markup, NULL);
+                       g_free (markup);
+                       g_object_set (G_OBJECT (cell), "cell-background-set", FALSE, NULL);
+               }
+       } else
+               g_object_set (G_OBJECT (cell), "cell-background-set", FALSE, NULL);
+}
diff --git a/src/utils/utils.h b/src/utils/utils.h
index 3e3d31b..6d4147f 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -101,6 +101,9 @@ void utils_update_password_storage (NMSetting *setting,
                                     const char *password_flags_name);
 
 void utils_override_bg_color (GtkWidget *widget, GdkRGBA *rgba);
+void utils_set_cell_background (GtkCellRenderer *cell,
+                                const char *color,
+                                const char *value);
 
 #endif /* UTILS_H */
 


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