[gnome-control-center] network: Use a table-like widget to edit routes



commit 08657fac44d056b48feef7a61adfb0bd4723c0eb
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Tue May 23 13:04:52 2017 -0300

    network: Use a table-like widget to edit routes
    
    According to the latest mockups for the connection editor dialog [1],
    the IPv4 and IPv6 pages are supposed to use a table-like editor to
    manage the routes. This editor is not only easier to comprehend, but
    also improves the size of the dialog, requiring much less vertical
    space to present the routes.
    
    The current implementation, however, uses a vertical layout and a toolbar,
    which is inefficient in its usage of space.
    
    Fix that by implementing the table-like editor widget, both in IPv4
    and IPv6 pages.
    
    [1] 
https://raw.githubusercontent.com/gnome-design-team/gnome-mockups/master/system-settings/network/aday2/network-wires.png
    
    https://bugzilla.gnome.org/show_bug.cgi?id=779841

 panels/network/connection-editor/ce-page-ip4.c |  123 ++++++++++++++----------
 panels/network/connection-editor/ce-page-ip6.c |  123 ++++++++++++++----------
 panels/network/connection-editor/ip4-page.ui   |  108 +++++++++++++++++----
 panels/network/connection-editor/ip6-page.ui   |  108 +++++++++++++++++----
 4 files changed, 320 insertions(+), 142 deletions(-)
---
diff --git a/panels/network/connection-editor/ce-page-ip4.c b/panels/network/connection-editor/ce-page-ip4.c
index fe6b81b..4e7eb7a 100644
--- a/panels/network/connection-editor/ce-page-ip4.c
+++ b/panels/network/connection-editor/ce-page-ip4.c
@@ -34,6 +34,8 @@
 
 #define RADIO_IS_ACTIVE(x) (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(CE_PAGE 
(page)->builder, x))))
 
+static void ensure_empty_routes_row (CEPageIP4 *page);
+
 G_DEFINE_TYPE (CEPageIP4, ce_page_ip4, CE_TYPE_PAGE)
 
 enum {
@@ -88,7 +90,7 @@ static void
 update_row_sensitivity (CEPageIP4 *page, GtkWidget *list)
 {
         GList *children, *l;
-        gint rows = 0;
+        gint rows = 0, i = 0;
 
         children = gtk_container_get_children (GTK_CONTAINER (list));
         for (l = children; l; l = l->next) {
@@ -105,7 +107,7 @@ update_row_sensitivity (CEPageIP4 *page, GtkWidget *list)
 
                 button = GTK_WIDGET (g_object_get_data (G_OBJECT (row), "delete-button"));
                 if (button != NULL)
-                        gtk_widget_set_sensitive (button, rows > 1);
+                        gtk_widget_set_sensitive (button, rows > 1 && ++i < rows);
         }
         g_list_free (children);
 }
@@ -152,6 +154,29 @@ remove_row (GtkButton *button, CEPageIP4 *page)
                 update_row_gateway_visibility (page);
 }
 
+static gboolean
+validate_row (GtkWidget *row)
+{
+        GtkWidget *box;
+        GList *children, *l;
+        gboolean valid;
+
+        valid = FALSE;
+        box = gtk_bin_get_child (GTK_BIN (row));
+        children = gtk_container_get_children (GTK_CONTAINER (box));
+
+        for (l = children; l != NULL; l = l->next) {
+                if (!GTK_IS_ENTRY (l->data))
+                        continue;
+
+                valid = valid || gtk_entry_get_text_length (l->data) > 0;
+        }
+
+        g_list_free (children);
+
+        return valid;
+}
+
 static gint
 sort_first_last (gconstpointer a, gconstpointer b, gpointer data)
 {
@@ -235,6 +260,7 @@ add_address_row (CEPageIP4   *page,
         gtk_widget_set_no_show_all (widget, FALSE);
 
         delete_button = gtk_button_new ();
+        gtk_widget_set_sensitive (delete_button, FALSE);
         gtk_style_context_add_class (gtk_widget_get_style_context (delete_button), "image-button");
         g_signal_connect (delete_button, "clicked", G_CALLBACK (remove_row), page);
         image = gtk_image_new_from_icon_name ("user-trash-symbolic", GTK_ICON_SIZE_MENU);
@@ -382,92 +408,76 @@ add_route_row (CEPageIP4   *page,
                const gchar *gateway,
                gint         metric)
 {
+        GtkSizeGroup *group;
         GtkWidget *row;
-        GtkWidget *row_grid;
-        GtkWidget *label;
+        GtkWidget *row_box;
         GtkWidget *widget;
         GtkWidget *delete_button;
         GtkWidget *image;
 
         row = gtk_list_box_row_new ();
 
-        row_grid = gtk_grid_new ();
-        label = gtk_label_new (_("Address"));
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID (row_grid), label, 1, 1, 1, 1);
+        row_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+        gtk_style_context_add_class (gtk_widget_get_style_context (row_box), "linked");
+
         widget = gtk_entry_new ();
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
         g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), page);
