[network-manager-applet/new-editor: 4/7] connection-editor: redo as a single page with a tree of connections



commit af8a4aeca75a14f8f137faf0498de7d03a438c6b
Author: Dan Winship <danw gnome org>
Date:   Fri Feb 17 09:09:41 2012 -0500

    connection-editor: redo as a single page with a tree of connections
    
    In preparation for adding additional connection types, change the
    connection editor to a single list of connections, grouped by type.

 po/POTFILES.in                                |    1 +
 src/connection-editor/Makefile.am             |    4 +-
 src/connection-editor/new-connection.c        |  219 +++++++
 src/connection-editor/new-connection.h        |   47 ++
 src/connection-editor/nm-connection-editor.ui |  465 ++++-----------
 src/connection-editor/nm-connection-list.c    |  772 +++++++++++--------------
 src/connection-editor/nm-connection-list.h    |   14 +-
 7 files changed, 734 insertions(+), 788 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5ac6bf6..60251b4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -31,6 +31,7 @@ src/connection-editor/ce-page.c
 [type: gettext/glade]src/connection-editor/ce-vpn-wizard.ui
 src/connection-editor/ip4-routes-dialog.c
 src/connection-editor/ip6-routes-dialog.c
+src/connection-editor/new-connection.c
 src/connection-editor/page-dsl.c
 src/connection-editor/page-ip4.c
 src/connection-editor/page-ip6.c
diff --git a/src/connection-editor/Makefile.am b/src/connection-editor/Makefile.am
index d26b674..df2b026 100644
--- a/src/connection-editor/Makefile.am
+++ b/src/connection-editor/Makefile.am
@@ -55,7 +55,9 @@ nm_connection_editor_SOURCES = \
 	ppp-auth-methods-dialog.c \
 	ppp-auth-methods-dialog.h \
 	ce-polkit-button.c \
-	ce-polkit-button.h
+	ce-polkit-button.h \
+	new-connection.c \
+	new-connection.h
 
 nm-connection-editor-service-glue.h: $(top_srcdir)/src/connection-editor/nm-connection-editor-service.xml
 	$(AM_V_GEN) dbus-binding-tool --prefix=nm_connection_editor_service --mode=glib-server --output=$@ $<
diff --git a/src/connection-editor/new-connection.c b/src/connection-editor/new-connection.c
new file mode 100644
index 0000000..54d1c5c
--- /dev/null
+++ b/src/connection-editor/new-connection.c
@@ -0,0 +1,219 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2012 Red Hat, Inc.
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+
+#include "new-connection.h"
+#include "nm-connection-list.h"
+#include "page-wired.h"
+#include "page-wireless.h"
+#include "page-mobile.h"
+#include "page-dsl.h"
+#include "page-vpn.h"
+#include "vpn-helpers.h"
+
+#define COL_ICON     0
+#define COL_LABEL    1
+#define COL_NEW_FUNC 2
+
+#define ICON_LOAD(x, y)	\
+	{ \
+		x = gtk_icon_theme_load_icon (theme, y, 16, 0, &error); \
+		if (x == NULL) { \
+			g_warning ("Icon %s missing: %s", y, error->message); \
+			g_error_free (error); \
+		} \
+	}
+
+ConnectionTypeData *
+get_connection_type_list (void)
+{
+	GArray *array;
+	ConnectionTypeData data;
+	static ConnectionTypeData *list;
+	static GtkIconTheme *theme;
+	GError *error = NULL;
+	GHashTable *vpn_plugins;
+	gboolean have_vpn_plugins;
+
+	if (list)
+		return list;
+
+	array = g_array_new (TRUE, FALSE, sizeof (ConnectionTypeData));
+	theme = gtk_icon_theme_get_default ();
+
+	data.name = _("Wired");
+	ICON_LOAD (data.icon, "nm-device-wired");
+	data.new_connection_func = wired_connection_new;
+	data.setting_type = NM_TYPE_SETTING_WIRED;
+	g_array_append_val (array, data);
+
+	data.name = _("Wireless");
+	ICON_LOAD (data.icon, "nm-device-wireless");
+	data.new_connection_func = wifi_connection_new;
+	data.setting_type = NM_TYPE_SETTING_WIRELESS;
+	g_array_append_val (array, data);
+
+	data.name = _("Mobile Broadband");
+	ICON_LOAD (data.icon, "nm-device-wwan");
+	data.new_connection_func = mobile_connection_new;
+	data.setting_type = NM_TYPE_SETTING_GSM;
+	g_array_append_val (array, data);
+
+	data.name = _("DSL");
+	ICON_LOAD (data.icon, "nm-device-wired");
+	data.new_connection_func = dsl_connection_new;
+	data.setting_type = NM_TYPE_SETTING_PPPOE;
+	g_array_append_val (array, data);
+
+	/* Add "VPN" only if there are plugins */
+	vpn_plugins = vpn_get_plugins (NULL);
+	have_vpn_plugins = vpn_plugins && g_hash_table_size (vpn_plugins);
+	if (have_vpn_plugins) {
+		data.name = _("VPN");
+		ICON_LOAD (data.icon, "nm-vpn-standalone-lock");
+		data.new_connection_func = vpn_connection_new;
+		data.setting_type = NM_TYPE_SETTING_VPN;
+		g_array_append_val (array, data);
+	}
+
+	return (ConnectionTypeData *)g_array_free (array, FALSE);
+}
+
+static void
+fill_connection_type_model (GtkComboBox *combo)
+{
+	GtkListStore *model = GTK_LIST_STORE (gtk_combo_box_get_model (combo));
+	ConnectionTypeData *list = get_connection_type_list ();
+	GtkTreeIter iter;
+	int i;
+
+	for (i = 0; list[i].name; i++) {
+		gtk_list_store_append (model, &iter);
+		gtk_list_store_set (model, &iter,
+		                    COL_ICON, list[i].icon,
+		                    COL_LABEL, list[i].name,
+		                    COL_NEW_FUNC, list[i].new_connection_func,
+		                    -1);
+	}
+}
+
+typedef struct {
+	GtkWindow *parent_window;
+	NMRemoteSettings *settings;
+	PageNewConnectionResultFunc result_func;
+	gpointer user_data;
+} NewConnectionData;
+
+static GSList *
+new_connection_get_connections (gpointer user_data)
+{
+	NewConnectionData *ncd = user_data;
+
+	return nm_remote_settings_list_connections (ncd->settings);
+}
+
+static void
+new_connection_result (NMConnection *connection,
+                       gboolean canceled,
+                       GError *error,
+                       gpointer user_data)
+{
+	NewConnectionData *ncd = user_data;
+	PageNewConnectionResultFunc result_func;
+
+	result_func = ncd->result_func;
+	user_data = ncd->user_data;
+	g_slice_free (NewConnectionData, ncd);
+
+	result_func (connection, canceled, error, user_data);
+}
+
+void
+new_connection_of_type (GtkWindow *parent_window,
+                        NMRemoteSettings *settings,
+                        PageNewConnectionFunc new_func,
+                        PageNewConnectionResultFunc result_func,
+                        gpointer user_data)
+{
+	NewConnectionData *ncd;
+
+	ncd = g_slice_new (NewConnectionData);
+	ncd->parent_window = parent_window;
+	ncd->settings = settings;
+	ncd->result_func = result_func;
+	ncd->user_data = user_data;
+
+	new_func (parent_window,
+	          new_connection_result,
+	          new_connection_get_connections,
+	          ncd);
+}
+
+void
+new_connection_dialog (GtkWindow *parent_window,
+                       NMRemoteSettings *settings,
+                       PageNewConnectionResultFunc result_func,
+                       gpointer user_data)
+{
+	const char *objects[] = { "new-connection-dialog", "new-connection-combo-model", NULL };
+	GtkBuilder *gui;
+	GtkDialog *type_dialog;
+	GtkComboBox *combo;
+	GtkTreeIter iter;
+	int response;
+	PageNewConnectionFunc new_func = NULL;
+	GError *error = NULL;
+
+	/* load GUI */
+	gui = gtk_builder_new ();
+	if (!gtk_builder_add_objects_from_file (gui,
+	                                        UIDIR "/nm-connection-editor.ui",
+	                                        (char **) objects,
+	                                        &error)) {
+		g_warning ("Couldn't load builder file: %s", error->message);
+		g_error_free (error);
+		g_object_unref (gui);
+		return;
+	}
+
+	type_dialog = GTK_DIALOG (gtk_builder_get_object (gui, "new-connection-dialog"));
+	gtk_window_set_transient_for (GTK_WINDOW (type_dialog), parent_window);
+
+	combo = GTK_COMBO_BOX (gtk_builder_get_object (gui, "new-connection-combo"));
+	fill_connection_type_model (combo);
+	gtk_combo_box_set_active (combo, 0);
+
+	response = gtk_dialog_run (type_dialog);
+	if (response == GTK_RESPONSE_OK) {
+		gtk_combo_box_get_active_iter (combo, &iter);
+		gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
+		                    COL_NEW_FUNC, &new_func,
+		                    -1);
+	}
+
+	gtk_widget_destroy (GTK_WIDGET (type_dialog));
+	g_object_unref (gui);
+
+	if (new_func)
+		new_connection_of_type (parent_window, settings, new_func, result_func, user_data);
+}
diff --git a/src/connection-editor/new-connection.h b/src/connection-editor/new-connection.h
new file mode 100644
index 0000000..429e9bb
--- /dev/null
+++ b/src/connection-editor/new-connection.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager Connection editor -- Connection editor for NetworkManager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2012 Red Hat, Inc.
+ */
+
+#ifndef __CONNECTION_HELPERS_H__
+#define __CONNECTION_HELPERS_H__
+
+#include "ce-page.h"
+#include <nm-remote-settings.h>
+
+typedef struct {
+	const char *name;
+	GdkPixbuf *icon;
+	GType setting_type;
+	PageNewConnectionFunc new_connection_func;
+} ConnectionTypeData;
+
+ConnectionTypeData *get_connection_type_list (void);
+
+void new_connection_dialog  (GtkWindow *parent_window,
+                             NMRemoteSettings *settings,
+                             PageNewConnectionResultFunc result_func,
+                             gpointer user_data);
+void new_connection_of_type (GtkWindow *parent_window,
+                             NMRemoteSettings *settings,
+                             PageNewConnectionFunc new_func,
+                             PageNewConnectionResultFunc result_func,
+                             gpointer user_data);
+
+#endif  /* __CONNECTION_HELPERS_H__ */
+
diff --git a/src/connection-editor/nm-connection-editor.ui b/src/connection-editor/nm-connection-editor.ui
index 3406fb7..56d3d4b 100644
--- a/src/connection-editor/nm-connection-editor.ui
+++ b/src/connection-editor/nm-connection-editor.ui
@@ -46,409 +46,183 @@
           </packing>
         </child>
         <child>
-          <object class="GtkNotebook" id="list_notebook">
+          <object class="GtkHBox" id="hbox2">
             <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="border_width">5</property>
+            <property name="border_width">6</property>
+            <property name="spacing">6</property>
             <child>
-              <object class="GtkHBox" id="wired_child">
+              <object class="GtkScrolledWindow" id="scrolledwindow1">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="border_width">6</property>
-                <property name="spacing">6</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="shadow_type">in</property>
                 <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow1">
+                  <object class="GtkTreeView" id="connection_list">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="wired_list">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="headers_visible">False</property>
-                        <property name="rules_hint">True</property>
-                        <child internal-child="selection">
-                          <object class="GtkTreeSelection" id="treeview-selection1"/>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkVButtonBox" id="wired_button_box">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="spacing">6</property>
-                    <property name="layout_style">start</property>
-                    <child>
-                      <object class="GtkButton" id="wired_add">
-                        <property name="label">gtk-add</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="can_default">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="use_stock">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
+                    <property name="rules_hint">True</property>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
                 </child>
               </object>
-            </child>
-            <child type="tab">
-              <object class="GtkLabel" id="wired_label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Wired</property>
-              </object>
               <packing>
-                <property name="tab_fill">False</property>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
               </packing>
             </child>
             <child>
-              <object class="GtkHBox" id="wireless_child">
+              <object class="GtkVButtonBox" id="connection_button_box">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="border_width">6</property>
                 <property name="spacing">6</property>
+                <property name="layout_style">start</property>
                 <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow2">
+                  <object class="GtkButton" id="connection_add">
+                    <property name="label">gtk-add</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="wireless_list">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="headers_visible">False</property>
-                        <property name="rules_hint">True</property>
-                        <child internal-child="selection">
-                          <object class="GtkTreeSelection" id="treeview-selection2"/>
-                        </child>
-                      </object>
-                    </child>
+                    <property name="can_default">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_stock">True</property>
                   </object>
                   <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
                     <property name="position">0</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkVButtonBox" id="wireless_button_box">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="spacing">6</property>
-                    <property name="layout_style">start</property>
-                    <child>
-                      <object class="GtkButton" id="wireless_add">
-                        <property name="label">gtk-add</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="can_default">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="use_stock">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child type="tab">
-              <object class="GtkLabel" id="wireless_label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Wireless</property>
-              </object>
-              <packing>
-                <property name="position">1</property>
-                <property name="tab_fill">False</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkHBox" id="wwan_child">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="border_width">6</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow3">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="wwan_list">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="headers_visible">False</property>
-                        <property name="rules_hint">True</property>
-                        <child internal-child="selection">
-                          <object class="GtkTreeSelection" id="treeview-selection3"/>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
+                  <placeholder/>
                 </child>
                 <child>
-                  <object class="GtkVButtonBox" id="wwan_button_box">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="spacing">6</property>
-                    <property name="layout_style">start</property>
-                    <child>
-                      <object class="GtkButton" id="wwan_add">
-                        <property name="label">gtk-add</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="can_default">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="use_stock">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
+                  <placeholder/>
                 </child>
               </object>
               <packing>
-                <property name="position">2</property>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
               </packing>
             </child>
-            <child type="tab">
-              <object class="GtkLabel" id="wwan_label">
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-7">closebutton1</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkListStore" id="new-connection-combo-model">
+    <columns>
+      <!-- column-name icon -->
+      <column type="GdkPixbuf"/>
+      <!-- column-name name -->
+      <column type="gchararray"/>
+      <!-- column-name new_func -->
+      <column type="gpointer"/>
+    </columns>
+  </object>
+  <object class="GtkDialog" id="new-connection-dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Create New Connection</property>
+    <property name="modal">True</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox4">
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area4">
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-cancel</property>
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">Mobile Broadband</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
               </object>
               <packing>
-                <property name="position">2</property>
-                <property name="tab_fill">False</property>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
               </packing>
             </child>
             <child>
-              <object class="GtkHBox" id="vpn_child">
+              <object class="GtkButton" id="button2">
+                <property name="label">gtk-add</property>
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="border_width">6</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow4">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="vpn_list">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="headers_visible">False</property>
-                        <property name="rules_hint">True</property>
-                        <child internal-child="selection">
-                          <object class="GtkTreeSelection" id="treeview-selection4"/>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkVButtonBox" id="vpn_button_box">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="spacing">6</property>
-                    <property name="layout_style">start</property>
-                    <child>
-                      <object class="GtkButton" id="vpn_add">
-                        <property name="label">gtk-add</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="can_default">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="use_stock">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
               </object>
               <packing>
-                <property name="position">3</property>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
               </packing>
             </child>
-            <child type="tab">
-              <object class="GtkLabel" id="vpn_label">
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="box1">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">10</property>
+            <child>
+              <object class="GtkLabel" id="label1">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">VPN</property>
+                <property name="label" translatable="yes">Select the type of connection to create:</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
               </object>
               <packing>
-                <property name="position">3</property>
-                <property name="tab_fill">False</property>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
               </packing>
             </child>
             <child>
-              <object class="GtkHBox" id="dsl_child">
+              <object class="GtkComboBox" id="new-connection-combo">
                 <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="border_width">6</property>
-                <property name="spacing">6</property>
+                <property name="model">new-connection-combo-model</property>
                 <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow5">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="shadow_type">in</property>