+        g_signal_connect_swapped (widget, "activate", G_CALLBACK (ensure_empty_routes_row), page);
         g_object_set_data (G_OBJECT (row), "address", widget);
         gtk_entry_set_text (GTK_ENTRY (widget), address);
-        gtk_widget_set_margin_start (widget, 10);
-        gtk_widget_set_margin_end (widget, 10);
+        gtk_entry_set_width_chars (GTK_ENTRY (widget), 16);
         gtk_widget_set_hexpand (widget, TRUE);
-        gtk_grid_attach (GTK_GRID (row_grid), widget, 2, 1, 1, 1);
+        gtk_container_add (GTK_CONTAINER (row_box), widget);
 
-        label = gtk_label_new (_("Netmask"));
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID (row_grid), label, 1, 2, 1, 1);
         widget = gtk_entry_new ();
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
         g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), page);
+        g_signal_connect_swapped (widget, "activate", G_CALLBACK (ensure_empty_routes_row), page);
         g_object_set_data (G_OBJECT (row), "netmask", widget);
         gtk_entry_set_text (GTK_ENTRY (widget), netmask);
-        gtk_widget_set_margin_start (widget, 10);
-        gtk_widget_set_margin_end (widget, 10);
+        gtk_entry_set_width_chars (GTK_ENTRY (widget), 16);
         gtk_widget_set_hexpand (widget, TRUE);
-        gtk_grid_attach (GTK_GRID (row_grid), widget, 2, 2, 1, 1);
+        gtk_container_add (GTK_CONTAINER (row_box), widget);
 
-        label = gtk_label_new (_("Gateway"));
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID (row_grid), label, 1, 3, 1, 1);
         widget = gtk_entry_new ();
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
         g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), page);
+        g_signal_connect_swapped (widget, "activate", G_CALLBACK (ensure_empty_routes_row), page);
         g_object_set_data (G_OBJECT (row), "gateway", widget);
         gtk_entry_set_text (GTK_ENTRY (widget), gateway);
-        gtk_widget_set_margin_start (widget, 10);
-        gtk_widget_set_margin_end (widget, 10);
+        gtk_entry_set_width_chars (GTK_ENTRY (widget), 16);
         gtk_widget_set_hexpand (widget, TRUE);
-        gtk_grid_attach (GTK_GRID (row_grid), widget, 2, 3, 1, 1);
+        gtk_container_add (GTK_CONTAINER (row_box), widget);
 
-        /* Translators: Please see https://en.wikipedia.org/wiki/Metrics_(networking) */
-        label = gtk_label_new (C_("network parameters", "Metric"));
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID (row_grid), label, 1, 4, 1, 1);
         widget = gtk_entry_new ();
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
         g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), page);
+        g_signal_connect_swapped (widget, "activate", G_CALLBACK (ensure_empty_routes_row), page);
         g_object_set_data (G_OBJECT (row), "metric", widget);
         if (metric >= 0) {
                 gchar *s = g_strdup_printf ("%d", metric);
                 gtk_entry_set_text (GTK_ENTRY (widget), s);
                 g_free (s);
         }