-                    <child>
-                      <object class="GtkTreeView" id="dsl_list">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="headers_visible">False</property>
-                        <property name="rules_hint">True</property>
-                        <child internal-child="selection">
-                          <object class="GtkTreeSelection" id="treeview-selection5"/>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
+                  <object class="GtkCellRendererPixbuf" id="renderer1"/>
+                  <attributes>
+                    <attribute name="pixbuf">0</attribute>
+                  </attributes>
                 </child>
                 <child>
-                  <object class="GtkVButtonBox" id="dsl_button_box">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="spacing">6</property>
-                    <property name="layout_style">start</property>
-                    <child>
-                      <object class="GtkButton" id="dsl_add">
-                        <property name="label">gtk-add</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="can_default">True</property>
-                        <property name="receives_default">False</property>
-                        <property name="use_action_appearance">False</property>
-                        <property name="use_stock">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">False</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
+                  <object class="GtkCellRendererText" id="renderer2"/>
+                  <attributes>
+                    <attribute name="text">1</attribute>
+                  </attributes>
                 </child>
               </object>
               <packing>
-                <property name="position">4</property>
-              </packing>
-            </child>
-            <child type="tab">
-              <object class="GtkLabel" id="dsl_label">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">DSL</property>
-              </object>
-              <packing>
-                <property name="position">4</property>
-                <property name="tab_fill">False</property>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
               </packing>
             </child>
           </object>
           <packing>
-            <property name="expand">True</property>
+            <property name="expand">False</property>
             <property name="fill">True</property>
             <property name="position">1</property>
           </packing>
@@ -456,7 +230,8 @@
       </object>
     </child>
     <action-widgets>
-      <action-widget response="-7">closebutton1</action-widget>
+      <action-widget response="-6">button1</action-widget>
+      <action-widget response="-5">button2</action-widget>
     </action-widgets>
   </object>
   <object class="GtkWindow" id="nm-connection-editor">
diff --git a/src/connection-editor/nm-connection-list.c b/src/connection-editor/nm-connection-list.c
index c9a0929..66163c0 100644
--- a/src/connection-editor/nm-connection-list.c
+++ b/src/connection-editor/nm-connection-list.c
@@ -55,6 +55,7 @@
 #include "nm-connection-list.h"
 #include "vpn-helpers.h"
 #include "ce-polkit-button.h"
+#include "new-connection.h"
 
 G_DEFINE_TYPE (NMConnectionList, nm_connection_list, G_TYPE_OBJECT)
 
@@ -66,18 +67,13 @@ enum {
 
 static guint list_signals[LIST_LAST_SIGNAL] = { 0 };
 
-#define COL_ID 			0
-#define COL_LAST_USED	1
-#define COL_TIMESTAMP	2
-#define COL_CONNECTION	3
-
-typedef struct {
-	NMConnectionList *list;
-	GtkTreeView *treeview;
-	GtkWindow *list_window;
-	GtkWidget *button;
-	PageNewConnectionFunc new_func;
-} ActionInfo;
+#define COL_ICON       0
+#define COL_ID         1
+#define COL_LAST_USED  2
+#define COL_TIMESTAMP  3
+#define COL_CONNECTION 4
+#define COL_GTYPE      5
+#define COL_ORDER      6
 
 static void
 error_dialog (GtkWindow *parent, const char *heading, const char *format, ...)
@@ -135,79 +131,35 @@ get_active_connection (GtkTreeView *treeview)
 	return connection;
 }
 
-#define TV_TYPE_TAG "ctype"
-
-static GtkTreeView *
-get_treeview_for_type (NMConnectionList *list, GType ctype)
-{
-	GSList *iter;
-
-	for (iter = list->treeviews; iter; iter = g_slist_next (iter)) {
-		GtkTreeView *candidate = GTK_TREE_VIEW (iter->data);
-		GType candidate_type;
-
-		candidate_type = GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (candidate), TV_TYPE_TAG));
-		if (candidate_type == ctype)
-			return candidate;
-	}
-
-	return NULL;
-}
-
-static GtkListStore *
-get_model_for_connection (NMConnectionList *list, NMRemoteConnection *connection)
-{
-	NMSettingConnection *s_con;
-	GtkTreeView *treeview;
-	GtkTreeModel *model;
-	const char *str_type;
-
-	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
-	g_assert (s_con);
-	str_type = nm_setting_connection_get_connection_type (s_con);
-
-	if (!str_type) {
-		g_warning ("Ignoring incomplete connection");
-		return NULL;
-	}
-
-	if (!strcmp (str_type, NM_SETTING_CDMA_SETTING_NAME))
-		str_type = NM_SETTING_GSM_SETTING_NAME;
-
-	treeview = get_treeview_for_type (list, nm_connection_lookup_setting_type (str_type));
-	if (!treeview)
-		return NULL;
-
-	model = gtk_tree_view_get_model (treeview);
-	if (GTK_IS_TREE_MODEL_SORT (model))
-		return GTK_LIST_STORE (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model)));
-
-	return GTK_LIST_STORE (model);
-}
-
 static gboolean
-get_iter_for_connection (GtkTreeModel *model,
+get_iter_for_connection (NMConnectionList *list,
                          NMRemoteConnection *connection,
                          GtkTreeIter *iter)
 {
-	GtkTreeIter temp_iter;
-	gboolean found = FALSE;
+	GtkTreeIter types_iter;
 
-	if (!gtk_tree_model_get_iter_first (model, &temp_iter))
+	if (!gtk_tree_model_get_iter_first (list->model, &types_iter))
 		return FALSE;
 
 	do {
-		NMRemoteConnection *candidate = NULL;
-
-		gtk_tree_model_get (model, &temp_iter, COL_CONNECTION, &candidate, -1);
-		if (candidate && (candidate == connection)) {
-			*iter = temp_iter;
-			found = TRUE;
-		}
-		g_object_unref (candidate);
-	} while (!found && gtk_tree_model_iter_next (model, &temp_iter));
-
-	return found;
+		if (!gtk_tree_model_iter_children (list->model, iter, &types_iter))
+			continue;
+
+		do {
+			NMRemoteConnection *candidate = NULL;
+
+			gtk_tree_model_get (list->model, iter,
+			                    COL_CONNECTION, &candidate,
+			                    -1);
+			if (candidate == connection) {
+				g_object_unref (candidate);
+				return TRUE;
+			}
+			g_object_unref (candidate);
+		} while (gtk_tree_model_iter_next (list->model, iter));
+	} while (gtk_tree_model_iter_next (list->model, &types_iter));
+
+	return FALSE;
 }
 
 static char *
@@ -283,24 +235,28 @@ out:
 }
 
 static void
-update_connection_row (GtkListStore *store,
+update_connection_row (NMConnectionList *self,
                        GtkTreeIter *iter,
                        NMRemoteConnection *connection)
 {
 	NMSettingConnection *s_con;
-	char *last_used;
+	char *last_used, *id;
 
 	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 	g_assert (s_con);
 
 	last_used = format_last_used (nm_setting_connection_get_timestamp (s_con));
-	gtk_list_store_set (store, iter,
-	                    COL_ID, nm_setting_connection_get_id (s_con),
+	id = g_markup_escape_text (nm_setting_connection_get_id (s_con), -1);
+	gtk_tree_store_set (GTK_TREE_STORE (self->model), iter,
+	                    COL_ID, id,
 	                    COL_LAST_USED, last_used,
 	                    COL_TIMESTAMP, nm_setting_connection_get_timestamp (s_con),
 	                    COL_CONNECTION, connection,
 	                    -1);
 	g_free (last_used);
+	g_free (id);
+
+	gtk_tree_model_filter_refilter (self->filter);
 }
 
 
@@ -498,7 +454,7 @@ add_finished_cb (NMConnectionList *list, GError *error, gpointer user_data)
 static void
 add_response_cb (NMConnectionEditor *editor, gint response, GError *error, gpointer user_data)
 {
-	ActionInfo *info = (ActionInfo *) user_data;
+	NMConnectionList *list = user_data;
 	GError *add_error = NULL;
 
 	/* if the dialog is busy waiting for authorization or something,
@@ -513,7 +469,7 @@ add_response_cb (NMConnectionEditor *editor, gint response, GError *error, gpoin
 			/* Yay we can try to add the connection; it'll get removed from
 			 * list->editors when the add finishes.
 			 */
-			add_connection (info->list, editor, add_finished_cb, editor);
+			add_connection (list, editor, add_finished_cb, editor);
 			return;
 		} else {
 			error_dialog (GTK_WINDOW (editor->window),
@@ -534,8 +490,8 @@ add_response_cb (NMConnectionEditor *editor, gint response, GError *error, gpoin
 		              "%s", message);
 	}
 
-	g_hash_table_remove (info->list->editors, nm_connection_editor_get_connection (editor));
-	g_signal_emit (info->list, list_signals[EDITING_DONE], 0, 0);
+	g_hash_table_remove (list->editors, nm_connection_editor_get_connection (editor));
+	g_signal_emit (list, list_signals[EDITING_DONE], 0, 0);
 }
 
 
@@ -545,72 +501,53 @@ really_add_connection (NMConnection *connection,
                        GError *error,
                        gpointer user_data)
 {
-	ActionInfo *info = user_data;
+	NMConnectionList *list = user_data;
 	NMConnectionEditor *editor;
 	GError *editor_error = NULL;
 	const char *message = _("The connection editor dialog could not be initialized due to an unknown error.");
 
-	g_return_if_fail (info != NULL);
-
 	if (canceled) {
-		g_signal_emit (info->list, list_signals[EDITING_DONE], 0, 0);
+		g_signal_emit (list, list_signals[EDITING_DONE], 0, 0);
 		return;
 	}
 
 	if (!connection) {
-		error_dialog (info->list_window,
+		error_dialog (GTK_WINDOW (list->dialog),
 		              _("Could not create new connection"),
 		              "%s",
 		              (error && error->message) ? error->message : message);
-		g_signal_emit (info->list, list_signals[EDITING_DONE], 0, 0);
+		g_signal_emit (list, list_signals[EDITING_DONE], 0, 0);
 		return;
 	}
 
-	editor = nm_connection_editor_new (connection, info->list->nm_client, &error);
+	editor = nm_connection_editor_new (connection, list->nm_client, &error);
 	if (!editor) {
 		g_object_unref (connection);
 
-		error_dialog (info->list_window,
+		error_dialog (GTK_WINDOW (list->dialog),
 		              _("Could not edit new connection"),
 		              "%s",
 		              (editor_error && editor_error->message) ? editor_error->message : message);
 		g_clear_error (&editor_error);
-		g_signal_emit (info->list, list_signals[EDITING_DONE], 0, 0);
+		g_signal_emit (list, list_signals[EDITING_DONE], 0, 0);
 		return;
 	}
 
-	g_signal_connect (editor, "done", G_CALLBACK (add_response_cb), info);
-	g_hash_table_insert (info->list->editors, connection, editor);
+	g_signal_connect (editor, "done", G_CALLBACK (add_response_cb), list);
+	g_hash_table_insert (list->editors, connection, editor);
 
 	nm_connection_editor_run (editor);
 }
 
-static GSList *
-page_get_connections (gpointer user_data)
-{
-	ActionInfo *info = (ActionInfo *) user_data;
-
-	return nm_remote_settings_list_connections (info->list->settings);
-}
-
 static void
 add_clicked (GtkButton *button, gpointer user_data)
 {
-	ActionInfo *info = (ActionInfo *) user_data;
-	NMConnectionList *list = info->list;
-	GType ctype;
-
-	if (!info->new_func) {
-		ctype = GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (info->treeview), TV_TYPE_TAG));
-		g_warning ("No new-connection function registered for type '%s'",
-		           g_type_name (ctype));
-		return;
-	}
+	NMConnectionList *list = user_data;
 
-	info->new_func (GTK_WINDOW (list->dialog),
-	                really_add_connection,
-	                page_get_connections,
-	                info);
+	new_connection_dialog (GTK_WINDOW (list->dialog),
+	                       list->settings,
+	                       really_add_connection,
+	                       list);
 }
 
 typedef struct {
@@ -625,7 +562,6 @@ connection_updated_cb (NMConnectionList *list,
                        gpointer user_data)
 {
 	EditInfo *info = user_data;
-	GtkListStore *store;
 	GtkTreeIter iter;
 
 	if (error) {
@@ -644,10 +580,8 @@ connection_updated_cb (NMConnectionList *list,
 	}
 
 	/* Success */
-	store = get_model_for_connection (list, connection);
-	g_assert (store);
-	if (get_iter_for_connection (GTK_TREE_MODEL (store), connection, &iter))
-		update_connection_row (store, &iter, connection);
+	if (get_iter_for_connection (list, connection, &iter))
+		update_connection_row (list, &iter, connection);
 
 	/* This callback might be triggered long after it's caller was called,
 	 * if for example we've had to get PolicyKit authentication to perform
@@ -716,7 +650,7 @@ edit_done_cb (NMConnectionEditor *editor, gint response, GError *error, gpointer
 }
 
 static void
-edit_connection (ActionInfo *info, NMConnection *connection)
+edit_connection (NMConnectionList *list, NMConnection *connection)
 {
 	NMConnectionEditor *editor;
 	EditInfo *edit_info;
@@ -726,15 +660,15 @@ edit_connection (ActionInfo *info, NMConnection *connection)
 	g_return_if_fail (connection != NULL);
 
 	/* Don't allow two editors for the same connection */
-	editor = (NMConnectionEditor *) g_hash_table_lookup (info->list->editors, connection);
+	editor = (NMConnectionEditor *) g_hash_table_lookup (list->editors, connection);
 	if (editor) {
 		nm_connection_editor_present (editor);
 		return;
 	}
 
-	editor = nm_connection_editor_new (NM_CONNECTION (connection), info->list->nm_client, &error);
+	editor = nm_connection_editor_new (NM_CONNECTION (connection), list->nm_client, &error);
 	if (!editor) {
-		error_dialog (info->list_window,
+		error_dialog (GTK_WINDOW (list->dialog),
 		              _("Could not edit connection"),
 		              "%s",
 		              (error && error->message) ? error->message : message);
@@ -742,19 +676,19 @@ edit_connection (ActionInfo *info, NMConnection *connection)
 	}
 
 	edit_info = g_malloc0 (sizeof (EditInfo));
-	edit_info->list = info->list;
+	edit_info->list = list;
 	edit_info->editor = editor;
 
 	g_signal_connect (editor, "done", G_CALLBACK (edit_done_cb), edit_info);
-	g_hash_table_insert (info->list->editors, connection, editor);
+	g_hash_table_insert (list->editors, connection, editor);
 
 	nm_connection_editor_run (editor);
 }
 
 static void
-do_edit (ActionInfo *info)
+do_edit (NMConnectionList *list)
 {
-	edit_connection (info, NM_CONNECTION (get_active_connection (info->treeview)));
+	edit_connection (list, NM_CONNECTION (get_active_connection (list->connection_list)));
 }
 
 static void
@@ -771,7 +705,7 @@ delete_result_cb (NMConnectionList *list,
 static void
 delete_clicked (GtkButton *button, gpointer user_data)
 {
-	ActionInfo *info = (ActionInfo *) user_data;
+	NMConnectionList *list = user_data;
 	NMRemoteConnection *connection;
 	NMConnectionEditor *editor;
 	NMSettingConnection *s_con;
@@ -779,10 +713,10 @@ delete_clicked (GtkButton *button, gpointer user_data)
 	const char *id;
 	guint result;
 
-	connection = get_active_connection (info->treeview);
+	connection = get_active_connection (list->connection_list);
 	g_return_if_fail (connection != NULL);
 
-	editor = g_hash_table_lookup (info->list->editors, connection);
+	editor = g_hash_table_lookup (list->editors, connection);
 	if (editor && nm_connection_editor_get_busy (editor)) {
 		/* Editor already has an operation in progress, raise it */
 		nm_connection_editor_present (editor);
@@ -793,7 +727,7 @@ delete_clicked (GtkButton *button, gpointer user_data)
 	g_assert (s_con);
 	id = nm_setting_connection_get_id (s_con);
 
-	dialog = gtk_message_dialog_new (GTK_WINDOW (info->list->dialog),
+	dialog = gtk_message_dialog_new (GTK_WINDOW (list->dialog),
 	                                 GTK_DIALOG_DESTROY_WITH_PARENT,
 	                                 GTK_MESSAGE_QUESTION,
 	                                 GTK_BUTTONS_NONE,
@@ -803,23 +737,24 @@ delete_clicked (GtkButton *button, gpointer user_data)
 	                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 	                        GTK_STOCK_DELETE, GTK_RESPONSE_YES,
 	                        NULL);
-	gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (info->list->dialog));
+	gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (list->dialog));
 
 	result = gtk_dialog_run (GTK_DIALOG (dialog));
 	gtk_widget_destroy (dialog);
 
 	if (result == GTK_RESPONSE_YES) {
-		delete_connection (info->list,
+		delete_connection (list,
 		                   connection,
 		                   delete_result_cb,
-		                   GTK_WINDOW (info->list->dialog));
+		                   GTK_WINDOW (list->dialog));
 	}
 }
 
 static void
 pk_button_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
 {
-	ActionInfo *info = (ActionInfo *) user_data;
+	CEPolkitButton *button = user_data;
+	NMConnectionList *list = g_object_get_data (G_OBJECT (button), "NMConnectionList");
 	GtkTreeIter iter;
 	GtkTreeModel *model;
 	NMRemoteConnection *connection;
@@ -827,7 +762,7 @@ pk_button_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
 	gboolean sensitive = FALSE;
 
 	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
-		connection = get_active_connection (info->treeview);
+		connection = get_active_connection (list->connection_list);
 		if (connection) {
 			s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 			g_assert (s_con);
@@ -836,7 +771,7 @@ pk_button_selection_changed_cb (GtkTreeSelection *selection, gpointer user_data)
 		}
 	}
 
-	ce_polkit_button_set_master_sensitive (CE_POLKIT_BUTTON (info->button), sensitive);
+	ce_polkit_button_set_master_sensitive (button, sensitive);
 }
 
 static void
@@ -845,10 +780,10 @@ connection_double_clicked_cb (GtkTreeView *tree_view,
                               GtkTreeViewColumn *column,
                               gpointer user_data)
 {
-	ActionInfo *info = user_data;
+	GtkButton *button = user_data;
 
-	if (ce_polkit_button_get_actionable (CE_POLKIT_BUTTON (info->button)))
-		gtk_button_clicked (GTK_BUTTON (info->button));
+	if (ce_polkit_button_get_actionable (CE_POLKIT_BUTTON (button)))
+		gtk_button_clicked (button);
 }
 
 static void
@@ -873,27 +808,11 @@ dispose (GObject *object)
 	if (list->editors)
 		g_hash_table_destroy (list->editors);
 
-	if (list->actions)
-		g_hash_table_destroy (list->actions);
-
-	if (list->wired_icon)
-		g_object_unref (list->wired_icon);
-	if (list->wireless_icon)
-		g_object_unref (list->wireless_icon);
-	if (list->wwan_icon)
-		g_object_unref (list->wwan_icon);
-	if (list->vpn_icon)
-		g_object_unref (list->vpn_icon);
-	if (list->unknown_icon)
-		g_object_unref (list->unknown_icon);
-
 	if (list->gui)
 		g_object_unref (list->gui);
 	if (list->nm_client)
 		g_object_unref (list->nm_client);
 
-	g_slist_free (list->treeviews);
-
 	if (list->settings)
 		g_object_unref (list->settings);
 
@@ -936,170 +855,205 @@ column_header_clicked_cb (GtkTreeViewColumn *treeviewcolumn, gpointer user_data)
 	gtk_tree_view_column_set_sort_column_id (treeviewcolumn, sort_col_id);
 }
 
-static GtkTreeView *
-add_connection_treeview (NMConnectionList *self, const char *prefix)
+static gint
+sort_connection_types (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
 {
-	GtkTreeModel *model;
-	GtkTreeModel *sort_model;
-	GtkCellRenderer *renderer;
-	GtkTreeSelection *selection;
-	GValue val = { 0, };
-	char *name;
-	GtkTreeView *treeview;
-	GtkTreeViewColumn *column1, *column2;
+	GtkTreeSortable *sortable = user_data;
+	int order_a, order_b;
+	GtkSortType order;
 
-	name = g_strdup_printf ("%s_list", prefix);
-	treeview = GTK_TREE_VIEW (GTK_WIDGET (gtk_builder_get_object (self->gui, name)));
-	g_free (name);
-	gtk_tree_view_set_headers_visible (treeview, TRUE);
+	gtk_tree_model_get (model, a, COL_ORDER, &order_a, -1);
+	gtk_tree_model_get (model, b, COL_ORDER, &order_b, -1);
 
+	/* The connection types should stay in the same order regardless of whether
+	 * the table is sorted ascending or descending.
+	 */
+	gtk_tree_sortable_get_sort_column_id (sortable, NULL, &order);
+	if (order == GTK_SORT_ASCENDING)
+		return order_a - order_b;
+	else
+		return order_b - order_a;
+}
 
-	/* Model */
-	model = GTK_TREE_MODEL (gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_OBJECT));
-	sort_model = gtk_tree_model_sort_new_with_model (model);
-	gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort_model), NULL, NULL, NULL);
-	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
-	                                      COL_TIMESTAMP, GTK_SORT_DESCENDING);
-	gtk_tree_view_set_model (treeview, sort_model);
+static gint
+id_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
+{
+	NMConnection *conn_a, *conn_b;
+	gint ret;
 
-	/* Name column */
-	gtk_tree_view_insert_column_with_attributes (treeview,
-	                                             -1, _("Name"), gtk_cell_renderer_text_new (),
-	                                             "text", COL_ID,
-	                                             NULL);
-	gtk_tree_view_column_set_expand (gtk_tree_view_get_column (treeview, 0), TRUE);
+	gtk_tree_model_get (model, a, COL_CONNECTION, &conn_a, -1);
+	gtk_tree_model_get (model, b, COL_CONNECTION, &conn_b, -1);
 
-	/* Last Used column */
-	renderer = gtk_cell_renderer_text_new ();
-	g_value_init (&val, G_TYPE_STRING);
-	g_value_set_string (&val, "SlateGray");
-	g_object_set_property (G_OBJECT (renderer), "foreground", &val);
+	if (!conn_a || !conn_b) {
+		g_assert (!conn_a && !conn_b);
+		return sort_connection_types (model, a, b, user_data);
+	}
 
-	gtk_tree_view_insert_column_with_attributes (treeview,
-	                                             -1, _("Last Used"), renderer,
-	                                             "text", COL_LAST_USED,
-	                                             NULL);
+	ret = strcmp (nm_connection_get_id (conn_a), nm_connection_get_id (conn_b));
+	g_object_unref (conn_a);
+	g_object_unref (conn_b);
 
-	/* Make columns clickable and sortable */
-	gtk_tree_view_set_headers_clickable (treeview, TRUE);
-	column1 = gtk_tree_view_get_column (treeview, 0);
-	g_signal_connect (column1, "clicked", G_CALLBACK (column_header_clicked_cb), GINT_TO_POINTER (COL_ID));
-	gtk_tree_view_column_set_sort_column_id (column1, COL_ID);
+	return ret;
+}
 
-	column2 = gtk_tree_view_get_column (treeview, 1);
-	g_signal_connect (column2, "clicked", G_CALLBACK (column_header_clicked_cb), GINT_TO_POINTER (COL_TIMESTAMP));
-	gtk_tree_view_column_set_sort_column_id (column2, COL_TIMESTAMP);
+static gint
+timestamp_sort_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
+{
+	NMConnection *conn_a, *conn_b;
+	guint64 time_a, time_b;
 
-	/* Selection */
-	selection = gtk_tree_view_get_selection (treeview);
-	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+	gtk_tree_model_get (model, a,
+	                    COL_CONNECTION, &conn_a,
+	                    COL_TIMESTAMP, &time_a,
+	                    -1);
+	gtk_tree_model_get (model, b,
+	                    COL_CONNECTION, &conn_b,
+	                    COL_TIMESTAMP, &time_b,
+	                    -1);
 
-	return treeview;
+	if (!conn_a || !conn_b) {
+		g_assert (!conn_a && !conn_b);
+		return sort_connection_types (model, a, b, user_data);
+	}
+
+	g_object_unref (conn_a);
+	g_object_unref (conn_b);
+
+	return time_b - time_a;
 }
 
 static void
-action_info_free (ActionInfo *info)
+name_column_data_func (GtkTreeViewColumn *tree_column,
+                       GtkCellRenderer *cell,
+                       GtkTreeModel *tree_model,
+                       GtkTreeIter *iter,
+                       gpointer data)
 {
-	g_return_if_fail (info != NULL);
-	g_free (info);
-}
+	GdkPixbuf *icon;
 
-static char *
-get_action_name (GType ctype, const char *action)
-{
-	return g_strdup_printf ("%s_%s", g_type_name (ctype), action);
+	gtk_tree_model_get (tree_model, iter,
+	                    COL_ICON, &icon,
+	                    -1);
+	g_object_set (G_OBJECT (cell),
+	              "pixbuf", icon,
+	              "visible", icon != NULL,
+	              NULL);
+	if (icon)
+		g_object_unref (icon);
 }
 
-static ActionInfo *
-find_action_info (NMConnectionList *list, GType ctype, const char *action)
+static gboolean
+tree_model_visible_func (GtkTreeModel *model,
+                         GtkTreeIter *iter,
+                         gpointer user_data)
 {
-	ActionInfo *ret;
-	char *name;
+	NMConnection *connection;
 
-	name = get_action_name (ctype, action);
-	ret = g_hash_table_lookup (list->actions, name);
-	g_free (name);
-	return ret;
+	gtk_tree_model_get (model, iter, COL_CONNECTION, &connection, -1);
+	if (connection) {
+		g_object_unref (connection);
+		return TRUE;
+	} else {
+		/* Top-level type nodes are visible iff they have children */
+		return gtk_tree_model_iter_has_child  (model, iter);
+	}
 }
 
-static ActionInfo *
-action_info_new (NMConnectionList *list,
-                 gchar *action,
-                 GType ctype,
-                 GtkTreeView *treeview,
-                 GtkWindow *list_window,
-                 GtkWidget *button)
+static void
+initialize_treeview (NMConnectionList *self)
 {
-	ActionInfo *info;
+	GtkCellRenderer *renderer;
+	GtkTreeViewColumn *column;
+	GtkTreeSelection *selection;
+	ConnectionTypeData *types;
+	GtkTreeIter iter;
+	char *id;
+	int i;
 
-	info = g_malloc0 (sizeof (ActionInfo));
-	g_hash_table_insert (list->actions, get_action_name (ctype, action), info);
+	/* Model */
+	self->model = GTK_TREE_MODEL (gtk_tree_store_new (7, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_OBJECT, G_TYPE_GTYPE, G_TYPE_INT));
 
-	info->list = list;
-	info->treeview = treeview;
-	info->list_window = list_window;
-	info->button = button;
-	return info;
-}
+	/* Filter */
+	self->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (self->model, NULL));
+	gtk_tree_model_filter_set_visible_func (self->filter,
+	                                        tree_model_visible_func,
+	                                        self, NULL);
 