-        gtk_widget_set_margin_start (widget, 10);
-        gtk_widget_set_margin_end (widget, 10);
+        gtk_entry_set_width_chars (GTK_ENTRY (widget), 5);
         gtk_widget_set_hexpand (widget, TRUE);
-        gtk_grid_attach (GTK_GRID (row_grid), widget, 2, 4, 1, 1);
+        gtk_container_add (GTK_CONTAINER (row_box), widget);
+
+        group = GTK_SIZE_GROUP (gtk_builder_get_object (CE_PAGE (page)->builder, "routes_metric_sizegroup"));
+        gtk_size_group_add_widget (group, widget);
 
         delete_button = gtk_button_new ();
         gtk_style_context_add_class (gtk_widget_get_style_context (delete_button), "image-button");
         g_signal_connect (delete_button, "clicked", G_CALLBACK (remove_row), page);
-        image = gtk_image_new_from_icon_name ("user-trash-symbolic", GTK_ICON_SIZE_MENU);
+        image = gtk_image_new_from_icon_name ("edit-delete-symbolic", GTK_ICON_SIZE_MENU);
         atk_object_set_name (gtk_widget_get_accessible (delete_button), _("Delete Route"));
         gtk_button_set_image (GTK_BUTTON (delete_button), image);
         gtk_widget_set_halign (delete_button, GTK_ALIGN_CENTER);
         gtk_widget_set_valign (delete_button, GTK_ALIGN_CENTER);
-        gtk_grid_attach (GTK_GRID (row_grid), delete_button, 3, 1, 1, 4);
+        gtk_container_add (GTK_CONTAINER (row_box), delete_button);
         g_object_set_data (G_OBJECT (row), "delete-button", delete_button);
 
-        gtk_grid_set_row_spacing (GTK_GRID (row_grid), 10);
-        gtk_widget_set_margin_start (row_grid, 10);
-        gtk_widget_set_margin_end (row_grid, 10);
-        gtk_widget_set_margin_top (row_grid, 10);
-        gtk_widget_set_margin_bottom (row_grid, 10);
-        gtk_widget_set_halign (row_grid, GTK_ALIGN_FILL);
+        group = GTK_SIZE_GROUP (gtk_builder_get_object (CE_PAGE (page)->builder, "routes_sizegroup"));
+        gtk_size_group_add_widget (group, delete_button);
 
-        gtk_container_add (GTK_CONTAINER (row), row_grid);
+        gtk_container_add (GTK_CONTAINER (row), row_box);
         gtk_widget_show_all (row);
         gtk_container_add (GTK_CONTAINER (page->routes_list), row);
 
@@ -475,33 +485,41 @@ add_route_row (CEPageIP4   *page,
 }
 
 static void
-add_empty_route_row (CEPageIP4 *page)
+ensure_empty_routes_row (CEPageIP4 *page)
 {
-        add_route_row (page, "", "", "", -1);
+        GList *children, *l;
+
+        children = gtk_container_get_children (GTK_CONTAINER (page->routes_list));
+        l = children;
+
+        while (l && l->next)
+                l = l->next;
+
+        /* Add the last, stub row if needed*/
+        if (!l || validate_row (l->data))
+                add_route_row (page, "", "", "", -1);
+
+        g_list_free (children);
 }
 
 static void
 add_routes_section (CEPageIP4 *page)
 {
         GtkWidget *widget;
-        GtkWidget *frame;
         GtkWidget *list;
         gint i;
 
         widget = GTK_WIDGET (gtk_builder_get_object (CE_PAGE (page)->builder, "routes_section"));
 
-        frame = gtk_frame_new (NULL);
-        gtk_container_add (GTK_CONTAINER (widget), frame);
         page->routes_list = list = gtk_list_box_new ();
         gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_NONE);
         gtk_list_box_set_header_func (GTK_LIST_BOX (list), cc_list_box_update_header_func, NULL, NULL);
         gtk_list_box_set_sort_func (GTK_LIST_BOX (list), (GtkListBoxSortFunc)sort_first_last, NULL, NULL);