-static void
-action_info_set_button (ActionInfo *info,
-                        GtkWidget *button)
-{
-	g_return_if_fail (info != NULL);
+	/* Sortable */
+	self->sortable = GTK_TREE_SORTABLE (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (self->filter)));
+	gtk_tree_sortable_set_default_sort_func (self->sortable, NULL, NULL, NULL);
+	gtk_tree_sortable_set_sort_func (self->sortable, COL_TIMESTAMP, timestamp_sort_func,
+	                                 self->sortable, NULL);
+	gtk_tree_sortable_set_sort_func (self->sortable, COL_ID, id_sort_func,
+	                                 self->sortable, NULL);
+	gtk_tree_sortable_set_sort_column_id (self->sortable, COL_TIMESTAMP, GTK_SORT_DESCENDING);
 
-	info->button = button;
-}
+	gtk_tree_view_set_model (self->connection_list, GTK_TREE_MODEL (self->sortable));
 
-static void
-action_info_set_new_func (ActionInfo *info,
-                          PageNewConnectionFunc func)
-{
-	g_return_if_fail (info != NULL);
+	/* Name column */
+	column = gtk_tree_view_column_new ();
+	gtk_tree_view_column_set_title (column, _("Name"));
+	gtk_tree_view_column_set_spacing (column, 4);
 
-	info->new_func = func;
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	gtk_tree_view_column_pack_start (column, renderer, FALSE);
+	gtk_tree_view_column_set_cell_data_func (column, renderer, name_column_data_func, NULL, NULL);
+
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute (column, renderer, "markup", COL_ID);
+
+	gtk_tree_view_column_set_expand (column, TRUE);
+	gtk_tree_view_column_set_sort_column_id (column, COL_ID);
+	g_signal_connect (column, "clicked", G_CALLBACK (column_header_clicked_cb), GINT_TO_POINTER (COL_ID));
+	gtk_tree_view_append_column (self->connection_list, column);
+
+	/* Last Used column */
+	renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
+	                         "foreground", "SlateGray",
+	                         NULL);
+	column = gtk_tree_view_column_new_with_attributes (_("Last Used"),
+	                                                   renderer,
+	                                                   "text", COL_LAST_USED,
+	                                                   NULL);
+	gtk_tree_view_column_set_sort_column_id (column, COL_TIMESTAMP);
+	g_signal_connect (column, "clicked", G_CALLBACK (column_header_clicked_cb), GINT_TO_POINTER (COL_TIMESTAMP));
+	gtk_tree_view_append_column (self->connection_list, column);
+
+	/* Selection */
+	selection = gtk_tree_view_get_selection (self->connection_list);
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+	/* Fill in connection types */
+	types = get_connection_type_list ();
+	for (i = 0; types[i].name; i++) {
+		id = g_strdup_printf ("<b>%s</b>", types[i].name);
+		gtk_tree_store_append (GTK_TREE_STORE (self->model), &iter, NULL);
+		gtk_tree_store_set (GTK_TREE_STORE (self->model), &iter,
+		                    COL_ICON, types[i].icon,
+		                    COL_ID, id,
+		                    COL_GTYPE, types[i].setting_type,
+		                    COL_ORDER, i,
+		                    -1);
+		g_free (id);
+	}
 }
 
 static void
-add_connection_buttons (NMConnectionList *self,
-                        const char *prefix,
-                        GtkTreeView *treeview,
-                        GType ctype,
-                        PageNewConnectionFunc new_func)
+add_connection_buttons (NMConnectionList *self)
 {
-	char *name;
-	GtkWidget *button, *hbox;
-	ActionInfo *info;
+	GtkWidget *button, *box;
 	GtkTreeSelection *selection;
 
-	selection = gtk_tree_view_get_selection (treeview);
+	selection = gtk_tree_view_get_selection (self->connection_list);
 
 	/* Add */
-	name = g_strdup_printf ("%s_add", prefix);
-	button = GTK_WIDGET (gtk_builder_get_object (self->gui, name));
-	g_free (name);
-	info = action_info_new (self, "add", ctype, treeview, GTK_WINDOW (self->dialog), NULL);
-	g_signal_connect (button, "clicked", G_CALLBACK (add_clicked), info);
-	if (ctype == NM_TYPE_SETTING_VPN) {
-		GHashTable *plugins;
-		gboolean have_plugins;
-
-		/* disable the "Add..." button if there aren't any VPN plugins */
-		plugins = vpn_get_plugins (NULL);
-		have_plugins = plugins && g_hash_table_size (plugins);
-		gtk_widget_set_sensitive (button, have_plugins);
-		if (!have_plugins)
-			gtk_widget_set_tooltip_text (button, _("No VPN plugin available. Please install one to enable this button."));
-	}
-	if (new_func)
-		action_info_set_new_func (info, new_func);
+	button = GTK_WIDGET (gtk_builder_get_object (self->gui, "connection_add"));
+	g_signal_connect (button, "clicked", G_CALLBACK (add_clicked), self);
 
-	name = g_strdup_printf ("%s_button_box", prefix);
-	hbox = GTK_WIDGET (gtk_builder_get_object (self->gui, name));
-	g_free (name);
+	box = GTK_WIDGET (gtk_builder_get_object (self->gui, "connection_button_box"));
 
 	/* Edit */
-	info = action_info_new (self, "edit", ctype, treeview, GTK_WINDOW (self->dialog), NULL);
 	button = ce_polkit_button_new (_("_Edit"),
 	                               _("Edit the selected connection"),
 	                               _("_Edit..."),
@@ -1107,17 +1061,16 @@ add_connection_buttons (NMConnectionList *self,
 	                               GTK_STOCK_EDIT,
 	                               self->nm_client,
 	                               NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM);
+	g_object_set_data (G_OBJECT (button), "NMConnectionList", self);
 	gtk_button_set_use_underline (GTK_BUTTON (button), TRUE);
-	gtk_box_pack_end (GTK_BOX (hbox), button, TRUE, TRUE, 0);
+	gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 0);
 
-	action_info_set_button (info, button);
-	g_signal_connect_swapped (button, "clicked", G_CALLBACK (do_edit), info);
-	g_signal_connect (treeview, "row-activated", G_CALLBACK (connection_double_clicked_cb), info);
-	g_signal_connect (selection, "changed", G_CALLBACK (pk_button_selection_changed_cb), info);
-	pk_button_selection_changed_cb (selection, info);
+	g_signal_connect_swapped (button, "clicked", G_CALLBACK (do_edit), self);
+	g_signal_connect (self->connection_list, "row-activated", G_CALLBACK (connection_double_clicked_cb), button);
+	g_signal_connect (selection, "changed", G_CALLBACK (pk_button_selection_changed_cb), button);
+	pk_button_selection_changed_cb (selection, button);
 
 	/* Delete */
-	info = action_info_new (self, "delete", ctype, treeview, GTK_WINDOW (self->dialog), NULL);
 	button = ce_polkit_button_new (_("_Delete"),
 	                               _("Delete the selected connection"),
 	                               _("_Delete..."),
@@ -1125,78 +1078,73 @@ add_connection_buttons (NMConnectionList *self,
 	                               GTK_STOCK_DELETE,
 	                               self->nm_client,
 	                               NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM);
+	g_object_set_data (G_OBJECT (button), "NMConnectionList", self);
 	gtk_button_set_use_underline (GTK_BUTTON (button), TRUE);
-	gtk_box_pack_end (GTK_BOX (hbox), button, TRUE, TRUE, 0);
+	gtk_box_pack_end (GTK_BOX (box), button, TRUE, TRUE, 0);
+
+	g_signal_connect (button, "clicked", G_CALLBACK (delete_clicked), self);
+	g_signal_connect (selection, "changed", G_CALLBACK (pk_button_selection_changed_cb), button);
+	pk_button_selection_changed_cb (selection, button);
 
-	action_info_set_button (info, button);
-	g_signal_connect (button, "clicked", G_CALLBACK (delete_clicked), info);
-	g_signal_connect (selection, "changed", G_CALLBACK (pk_button_selection_changed_cb), info);
-	pk_button_selection_changed_cb (selection, info);
+	gtk_widget_show_all (box);
 }
 
 static void
-add_connection_tab (NMConnectionList *self,
-                    GType ctype,
-                    GdkPixbuf *pixbuf,
-                    const char *prefix,
-                    const char *label_text,
-                    PageNewConnectionFunc new_func)
+connection_removed (NMRemoteConnection *connection, gpointer user_data)
 {
-	char *name;
-	GtkWidget *child, *hbox, *notebook;
-	GtkTreeView *treeview;
-
-	name = g_strdup_printf ("%s_child", prefix);
-	child = GTK_WIDGET (gtk_builder_get_object (self->gui, name));
-	g_free (name);
-
-	/* Notebook tab */
-#if GTK_CHECK_VERSION(3,1,6)
-        hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
-#else
-	hbox = gtk_hbox_new (FALSE, 6);
-#endif
-	if (pixbuf) {
-		GtkWidget *image;
-
-		image = gtk_image_new_from_pixbuf (pixbuf);
-		gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
-	}
-	gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (label_text), FALSE, FALSE, 0);
-	gtk_widget_show_all (hbox);
-
-	notebook = GTK_WIDGET (gtk_builder_get_object (self->gui, "list_notebook"));
-	gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), child, hbox);
-
-	treeview = add_connection_treeview (self, prefix);
-	add_connection_buttons (self, prefix, treeview, ctype, new_func);
-	gtk_widget_show_all (GTK_WIDGET (notebook));
-
-	self->treeviews = g_slist_prepend (self->treeviews, treeview);
+	NMConnectionList *self = NM_CONNECTION_LIST (user_data);
+	GtkTreeIter iter, parent_iter;
 