-        gtk_container_add (GTK_CONTAINER (frame), list);
+        gtk_container_add (GTK_CONTAINER (widget), list);
         page->auto_routes = GTK_SWITCH (gtk_builder_get_object (CE_PAGE (page)->builder, 
"auto_routes_switch"));
         gtk_switch_set_active (page->auto_routes, !nm_setting_ip_config_get_ignore_auto_routes 
(page->setting));
         g_signal_connect (page->auto_routes, "notify::active", G_CALLBACK (switch_toggled), page);
 
-        add_section_toolbar (page, widget, G_CALLBACK (add_empty_route_row));
 
         for (i = 0; i < nm_setting_ip_config_get_num_routes (page->setting); i++) {
                 NMIPRoute *route;
@@ -522,7 +540,7 @@ add_routes_section (CEPageIP4 *page)
                                nm_ip_route_get_metric (route));
         }
         if (nm_setting_ip_config_get_num_routes (page->setting) == 0)
-                add_empty_route_row (page);
+                ensure_empty_routes_row (page);
 
         gtk_widget_show_all (widget);
 }
@@ -842,6 +860,9 @@ ui_to_setting (CEPageIP4 *page)
                 route = nm_ip_route_new (AF_INET, text_address, netmask, text_gateway, metric, NULL);
                 if (route)
                         g_ptr_array_add (routes, route);
+
+                if (!l || !l->next)
+                        ensure_empty_routes_row (page);
         }
         g_list_free (children);
 
diff --git a/panels/network/connection-editor/ce-page-ip6.c b/panels/network/connection-editor/ce-page-ip6.c
index c194e64..2c82067 100644
--- a/panels/network/connection-editor/ce-page-ip6.c
+++ b/panels/network/connection-editor/ce-page-ip6.c
@@ -34,6 +34,8 @@
 
 #define RADIO_IS_ACTIVE(x) (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object(CE_PAGE 
(page)->builder, x))))
 
+static void ensure_empty_routes_row (CEPageIP6 *page);
+
 G_DEFINE_TYPE (CEPageIP6, ce_page_ip6, CE_TYPE_PAGE)
 
 enum {
@@ -89,7 +91,7 @@ static void
 update_row_sensitivity (CEPageIP6 *page, GtkWidget *list)
 {
         GList *children, *l;
-        gint rows = 0;
+        gint rows = 0, i = 0;
 
         children = gtk_container_get_children (GTK_CONTAINER (list));
         for (l = children; l; l = l->next) {
@@ -106,7 +108,7 @@ update_row_sensitivity (CEPageIP6 *page, GtkWidget *list)
 
                 button = GTK_WIDGET (g_object_get_data (G_OBJECT (row), "delete-button"));
                 if (button != NULL)
-                        gtk_widget_set_sensitive (button, rows > 1);
+                        gtk_widget_set_sensitive (button, rows > 1 && ++i < rows);
         }
         g_list_free (children);
 }
@@ -129,6 +131,29 @@ remove_row (GtkButton *button, CEPageIP6 *page)
         update_row_sensitivity (page, list);
 }
 
+static gboolean
+validate_row (GtkWidget *row)
+{
+        GtkWidget *box;
+        GList *children, *l;
+        gboolean valid;
+
+        valid = FALSE;
+        box = gtk_bin_get_child (GTK_BIN (row));
+        children = gtk_container_get_children (GTK_CONTAINER (box));
+
+        for (l = children; l != NULL; l = l->next) {
+                if (!GTK_IS_ENTRY (l->data))
+                        continue;
+
+                valid = valid || gtk_entry_get_text_length (l->data) > 0;
+        }
+
+        g_list_free (children);
+
+        return valid;
+}
+
 static gint
 sort_first_last (gconstpointer a, gconstpointer b, gpointer data)
 {
@@ -347,88 +372,72 @@ add_route_row (CEPageIP6   *page,
                const gchar *gateway,
                const gchar *metric)
 {
+        GtkSizeGroup *group;
         GtkWidget *row;
-        GtkWidget *row_grid;
-        GtkWidget *label;
+        GtkWidget *row_box;
         GtkWidget *widget;
         GtkWidget *delete_button;
         GtkWidget *image;
 
         row = gtk_list_box_row_new ();
 
-        row_grid = gtk_grid_new ();
-        label = gtk_label_new (_("Address"));
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID (row_grid), label, 1, 1, 1, 1);
+        row_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+        gtk_style_context_add_class (gtk_widget_get_style_context (row_box), "linked");
+
         widget = gtk_entry_new ();
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
         g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), page);