-	/* Tag the notebook child and the treeview with the type of connection they contain */
-	g_object_set_data (G_OBJECT (child), TV_TYPE_TAG, GSIZE_TO_POINTER (ctype));
-	g_object_set_data (G_OBJECT (treeview), TV_TYPE_TAG, GSIZE_TO_POINTER (ctype));
+	if (get_iter_for_connection (self, connection, &iter)) {
+		gtk_tree_model_iter_parent (self->model, &parent_iter, &iter);
+		gtk_tree_store_remove (GTK_TREE_STORE (self->model), &iter);
+	}
+	gtk_tree_model_filter_refilter (self->filter);
 }
 
 static void
-connection_removed (NMRemoteConnection *connection, gpointer user_data)
+connection_updated (NMRemoteConnection *connection, gpointer user_data)
 {
-	GtkListStore *store = GTK_LIST_STORE (user_data);
+	NMConnectionList *self = NM_CONNECTION_LIST (user_data);
 	GtkTreeIter iter;
 
-	if (get_iter_for_connection (GTK_TREE_MODEL (store), connection, &iter))
-		gtk_list_store_remove (store, &iter);
+	if (get_iter_for_connection (self, connection, &iter))
+		update_connection_row (self, &iter, connection);
 }
 
-static void
-connection_updated (NMRemoteConnection *connection, gpointer user_data)
+static gboolean
+get_parent_iter_for_connection (NMConnectionList *list,
+                                NMRemoteConnection *connection,
+                                GtkTreeIter *iter)
 {
-	GtkListStore *store = GTK_LIST_STORE (user_data);
-	GtkTreeIter iter;
+	NMSettingConnection *s_con;
+	const char *str_type;
+	GType type, row_type;
 
-	if (get_iter_for_connection (GTK_TREE_MODEL (store), connection, &iter))
-		update_connection_row (store, &iter, connection);
+	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
+	g_assert (s_con);
+	str_type = nm_setting_connection_get_connection_type (s_con);
+	if (!str_type) {
+		g_warning ("Ignoring incomplete connection");
+		return FALSE;
+	}
+
+	if (!strcmp (str_type, NM_SETTING_CDMA_SETTING_NAME))
+		str_type = NM_SETTING_GSM_SETTING_NAME;
+	type = nm_connection_lookup_setting_type (str_type);
+
+	if (gtk_tree_model_get_iter_first (list->model, iter)) {
+		do {
+			gtk_tree_model_get (list->model, iter,
+			                    COL_GTYPE, &row_type,
+			                    -1);
+			if (row_type == type)
+				return TRUE;
+		} while (gtk_tree_model_iter_next (list->model, iter));
+	}
+
+	g_warning ("Unsupported connection type '%s'", str_type);
+	return FALSE;
 }
 
 static void
@@ -1205,21 +1153,20 @@ connection_added (NMRemoteSettings *settings,
                   gpointer user_data)
 {
 	NMConnectionList *self = NM_CONNECTION_LIST (user_data);
-	GtkListStore *store;
-	GtkTreeIter iter;
+	GtkTreeIter parent_iter, iter;
 	NMSettingConnection *s_con;
 	char *last_used;
+	gboolean expand = TRUE;
 
-	store = get_model_for_connection (self, connection);
-	if (!store)
+	if (!get_parent_iter_for_connection (self, connection, &parent_iter))
 		return;
 
 	s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection));
 
 	last_used = format_last_used (nm_setting_connection_get_timestamp (s_con));
 