+        g_signal_connect_swapped (widget, "activate", G_CALLBACK (ensure_empty_routes_row), page);
         g_object_set_data (G_OBJECT (row), "address", widget);
         gtk_entry_set_text (GTK_ENTRY (widget), address);
-        gtk_widget_set_margin_start (widget, 10);
-        gtk_widget_set_margin_end (widget, 10);
+        gtk_entry_set_width_chars (GTK_ENTRY (widget), 16);
         gtk_widget_set_hexpand (widget, TRUE);
-        gtk_grid_attach (GTK_GRID (row_grid), widget, 2, 1, 1, 1);
+        gtk_container_add (GTK_CONTAINER (row_box), widget);
 
-        label = gtk_label_new (_("Prefix"));
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID (row_grid), label, 1, 2, 1, 1);
         widget = gtk_entry_new ();
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
         g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), page);
+        g_signal_connect_swapped (widget, "activate", G_CALLBACK (ensure_empty_routes_row), page);
         g_object_set_data (G_OBJECT (row), "prefix", widget);
         gtk_entry_set_text (GTK_ENTRY (widget), prefix ? prefix : "");
-        gtk_widget_set_margin_start (widget, 10);
-        gtk_widget_set_margin_end (widget, 10);
+        gtk_entry_set_width_chars (GTK_ENTRY (widget), 16);
         gtk_widget_set_hexpand (widget, TRUE);
-        gtk_grid_attach (GTK_GRID (row_grid), widget, 2, 2, 1, 1);
+        gtk_container_add (GTK_CONTAINER (row_box), widget);
 
-        label = gtk_label_new (_("Gateway"));
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID (row_grid), label, 1, 3, 1, 1);
         widget = gtk_entry_new ();
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
         g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), page);
+        g_signal_connect_swapped (widget, "activate", G_CALLBACK (ensure_empty_routes_row), page);
         g_object_set_data (G_OBJECT (row), "gateway", widget);
         gtk_entry_set_text (GTK_ENTRY (widget), gateway);
-        gtk_widget_set_margin_start (widget, 10);
-        gtk_widget_set_margin_end (widget, 10);
+        gtk_entry_set_width_chars (GTK_ENTRY (widget), 16);
         gtk_widget_set_hexpand (widget, TRUE);
-        gtk_grid_attach (GTK_GRID (row_grid), widget, 2, 3, 1, 1);
+        gtk_container_add (GTK_CONTAINER (row_box), widget);
 
-        /* Translators: Please see https://en.wikipedia.org/wiki/Metrics_(networking) */
-        label = gtk_label_new (C_("network parameters", "Metric"));
-        gtk_widget_set_halign (label, GTK_ALIGN_END);
-        gtk_grid_attach (GTK_GRID (row_grid), label, 1, 4, 1, 1);
         widget = gtk_entry_new ();
-        gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
         g_signal_connect_swapped (widget, "changed", G_CALLBACK (ce_page_changed), page);
+        g_signal_connect_swapped (widget, "activate", G_CALLBACK (ensure_empty_routes_row), page);
         g_object_set_data (G_OBJECT (row), "metric", widget);
         gtk_entry_set_text (GTK_ENTRY (widget), metric ? metric : "");
-        gtk_widget_set_margin_start (widget, 10);
-        gtk_widget_set_margin_end (widget, 10);
+        gtk_entry_set_width_chars (GTK_ENTRY (widget), 5);
         gtk_widget_set_hexpand (widget, TRUE);