-	gtk_list_store_append (store, &iter);
-	gtk_list_store_set (store, &iter,
+	gtk_tree_store_append (GTK_TREE_STORE (self->model), &iter, &parent_iter);
+	gtk_tree_store_set (GTK_TREE_STORE (self->model), &iter,
 	                    COL_ID, nm_setting_connection_get_id (s_con),
 	                    COL_LAST_USED, last_used,
 	                    COL_TIMESTAMP, nm_setting_connection_get_timestamp (s_con),
@@ -1228,20 +1175,31 @@ connection_added (NMRemoteSettings *settings,
 
 	g_free (last_used);
 
-	g_signal_connect (connection, NM_REMOTE_CONNECTION_REMOVED, G_CALLBACK (connection_removed), store);
-	g_signal_connect (connection, NM_REMOTE_CONNECTION_UPDATED, G_CALLBACK (connection_updated), store);
-}
+	if (self->displayed_type) {
+		GType added_type;
+
+		gtk_tree_model_get (self->model, &parent_iter,
+		                    COL_GTYPE, &added_type,
+		                    -1);
+		if (added_type != self->displayed_type)
+			expand = FALSE;
+	}
+
+	if (expand) {
+		GtkTreePath *path, *filtered_path;
 
-#define ICON_LOAD(x, y)	\
-	{ \
-		x = gtk_icon_theme_load_icon (list->icon_theme, y, 16, 0, &error); \
-		if (x == NULL) { \
-			g_warning ("Icon %s missing: %s", y, error->message); \
-			g_error_free (error); \
-			goto error; \
-		} \
+		path = gtk_tree_model_get_path (self->model, &parent_iter);
+		filtered_path = gtk_tree_model_filter_convert_child_path_to_path (self->filter, path);
+		gtk_tree_view_expand_row (self->connection_list, filtered_path, FALSE);
+		gtk_tree_path_free (filtered_path);
+		gtk_tree_path_free (path);
 	}
 
+	g_signal_connect (connection, NM_REMOTE_CONNECTION_REMOVED, G_CALLBACK (connection_removed), self);
+	g_signal_connect (connection, NM_REMOTE_CONNECTION_UPDATED, G_CALLBACK (connection_updated), self);
+	gtk_tree_model_filter_refilter (self->filter);
+}
+
 NMConnectionList *
 nm_connection_list_new (void)
 {
@@ -1268,15 +1226,6 @@ nm_connection_list_new (void)
 
 	gtk_window_set_default_icon_name ("preferences-system-network");
 
-	list->icon_theme = gtk_icon_theme_get_for_screen (gdk_screen_get_default ());
-
-	/* Load icons */
-	ICON_LOAD(list->wired_icon, "nm-device-wired");
-	ICON_LOAD(list->wireless_icon, "nm-device-wireless");
-	ICON_LOAD(list->wwan_icon, "nm-device-wwan");
-	ICON_LOAD(list->vpn_icon, "nm-vpn-standalone-lock");
-	ICON_LOAD(list->unknown_icon, "nm-no-connection");
-
 	list->nm_client = nm_client_new ();
 	if (!list->nm_client)
 		goto error;
@@ -1296,28 +1245,10 @@ nm_connection_list_new (void)
 	                  list);
 
 	list->editors = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
-	list->actions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) action_info_free);
 
-	/* Add each connection type tab */
-	add_connection_tab (list, NM_TYPE_SETTING_WIRED,
-	                    list->wired_icon, "wired", _("Wired"),
-	                    wired_connection_new);
-
-	add_connection_tab (list, NM_TYPE_SETTING_WIRELESS,
-	                    list->wireless_icon, "wireless", _("Wireless"),
-	                    wifi_connection_new);
-
-	add_connection_tab (list, NM_TYPE_SETTING_GSM,
-	                    list->wwan_icon, "wwan", _("Mobile Broadband"),
-	                    mobile_connection_new);
-
-	add_connection_tab (list, NM_TYPE_SETTING_VPN,
-	                    list->vpn_icon, "vpn", _("VPN"),
-	                    vpn_connection_new);
-
-	add_connection_tab (list, NM_TYPE_SETTING_PPPOE,
-	                    list->wired_icon, "dsl", _("DSL"),
-	                    dsl_connection_new);
+	list->connection_list = GTK_TREE_VIEW (gtk_builder_get_object (list->gui, "connection_list"));
+	initialize_treeview (list);
+	add_connection_buttons (list);
 
 	/* Connect to the main dialog's response handler */
 	list->dialog = GTK_WIDGET (gtk_builder_get_object (list->gui, "NMConnectionList"));
@@ -1340,45 +1271,34 @@ error:
 void
 nm_connection_list_set_type (NMConnectionList *self, GType ctype)
 {
-	GtkNotebook *notebook;
-	int i;
-
 	g_return_if_fail (NM_IS_CONNECTION_LIST (self));
 
-	/* If a notebook page is found that owns the requested type, set it
-	 * as the current page.
-	 */
-	notebook = GTK_NOTEBOOK (GTK_WIDGET (gtk_builder_get_object (self->gui, "list_notebook")));
-	for (i = 0; i < gtk_notebook_get_n_pages (notebook); i++) {
-		GtkWidget *child;
-		GType child_type;
-
-		child = gtk_notebook_get_nth_page (notebook, i);
-		child_type = GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (child), TV_TYPE_TAG));
-		if (child_type == ctype) {
-			gtk_notebook_set_current_page (notebook, i);
-			break;
-		}
-	}
+	self->displayed_type = ctype;
 }
 
 void
 nm_connection_list_create (NMConnectionList *self, GType ctype)
 {
-	ActionInfo *info;
+	ConnectionTypeData *types;
+	int i;
 
 	g_return_if_fail (NM_IS_CONNECTION_LIST (self));
 
-	info = find_action_info (self, ctype, "add");
-	if (info == NULL) {
+	types = get_connection_type_list ();
+	for (i = 0; types[i].name; i++) {
+		if (types[i].setting_type == ctype)
+			break;
+	}
+	if (!types[i].name) {
 		error_dialog (NULL,
 		              _("Error creating connection"),
 		              _("Don't know how to create '%s' connections"), g_type_name (ctype));
 	} else {
-		info->new_func (GTK_WINDOW (info->list->dialog),
-		                really_add_connection,
-		                page_get_connections,
-		                info);
+		new_connection_of_type (GTK_WINDOW (self->dialog),
+		                        self->settings,
+		                        types[i].new_connection_func,
+		                        really_add_connection,
+		                        self);
 	}
 }
 
@@ -1417,21 +1337,7 @@ connections_read (NMRemoteSettings *settings, EditData *data)
 
 	connection = get_connection (settings, data->uuid);
 	if (connection) {
-		NMSettingConnection *s_con;
-		const char *type;
-		ActionInfo *info;
-
-		s_con = nm_connection_get_setting_connection (connection);
-		type = nm_setting_connection_get_connection_type (s_con);
-		info = find_action_info (data->self, nm_connection_lookup_setting_type (type), "edit");
-		if (info != NULL)
-			edit_connection (info, connection);
-		else {
-			error_dialog (NULL,
-			              _("Error editing connection"),
-			              _("Don't know how to edit '%s' connections"), type);
-		}
-
+		edit_connection (data->self, connection);
 		g_object_unref (connection);
 	} else if (data->wait) {
 		data->wait = FALSE;
diff --git a/src/connection-editor/nm-connection-list.h b/src/connection-editor/nm-connection-list.h
index 2db6c23..1a01bb3 100644
--- a/src/connection-editor/nm-connection-list.h
+++ b/src/connection-editor/nm-connection-list.h
@@ -38,9 +38,12 @@ typedef struct {
 
 	/* private data */
 	GHashTable *editors;
-	GSList *treeviews;
 
-	GHashTable *actions;
+	GtkTreeView *connection_list;
+	GtkTreeModel *model;
+	GtkTreeModelFilter *filter;
+	GtkTreeSortable *sortable;
+	GType displayed_type;
 
 	NMClient *nm_client;
 	NMRemoteSettings *settings;
@@ -48,13 +51,6 @@ typedef struct {
 	GtkBuilder *gui;
 	GtkWidget *dialog;
 
-	GdkPixbuf *wired_icon;
-	GdkPixbuf *wireless_icon;
-	GdkPixbuf *wwan_icon;
-	GdkPixbuf *vpn_icon;
-	GdkPixbuf *unknown_icon;
-	GtkIconTheme *icon_theme;
-
 	gboolean signals_connected;
 } NMConnectionList;
 



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