-        gtk_grid_attach (GTK_GRID (row_grid), widget, 2, 4, 1, 1);
+        gtk_container_add (GTK_CONTAINER (row_box), widget);
+
+        group = GTK_SIZE_GROUP (gtk_builder_get_object (CE_PAGE (page)->builder, "routes_metric_sizegroup"));
+        gtk_size_group_add_widget (group, widget);
 
         delete_button = gtk_button_new ();
         gtk_style_context_add_class (gtk_widget_get_style_context (delete_button), "image-button");
         g_signal_connect (delete_button, "clicked", G_CALLBACK (remove_row), page);
-        image = gtk_image_new_from_icon_name ("user-trash-symbolic", GTK_ICON_SIZE_MENU);
+        image = gtk_image_new_from_icon_name ("edit-delete-symbolic", GTK_ICON_SIZE_MENU);
         atk_object_set_name (gtk_widget_get_accessible (delete_button), _("Delete Route"));
         gtk_button_set_image (GTK_BUTTON (delete_button), image);
         gtk_widget_set_halign (delete_button, GTK_ALIGN_CENTER);
         gtk_widget_set_valign (delete_button, GTK_ALIGN_CENTER);
-        gtk_grid_attach (GTK_GRID (row_grid), delete_button, 3, 1, 1, 4);
+        gtk_container_add (GTK_CONTAINER (row_box), delete_button);
         g_object_set_data (G_OBJECT (row), "delete-button", delete_button);
 
-        gtk_grid_set_row_spacing (GTK_GRID (row_grid), 10);
-        gtk_widget_set_margin_start (row_grid, 10);
-        gtk_widget_set_margin_end (row_grid, 10);
-        gtk_widget_set_margin_top (row_grid, 10);
-        gtk_widget_set_margin_bottom (row_grid, 10);
-        gtk_widget_set_halign (row_grid, GTK_ALIGN_FILL);
+        group = GTK_SIZE_GROUP (gtk_builder_get_object (CE_PAGE (page)->builder, "routes_sizegroup"));
+        gtk_size_group_add_widget (group, delete_button);
 
-        gtk_container_add (GTK_CONTAINER (row), row_grid);
+        gtk_container_add (GTK_CONTAINER (row), row_box);
         gtk_widget_show_all (row);
         gtk_container_add (GTK_CONTAINER (page->routes_list), row);
 
@@ -436,6 +445,24 @@ add_route_row (CEPageIP6   *page,
 }
 
 static void
+ensure_empty_routes_row (CEPageIP6 *page)
+{
+        GList *children, *l;
+
+        children = gtk_container_get_children (GTK_CONTAINER (page->routes_list));
+        l = children;
+
+        while (l && l->next)
+                l = l->next;
+
+        /* Add the last, stub row if needed*/
+        if (!l || validate_row (l->data))
+                add_route_row (page, "", NULL, "", NULL);
+
+        g_list_free (children);
+}
+
+static void
 add_empty_route_row (CEPageIP6 *page)
 {
         add_route_row (page, "", NULL, "", NULL);
@@ -445,25 +472,20 @@ static void
 add_routes_section (CEPageIP6 *page)
 {
         GtkWidget *widget;
-        GtkWidget *frame;
         GtkWidget *list;
         gint i;
 
         widget = GTK_WIDGET (gtk_builder_get_object (CE_PAGE (page)->builder, "routes_section"));
 
-        frame = gtk_frame_new (NULL);
-        gtk_container_add (GTK_CONTAINER (widget), frame);
         page->routes_list = list = gtk_list_box_new ();
         gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_NONE);
         gtk_list_box_set_header_func (GTK_LIST_BOX (list), cc_list_box_update_header_func, NULL, NULL);
         gtk_list_box_set_sort_func (GTK_LIST_BOX (list), (GtkListBoxSortFunc)sort_first_last, NULL, NULL);
-        gtk_container_add (GTK_CONTAINER (frame), list);
+        gtk_container_add (GTK_CONTAINER (widget), list);
         page->auto_routes = GTK_SWITCH (gtk_builder_get_object (CE_PAGE (page)->builder, 
"auto_routes_switch"));
         gtk_switch_set_active (page->auto_routes, !nm_setting_ip_config_get_ignore_auto_routes 
(page->setting));
         g_signal_connect (page->auto_routes, "notify::active", G_CALLBACK (switch_toggled), page);
 
-        add_section_toolbar (page, widget, G_CALLBACK (add_empty_route_row));
-
         for (i = 0; i < nm_setting_ip_config_get_num_routes (page->setting); i++) {
                 NMIPRoute *route;
                 char *prefix, *metric;
@@ -778,6 +800,9 @@ ui_to_setting (CEPageIP6 *page)
                 route = nm_ip_route_new (AF_INET6, text_address, prefix, text_gateway, metric, NULL);
                 nm_setting_ip_config_add_route (page->setting, route);
                 nm_ip_route_unref (route);
+
+                if (!l || !l->next)
+                        ensure_empty_routes_row (page);
         }
         g_list_free (children);
 
diff --git a/panels/network/connection-editor/ip4-page.ui b/panels/network/connection-editor/ip4-page.ui
index a6538b6..932357d 100644
--- a/panels/network/connection-editor/ip4-page.ui
+++ b/panels/network/connection-editor/ip4-page.ui
@@ -182,62 +182,47 @@
                   </object>
                 </child>
                 <child>
-                  <object class="GtkBox" id="box3">
+                  <object class="GtkBox">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="margin_top">24</property>
-                    <property name="margin_bottom">5</property>
                     <property name="spacing">6</property>
                     <child>
                       <object class="GtkLabel" id="heading_routes">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="xalign">0</property>
+                        <property name="hexpand">True</property>
                         <property name="label" translatable="yes">Routes</property>
                         <attributes>
                           <attribute name="weight" value="bold"/>
                         </attributes>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel" id="label2">
+                      <object class="GtkLabel">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="hexpand">True</property>
                         <property name="xalign">1</property>
                         <property name="label" translatable="yes">Automatic</property>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkSwitch" id="auto_routes_switch">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
+                        <property name="halign">end</property>
+                        <property name="valign">center</property>
                         <child internal-child="accessible">
                           <object class="AtkObject" id="auto_routes_switch-accessible">
                             <property name="accessible-name" translatable="yes">Automatic Routes</property>
                           </object>
                         </child>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
-                      </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
                     <property name="position">5</property>
                   </packing>
                 </child>
@@ -247,7 +232,76 @@
                     <property name="can_focus">False</property>
                     <property name="orientation">vertical</property>
                     <child>
-                      <placeholder/>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">horizontal</property>
+                        <child>
+                          <object class="GtkLabel" id="routes_address_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label" translatable="yes">Address</property>
+                            <style>
+                              <class name="dim-label" />
+                            </style>
+                            <attributes>
+                              <attribute name="scale" value="0.8"/>
+                            </attributes>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="routes_netmask_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label" translatable="yes">Netmask</property>
+                            <style>
+                              <class name="dim-label" />
+                            </style>
+                            <attributes>
+                              <attribute name="scale" value="0.8"/>
+                            </attributes>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="routes_gateway_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label" translatable="yes">Gateway</property>
+                            <style>
+                              <class name="dim-label" />
+                            </style>
+                            <attributes>
+                              <attribute name="scale" value="0.8"/>
+                            </attributes>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="routes_metric_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes" comments="Translators: Please see 
https://en.wikipedia.org/wiki/Metrics_(networking)">Metric</property>
+                            <style>
+                              <class name="dim-label" />
+                            </style>
+                            <attributes>
+                              <attribute name="scale" value="0.8"/>
+                            </attributes>
+                          </object>
+                        </child>
+
+                        <!-- This invisible box is used to add some width in the
+                             end of the header row, assuming the space used by the
+                             delete button in the rows -->
+                        <child>
+                          <object class="GtkBox" id="routes_stub_box">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                        </child>
+                      </object>
                     </child>
                   </object>
                   <packing>
@@ -284,4 +338,16 @@
       </object>
     </child>
   </object>
+  <object class="GtkSizeGroup" id="routes_metric_sizegroup">
+    <property name="mode">horizontal</property>
+    <widgets>
+      <widget name="routes_metric_label" />
+    </widgets>
+  </object>
+  <object class="GtkSizeGroup" id="routes_sizegroup">
+    <property name="mode">horizontal</property>
+    <widgets>
+      <widget name="routes_stub_box" />
+    </widgets>
+  </object>
 </interface>
diff --git a/panels/network/connection-editor/ip6-page.ui b/panels/network/connection-editor/ip6-page.ui
index 8cf5a88..2d1b71e 100644
--- a/panels/network/connection-editor/ip6-page.ui
+++ b/panels/network/connection-editor/ip6-page.ui
@@ -196,62 +196,47 @@
                   </object>
                 </child>
                 <child>
-                  <object class="GtkBox" id="box3">
+                  <object class="GtkBox">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="margin_top">24</property>
-                    <property name="margin_bottom">5</property>
                     <property name="spacing">6</property>
                     <child>
                       <object class="GtkLabel" id="heading_routes">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="xalign">0</property>
+                        <property name="hexpand">True</property>
                         <property name="label" translatable="yes">Routes</property>
                         <attributes>
                           <attribute name="weight" value="bold"/>
                         </attributes>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
                     </child>
                     <child>
-                      <object class="GtkLabel" id="label2">
+                      <object class="GtkLabel">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                         <property name="hexpand">True</property>
                         <property name="xalign">1</property>
                         <property name="label" translatable="yes">Automatic</property>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
                     </child>
                     <child>
                       <object class="GtkSwitch" id="auto_routes_switch">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
+                        <property name="halign">end</property>
+                        <property name="valign">center</property>
                         <child internal-child="accessible">
                           <object class="AtkObject" id="auto_routes_switch-accessible">
                             <property name="accessible-name" translatable="yes">Automatic Routes</property>
                           </object>
                         </child>
                       </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">2</property>
-                      </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
                     <property name="position">5</property>
                   </packing>
                 </child>
@@ -261,7 +246,76 @@
                     <property name="can_focus">False</property>
                     <property name="orientation">vertical</property>
                     <child>
-                      <placeholder/>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="orientation">horizontal</property>
+                        <child>
+                          <object class="GtkLabel" id="routes_address_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label" translatable="yes">Address</property>
+                            <style>
+                              <class name="dim-label" />
+                            </style>
+                            <attributes>
+                              <attribute name="scale" value="0.8"/>
+                            </attributes>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="routes_prefix_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label" translatable="yes">Prefix</property>
+                            <style>
+                              <class name="dim-label" />
+                            </style>
+                            <attributes>
+                              <attribute name="scale" value="0.8"/>
+                            </attributes>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="routes_gateway_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label" translatable="yes">Gateway</property>
+                            <style>
+                              <class name="dim-label" />
+                            </style>
+                            <attributes>
+                              <attribute name="scale" value="0.8"/>
+                            </attributes>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="routes_metric_label">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label" translatable="yes" comments="Translators: Please see 
https://en.wikipedia.org/wiki/Metrics_(networking)">Metric</property>
+                            <style>
+                              <class name="dim-label" />
+                            </style>
+                            <attributes>
+                              <attribute name="scale" value="0.8"/>
+                            </attributes>
+                          </object>
+                        </child>
+
+                        <!-- This invisible box is used to add some width in the
+                             end of the header row, assuming the space used by the
+                             delete button in the rows -->
+                        <child>
+                          <object class="GtkBox" id="routes_stub_box">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                        </child>
+                      </object>
                     </child>
                   </object>
                   <packing>
@@ -298,4 +352,16 @@
       </object>
     </child>
   </object>
+  <object class="GtkSizeGroup" id="routes_metric_sizegroup">
+    <property name="mode">horizontal</property>
+    <widgets>
+      <widget name="routes_metric_label" />
+    </widgets>
+  </object>
+  <object class="GtkSizeGroup" id="routes_sizegroup">
+    <property name="mode">horizontal</property>
+    <widgets>
+      <widget name="routes_stub_box" />
+    </widgets>
+  </object>
 </interface>



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