[gnome-control-center] printers: Redesign of new printer dialog



commit 45ba8e89e86397df912e07df14d76373f1c7e7af
Author: Marek Kasik <mkasik redhat com>
Date:   Mon Sep 3 21:25:59 2012 +0200

    printers: Redesign of new printer dialog
    
    This commit implements design changes from
    https://live.gnome.org/Design/SystemSettings/Printers.
    
    The new printer dialog gets informations about connected devices
    from CUPS server asynchronously and separately for each backend now.
    
    Entering an address into the entry and pressing the icon inside
    the entry or enter starts to detect printers on the entered host.
    
    Entering a text which is a substring of a name of a device or its location
    filters the list to contain just devicess with the string in it (e.g. Canon
    will keep devices with "Canon" in their name).
    
    The PpNewPrinterDialog is regular object now. It emits signal "pre-response"
    when dialog is closed and a printer is being added and signal "response" when
    the new printer was added, addition of the new printer failed or the dialog was
    cancelled.
    This commit removes FirewallD support from new printer dialog. (#683229)

 panels/printers/cc-printers-panel.c     |  390 ++++-
 panels/printers/new-printer-dialog.ui   |  448 ++----
 panels/printers/pp-new-printer-dialog.c | 2900 ++++++++++++-------------------
 panels/printers/pp-new-printer-dialog.h |   39 +-
 4 files changed, 1641 insertions(+), 2136 deletions(-)
---
diff --git a/panels/printers/cc-printers-panel.c b/panels/printers/cc-printers-panel.c
index 70a04fc..85f29b2 100644
--- a/panels/printers/cc-printers-panel.c
+++ b/panels/printers/cc-printers-panel.c
@@ -37,6 +37,7 @@
 #include "pp-options-dialog.h"
 #include "pp-jobs-dialog.h"
 #include "pp-utils.h"
+#include "pp-maintenance-command.h"
 
 CC_PANEL_REGISTER (CcPrintersPanel, cc_printers_panel)
 
@@ -104,6 +105,12 @@ struct _CcPrintersPanelPrivate
   GHashTable   *preferred_drivers;
   GCancellable *get_all_ppds_cancellable;
 
+  gchar    *new_printer_name;
+  gchar    *new_printer_location;
+  gchar    *new_printer_make_and_model;
+  gboolean  new_printer_on_network;
+  gboolean  select_new_printer;
+
   gpointer dummy;
 };
 
@@ -153,13 +160,14 @@ cc_printers_panel_dispose (GObject *object)
   CcPrintersPanelPrivate *priv = CC_PRINTERS_PANEL (object)->priv;
 
   if (priv->pp_new_printer_dialog)
-    {
-      pp_new_printer_dialog_free (priv->pp_new_printer_dialog);
-      priv->pp_new_printer_dialog = NULL;
-    }
+    g_clear_object (&priv->pp_new_printer_dialog);
 
   free_dests (CC_PRINTERS_PANEL (object));
 
+  g_clear_pointer (&priv->new_printer_name, g_free);
+  g_clear_pointer (&priv->new_printer_location, g_free);
+  g_clear_pointer (&priv->new_printer_make_and_model, g_free);
+
   if (priv->builder)
     {
       g_object_unref (priv->builder);
@@ -538,7 +546,6 @@ printer_selection_changed_cb (GtkTreeSelection *selection,
   GtkWidget              *widget;
   GtkWidget              *model_button;
   GtkWidget              *model_label;
-  gboolean                sensitive;
   GValue                  value = G_VALUE_INIT;
   gchar                  *printer_make_and_model = NULL;
   gchar                  *printer_model = NULL;
@@ -710,10 +717,19 @@ printer_selection_changed_cb (GtkTreeSelection *selection,
             printer_model = g_strdup (printer_make_and_model);
         }
 
+      if (priv->new_printer_name &&
+          g_strcmp0 (priv->new_printer_name, printer_name) == 0)
+        {
+          /* Translators: Printer's state (printer is being configured right now) */
+          status = g_strdup ( C_("printer state", "Configuring"));
+        }
+
       /* Find the first of the most severe reasons
        * and show it in the status field
        */
-      if (reason && g_strcmp0 (reason, "none") != 0)
+      if (!status &&
+          reason &&
+          !g_str_equal (reason, "none"))
         {
           int errors = 0, warnings = 0, reports = 0;
           int error_index = -1, warning_index = -1, report_index = -1;
@@ -871,11 +887,9 @@ printer_selection_changed_cb (GtkTreeSelection *selection,
       widget = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "printer-default-check-button");
 
-      sensitive = gtk_widget_get_sensitive (widget);
       g_signal_handlers_block_by_func (G_OBJECT (widget), printer_set_default_cb, self);
       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), priv->dests[id].is_default);
       g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_set_default_cb, self);
-      gtk_widget_set_sensitive (widget, sensitive);
 
 
       widget = (GtkWidget*)
@@ -907,33 +921,107 @@ printer_selection_changed_cb (GtkTreeSelection *selection,
     }
   else
     {
+      if (id == -1)
+        {
+          if (priv->new_printer_name &&
+              g_strcmp0 (priv->new_printer_name, printer_name) == 0)
+            {
+              /* Translators: Printer's state (printer is being installed right now) */
+              status = g_strdup ( C_("printer state", "Installing"));
+              location = g_strdup (priv->new_printer_location);
+              printer_model = g_strdup (priv->new_printer_make_and_model);
+
+              widget = (GtkWidget*)
+                gtk_builder_get_object (priv->builder, "notebook");
+              if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) >= NOTEBOOK_NO_PRINTERS_PAGE)
+                gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_INFO_PAGE);
+            }
+        }
+
+      widget = (GtkWidget*)
+        gtk_builder_get_object (priv->builder, "printer-icon");
+      g_value_init (&value, G_TYPE_INT);
+      g_object_get_property ((GObject *) widget, "icon-size", &value);
+
+      if (printer_icon)
+        {
+          gtk_image_set_from_icon_name ((GtkImage *) widget, printer_icon, g_value_get_int (&value));
+          g_free (printer_icon);
+        }
+      else
+        gtk_image_set_from_icon_name ((GtkImage *) widget, "printer", g_value_get_int (&value));
+
       widget = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "printer-name-label");
-      cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), "");
+      if (printer_name)
+        {
+          cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), printer_name);
+          g_free (printer_name);
+        }
+      else
+        cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
 
       widget = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "printer-status-label");
-      cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), "");
+      if (status)
+        {
+          cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), status);
+          g_free (status);
+        }
+      else
+        cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
 
       widget = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "printer-location-label");
-      cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), "");
 
-      widget = (GtkWidget*)
+      if (location)
+        {
+          cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), location);
+          g_free (location);
+        }
+      else
+        cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
+
+
+      model_button = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "printer-model-button");
-      gtk_button_set_label (GTK_BUTTON (widget), "");
 
-      widget = (GtkWidget*)
+      model_label = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "printer-model-label");
-      gtk_label_set_text (GTK_LABEL (widget), "");
+
+      if (printer_model)
+        {
+          gtk_button_set_label (GTK_BUTTON (model_button), printer_model);
+          gtk_label_set_text (GTK_LABEL (model_label), printer_model);
+          g_free (printer_model);
+        }
+      else
+        {
+          gtk_button_set_label (GTK_BUTTON (model_button), EMPTY_TEXT);
+          gtk_label_set_text (GTK_LABEL (model_label), EMPTY_TEXT);
+        }
 
       widget = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "printer-ip-address-label");
-      cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), "");
+      cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
 
       widget = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "printer-jobs-label");
-      cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), "");
+      cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
+
+      widget = (GtkWidget*)
+        gtk_builder_get_object (priv->builder, "printer-disable-switch");
+
+      g_signal_handlers_block_by_func (G_OBJECT (widget), printer_disable_cb, self);
+      gtk_switch_set_active (GTK_SWITCH (widget), FALSE);
+      g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_disable_cb, self);
+
+      widget = (GtkWidget*)
+        gtk_builder_get_object (priv->builder, "printer-default-check-button");
+
+      g_signal_handlers_block_by_func (G_OBJECT (widget), printer_set_default_cb, self);
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+      g_signal_handlers_unblock_by_func (G_OBJECT (widget), printer_set_default_cb, self);
     }
 
   update_sensitivity (self);
@@ -943,34 +1031,47 @@ static void
 actualize_printers_list (CcPrintersPanel *self)
 {
   CcPrintersPanelPrivate *priv;
+  GtkTreeSelection       *selection;
   GtkListStore           *store;
   cups_ptype_t            printer_type = 0;
+  GtkTreeModel           *model;
   GtkTreeIter             selected_iter;
   GtkTreeView            *treeview;
   GtkTreeIter             iter;
   cups_job_t             *jobs = NULL;
   GtkWidget              *widget;
   gboolean                paused = FALSE;
+  gboolean                selected_iter_set = FALSE;
   gboolean                valid = FALSE;
   http_t                 *http;
-  gchar                  *current_printer_instance = NULL;
   gchar                  *current_printer_name = NULL;
   gchar                  *printer_icon_name = NULL;
   gchar                  *default_icon_name = NULL;
   gchar                  *device_uri = NULL;
+  gint                    new_printer_position = 0;
   int                     current_dest = -1;
   int                     i, j;
   int                     num_jobs = 0;
 
   priv = PRINTERS_PANEL_PRIVATE (self);
 
-  if (priv->current_dest >= 0 &&
-      priv->current_dest < priv->num_dests &&
-      priv->dests != NULL)
+  treeview = (GtkTreeView*)
+    gtk_builder_get_object (priv->builder, "printers-treeview");
+
+  if ((selection = gtk_tree_view_get_selection (treeview)) != NULL &&
+      gtk_tree_selection_get_selected (selection, &model, &iter))
     {
-      current_printer_name = g_strdup (priv->dests[priv->current_dest].name);
-      if (priv->dests[priv->current_dest].instance)
-        current_printer_instance = g_strdup (priv->dests[priv->current_dest].instance);
+      gtk_tree_model_get (model, &iter,
+			  PRINTER_NAME_COLUMN, &current_printer_name,
+			  -1);
+    }
+
+  if (priv->new_printer_name &&
+      priv->select_new_printer)
+    {
+      g_free (current_printer_name);
+      current_printer_name = g_strdup (priv->new_printer_name);
+      priv->select_new_printer = FALSE;
     }
 
   free_dests (self);
@@ -978,9 +1079,6 @@ actualize_printers_list (CcPrintersPanel *self)
   priv->dest_model_names = g_new0 (gchar *, priv->num_dests);
   priv->ppd_file_names = g_new0 (gchar *, priv->num_dests);
 
-  treeview = (GtkTreeView*)
-    gtk_builder_get_object (priv->builder, "printers-treeview");
-
   store = gtk_list_store_new (PRINTER_N_COLUMNS,
                               G_TYPE_INT,
                               G_TYPE_STRING,
@@ -988,7 +1086,7 @@ actualize_printers_list (CcPrintersPanel *self)
                               G_TYPE_STRING,
                               G_TYPE_STRING);
 
-  if (priv->num_dests == 0)
+  if (priv->num_dests == 0 && !priv->new_printer_name)
     {
       widget = (GtkWidget*)
         gtk_builder_get_object (priv->builder, "notebook");
@@ -1020,30 +1118,25 @@ actualize_printers_list (CcPrintersPanel *self)
     {
       gchar *instance;
 
+      if (priv->new_printer_name && new_printer_position >= 0)
+        {
+          gint comparison_result = g_ascii_strcasecmp (priv->dests[i].name, priv->new_printer_name);
+
+          if (comparison_result < 0)
+            new_printer_position = i + 1;
+          else if (comparison_result == 0)
+            new_printer_position = -1;
+        }
+
       gtk_list_store_append (store, &iter);
 
       if (priv->dests[i].instance)
         {
           instance = g_strdup_printf ("%s / %s", priv->dests[i].name, priv->dests[i].instance);
-
-          if (current_printer_instance &&
-              g_strcmp0 (current_printer_name, priv->dests[i].name) == 0 &&
-              g_strcmp0 (current_printer_instance, priv->dests[i].instance) == 0)
-            {
-              current_dest = i;
-              selected_iter = iter;
-            }
         }
       else
         {
           instance = g_strdup (priv->dests[i].name);
-
-          if (current_printer_instance == NULL &&
-              g_strcmp0 (current_printer_name, priv->dests[i].name) == 0)
-            {
-              current_dest = i;
-              selected_iter = iter;
-            }
         }
 
       for (j = 0; j < priv->dests[i].num_options; j++)
@@ -1074,11 +1167,37 @@ actualize_printers_list (CcPrintersPanel *self)
                           PRINTER_ICON_COLUMN, printer_icon_name,
                           -1);
 
+      if (g_strcmp0 (current_printer_name, instance) == 0)
+        {
+          current_dest = i;
+          selected_iter = iter;
+          selected_iter_set = TRUE;
+        }
+
       g_free (instance);
       g_free (printer_icon_name);
       g_free (default_icon_name);
     }
 
+  if (priv->new_printer_name && new_printer_position >= 0)
+    {
+      gtk_list_store_insert (store, &iter, new_printer_position);
+      gtk_list_store_set (store, &iter,
+                          PRINTER_ID_COLUMN, -1,
+                          PRINTER_NAME_COLUMN, priv->new_printer_name,
+                          PRINTER_PAUSED_COLUMN, TRUE,
+                          PRINTER_DEFAULT_ICON_COLUMN, NULL,
+                          PRINTER_ICON_COLUMN, priv->new_printer_on_network ?
+                            "printer-network" : "printer",
+                          -1);
+
+      if (g_strcmp0 (current_printer_name, priv->new_printer_name) == 0)
+        {
+          selected_iter = iter;
+          selected_iter_set = TRUE;
+        }
+    }
+
   g_signal_handlers_block_by_func (
     G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview))),
     printer_selection_changed_cb,
@@ -1091,7 +1210,7 @@ actualize_printers_list (CcPrintersPanel *self)
     printer_selection_changed_cb,
     self);
 
-  if (current_dest >= 0)
+  if (selected_iter_set)
     {
       priv->current_dest = current_dest;
       gtk_tree_selection_select_iter (
@@ -1160,7 +1279,6 @@ actualize_printers_list (CcPrintersPanel *self)
     }
 
   g_free (current_printer_name);
-  g_free (current_printer_instance);
   g_object_unref (store);
 
   update_sensitivity (self);
@@ -1192,14 +1310,20 @@ set_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
                   "width-chars", 18,
                   NULL);
 
-  if (paused)
-    g_object_set (cell,
-                  "sensitive", FALSE,
-                  NULL);
-  else
-    g_object_set (cell,
-                  "sensitive", TRUE,
-                  NULL);
+  g_object_set (cell, "sensitive", !paused, NULL);
+}
+
+static void
+set_pixbuf_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
+                                  GtkCellRenderer   *cell,
+                                  GtkTreeModel      *tree_model,
+                                  GtkTreeIter       *iter,
+                                  gpointer           func_data)
+{
+  gboolean paused = FALSE;
+
+  gtk_tree_model_get (tree_model, iter, PRINTER_PAUSED_COLUMN, &paused, -1);
+  g_object_set (cell, "sensitive", !paused, NULL);
 }
 
 static void
@@ -1228,6 +1352,8 @@ populate_printers_list (CcPrintersPanel *self)
   gtk_cell_renderer_set_padding (icon_renderer, 4, 4);
   column = gtk_tree_view_column_new_with_attributes ("Icon", icon_renderer,
                                                      "icon-name", PRINTER_ICON_COLUMN, NULL);
+  gtk_tree_view_column_set_cell_data_func (column, icon_renderer, set_pixbuf_cell_sensitivity_func,
+                                           self, NULL);
   gtk_tree_view_column_set_expand (column, FALSE);
   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
@@ -1524,7 +1650,7 @@ supply_levels_draw_cb (GtkWidget *widget,
           gtk_widget_set_has_tooltip (widget, FALSE);
         }
     }
-    
+
   return TRUE;
 }
 
@@ -1555,21 +1681,45 @@ printer_set_default_cb (GtkToggleButton *button,
 }
 
 static void
-new_printer_dialog_response_cb (GtkDialog *dialog,
-                                gint       response_id,
-                                gpointer   user_data)
+new_printer_dialog_pre_response_cb (PpNewPrinterDialog *dialog,
+                                    const gchar        *device_name,
+                                    const gchar        *device_location,
+                                    const gchar        *device_make_and_model,
+                                    gboolean            is_network_device,
+                                    gpointer            user_data)
 {
   CcPrintersPanelPrivate *priv;
   CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
 
   priv = PRINTERS_PANEL_PRIVATE (self);
 
-  pp_new_printer_dialog_free (priv->pp_new_printer_dialog);
-  priv->pp_new_printer_dialog = NULL;
+  priv->new_printer_name = g_strdup (device_name);
+  priv->new_printer_location = g_strdup (device_location);
+  priv->new_printer_make_and_model = g_strdup (device_make_and_model);
+  priv->new_printer_on_network = is_network_device;
+  priv->select_new_printer = TRUE;
 
-  if (response_id == GTK_RESPONSE_OK)
-    actualize_printers_list (self);
-  else if (response_id == GTK_RESPONSE_REJECT)
+  actualize_printers_list (self);
+}
+
+static void
+new_printer_dialog_response_cb (PpNewPrinterDialog *dialog,
+                                gint                response_id,
+                                gpointer            user_data)
+{
+  CcPrintersPanelPrivate *priv;
+  CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  if (priv->pp_new_printer_dialog)
+    g_clear_object (&priv->pp_new_printer_dialog);
+
+  g_clear_pointer (&priv->new_printer_name, g_free);
+  g_clear_pointer (&priv->new_printer_location, g_free);
+  g_clear_pointer (&priv->new_printer_make_and_model, g_free);
+
+  if (response_id == GTK_RESPONSE_REJECT)
     {
       GtkWidget *message_dialog;
 
@@ -1585,6 +1735,8 @@ new_printer_dialog_response_cb (GtkDialog *dialog,
                         NULL);
       gtk_widget_show (message_dialog);
     }
+
+  actualize_printers_list (self);
 }
 
 static void
@@ -1593,17 +1745,22 @@ printer_add_cb (GtkToolButton *toolbutton,
 {
   CcPrintersPanelPrivate *priv;
   CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
-  GtkWidget              *widget;
+  GtkWidget              *toplevel;
 
   priv = PRINTERS_PANEL_PRIVATE (self);
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "main-vbox");
+  toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
+  priv->pp_new_printer_dialog = PP_NEW_PRINTER_DIALOG (pp_new_printer_dialog_new (GTK_WINDOW (toplevel)));
 
-  priv->pp_new_printer_dialog = pp_new_printer_dialog_new (
-    GTK_WINDOW (gtk_widget_get_toplevel (widget)),
-    new_printer_dialog_response_cb,
-    self);
+  g_signal_connect (priv->pp_new_printer_dialog,
+                    "pre-response",
+                    G_CALLBACK (new_printer_dialog_pre_response_cb),
+                    self);
+
+  g_signal_connect (priv->pp_new_printer_dialog,
+                    "response",
+                    G_CALLBACK (new_printer_dialog_response_cb),
+                    self);
 }
 
 static void
@@ -2185,6 +2342,19 @@ popup_model_menu_cb (GtkButton *button,
 }
 
 static void
+pp_maintenance_command_execute_cb (GObject      *source_object,
+                                   GAsyncResult *res,
+                                   gpointer      user_data)
+{
+  PpMaintenanceCommand *command = (PpMaintenanceCommand *) source_object;
+  GError               *error = NULL;
+
+  pp_maintenance_command_execute_finish (command, res, &error);
+
+  g_object_unref (command);
+}
+
+static void
 test_page_cb (GtkButton *button,
               gpointer   user_data)
 {
@@ -2286,23 +2456,27 @@ test_page_cb (GtkButton *button,
               httpClose (http);
             }
 
+          if (response)
+            {
+              if (ippGetState (response) == IPP_ERROR)
+                g_warning ("An error has occured during printing of test page.");
+              ippDelete (response);
+            }
+
           g_free (filename);
           g_free (printer_uri);
           g_free (resource);
         }
       else
         {
-          response = execute_maintenance_command (printer_name,
-                                                  "PrintSelfTestPage",
+          PpMaintenanceCommand *command;
+
+          command = pp_maintenance_command_new (printer_name,
+                                                "PrintSelfTestPage",
           /* Translators: Name of job which makes printer to print test page */
-                                                  _("Test page"));
-        }
+                                                _("Test page"));
 
-      if (response)
-        {
-          if (ippGetState (response) == IPP_ERROR)
-            g_warning ("An error has occured during printing of test page.");
-          ippDelete (response);
+          pp_maintenance_command_execute_async (command, NULL, pp_maintenance_command_execute_cb, self);
         }
     }
 }
@@ -2311,8 +2485,12 @@ static void
 update_sensitivity (gpointer user_data)
 {
   CcPrintersPanelPrivate  *priv;
+  GtkTreeSelection        *selection;
   CcPrintersPanel         *self = (CcPrintersPanel*) user_data;
   cups_ptype_t             type = 0;
+  GtkTreeModel            *model;
+  GtkTreeView             *treeview;
+  GtkTreeIter              tree_iter;
   const char              *cups_server = NULL;
   GtkWidget               *widget;
   gboolean                 is_authorized;
@@ -2322,7 +2500,10 @@ update_sensitivity (gpointer user_data)
   gboolean                 printer_selected;
   gboolean                 local_server = TRUE;
   gboolean                 no_cups = FALSE;
+  gboolean                 is_new = FALSE;
+  gboolean                 already_present_local;
   GList                   *iter;
+  gchar                   *current_printer_name = NULL;
   gint                     i;
 
   priv = PRINTERS_PANEL_PRIVATE (self);
@@ -2361,6 +2542,29 @@ update_sensitivity (gpointer user_data)
         }
     }
 
+  treeview = (GtkTreeView*)
+    gtk_builder_get_object (priv->builder, "printers-treeview");
+
+  selection = gtk_tree_view_get_selection (treeview);
+  if (selection &&
+      gtk_tree_selection_get_selected (selection, &model, &tree_iter))
+    {
+      gtk_tree_model_get (model, &tree_iter,
+                          PRINTER_NAME_COLUMN, &current_printer_name,
+                          -1);
+    }
+
+  if (priv->new_printer_name &&
+      g_strcmp0 (priv->new_printer_name, current_printer_name) == 0)
+    {
+      printer_selected = TRUE;
+      is_discovered = FALSE;
+      is_class = FALSE;
+      is_new = TRUE;
+    }
+
+  g_free (current_printer_name);
+
   cups_server = cupsServer ();
   if (cups_server &&
       g_ascii_strncasecmp (cups_server, "localhost", 9) != 0 &&
@@ -2373,39 +2577,41 @@ update_sensitivity (gpointer user_data)
   if (gtk_notebook_get_current_page (GTK_NOTEBOOK (widget)) == NOTEBOOK_NO_CUPS_PAGE)
     no_cups = TRUE;
 
+  already_present_local = local_server && !is_discovered && is_authorized && !is_new;
+
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-add-button");
-  gtk_widget_set_sensitive (widget, local_server && is_authorized && !no_cups);
+  gtk_widget_set_sensitive (widget, local_server && is_authorized && !no_cups && !priv->new_printer_name);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-add-button2");
-  gtk_widget_set_sensitive (widget, local_server && is_authorized && !no_cups);
+  gtk_widget_set_sensitive (widget, local_server && is_authorized && !no_cups && !priv->new_printer_name);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-remove-button");
-  gtk_widget_set_sensitive (widget, local_server && !is_discovered && is_authorized && printer_selected && !no_cups);
+  gtk_widget_set_sensitive (widget, already_present_local && printer_selected && !no_cups);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-disable-switch");
-  gtk_widget_set_sensitive (widget, local_server && !is_discovered && is_authorized);
+  gtk_widget_set_sensitive (widget, already_present_local);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-default-check-button");
-  gtk_widget_set_sensitive (widget, is_authorized);
+  gtk_widget_set_sensitive (widget, is_authorized && !is_new);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "print-test-page-button");
-  gtk_widget_set_sensitive (widget, printer_selected);
+  gtk_widget_set_sensitive (widget, printer_selected && !is_new);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-options-button");
   gtk_widget_set_sensitive (widget, printer_selected && local_server && !is_discovered &&
-                            !priv->pp_options_dialog);
+                            !priv->pp_options_dialog && !is_new);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-jobs-button");
-  gtk_widget_set_sensitive (widget, printer_selected);
+  gtk_widget_set_sensitive (widget, printer_selected && !is_new);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-icon");
   gtk_widget_set_sensitive (widget, printer_selected);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-name-label");
-  cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), local_server && !is_discovered && is_authorized);
+  cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), already_present_local);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-location-label");
-  cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), local_server && !is_discovered && is_authorized);
+  cc_editable_entry_set_editable (CC_EDITABLE_ENTRY (widget), already_present_local);
 
   widget = (GtkWidget*) gtk_builder_get_object (priv->builder, "printer-model-notebook");
   if (is_changing_driver)
@@ -2414,7 +2620,7 @@ update_sensitivity (gpointer user_data)
     }
   else
     {
-      if (local_server && !is_discovered && is_authorized && !is_class && !priv->getting_ppd_names)
+      if (already_present_local && !is_class && !priv->getting_ppd_names)
         gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 0);
       else
         gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), 1);
@@ -2648,6 +2854,12 @@ cc_printers_panel_init (CcPrintersPanel *self)
   priv->cups_bus_connection = NULL;
   priv->dbus_subscription_id = 0;
 
+  priv->new_printer_name = NULL;
+  priv->new_printer_location = NULL;
+  priv->new_printer_make_and_model = NULL;
+  priv->new_printer_on_network = FALSE;
+  priv->select_new_printer = FALSE;
+
   priv->permission = NULL;
   priv->lockdown_settings = NULL;
 
diff --git a/panels/printers/new-printer-dialog.ui b/panels/printers/new-printer-dialog.ui
index fa49087..07d946a 100644
--- a/panels/printers/new-printer-dialog.ui
+++ b/panels/printers/new-printer-dialog.ui
@@ -1,378 +1,230 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <requires lib="gtk+" version="2.16"/>
-  <!-- interface-naming-policy project-wide -->
+  <!-- interface-requires gtk+ 3.0 -->
   <object class="GtkDialog" id="dialog">
-    <property name="width-request">500</property>
-    <property name="height-request">350</property>
-    <property name="border-width">5</property>
+    <property name="width_request">500</property>
+    <property name="height_request">350</property>
+    <property name="can_focus">False</property>
+    <property name="border_width">5</property>
     <property name="resizable">False</property>
-    <property name="type-hint">dialog</property>
+    <property name="modal">True</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
     <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox1">
+      <object class="GtkBox" id="dialog-vbox1">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="orientation">vertical</property>
-        <property name="spacing">2</property>
-        <child>
-          <object class="GtkVBox" id="vbox1">
+        <property name="spacing">10</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action-area1">
             <property name="visible">True</property>
-            <property name="orientation">vertical</property>
-            <property name="spacing">10</property>
+            <property name="can_focus">False</property>
             <child>
-              <object class="GtkLabel" id="label1">
+              <object class="GtkButton" id="new-printer-cancel-button">
+                <property name="label" translatable="yes">_Cancel</property>
+                <property name="use_action_appearance">False</property>
                 <property name="visible">True</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes">Add a New Printer</property>
-                <attributes>
-                  <attribute name="weight" value="bold"/>
-                </attributes>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
               </object>
               <packing>
                 <property name="expand">False</property>
+                <property name="fill">True</property>
                 <property name="position">0</property>
               </packing>
             </child>
             <child>
-              <object class="GtkHBox" id="hbox1">
+              <object class="GtkButton" id="new-printer-add-button">
+                <property name="label" translatable="yes">_Add</property>
+                <property name="use_action_appearance">False</property>
                 <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_underline">True</property>
+              </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="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkAlignment" id="content-alignment">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="spacing">10</property>
                 <child>
-                  <object class="GtkTreeView" id="device-types-treeview">
+                  <object class="GtkLabel" id="label1">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="headers_visible">False</property>
-                    <property name="headers_clickable">False</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Add a New Printer</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="GtkNotebook" id="device-type-notebook">
+                  <object class="GtkBox" id="box2">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="show_tabs">False</property>
-                    <property name="show_border">False</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
                     <child>
-                      <object class="GtkNotebook" id="local-devices-notebook">
+                      <object class="GtkScrolledWindow" id="scrolledwindow1">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="show_tabs">False</property>
-                        <property name="show_border">False</property>
+                        <property name="shadow_type">in</property>
                         <child>
-                          <object class="GtkScrolledWindow" id="scrolledwindow2">
+                          <object class="GtkTreeView" id="devices-treeview">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
-                            <property name="hscrollbar_policy">automatic</property>
-                            <property name="vscrollbar_policy">automatic</property>
-                            <child>
-                              <object class="GtkTreeView" id="local-devices-treeview">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="headers_visible">False</property>
-                              </object>
+                            <property name="headers_visible">False</property>
+                            <child internal-child="selection">
+                              <object class="GtkTreeSelection" id="treeview-selection"/>
                             </child>
                           </object>
                         </child>
-                        <child type="tab">
-                          <object class="GtkLabel" id="label9">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="label" translatable="no">page 1</property>
-                          </object>
-                          <packing>
-                            <property name="tab_fill">False</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkTextView" id="local-warning">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="pixels_above_lines">6</property>
-                            <property name="editable">False</property>
-                            <property name="wrap_mode">word</property>
-                            <property name="left_margin">10</property>
-                            <property name="right_margin">10</property>
-                          </object>
-                          <packing>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                        <child type="tab">
-                          <object class="GtkLabel" id="label10">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="label" translatable="no">page 2</property>
-                          </object>
-                          <packing>
-                            <property name="position">1</property>
-                            <property name="tab_fill">False</property>
-                          </packing>
-                        </child>
-                      </object>
-                    </child>
-                    <child type="tab">
-                      <object class="GtkLabel" id="label2">
-                        <property name="visible">True</property>
-                        <property name="label">page 1</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="GtkVBox" id="vbox2">
+                      <object class="GtkToolbar" id="toolbar1">
                         <property name="visible">True</property>
-                        <property name="orientation">vertical</property>
-                        <property name="spacing">10</property>
+                        <property name="can_focus">False</property>
+                        <property name="toolbar_style">icons</property>
+                        <property name="icon_size">1</property>
+                        <style>
+                          <class name="inline-toolbar"/>
+                        </style>
                         <child>
-                          <object class="GtkNotebook" id="network-devices-notebook">
+                          <object class="GtkToolItem" id="toolbutton1">
+                            <property name="use_action_appearance">False</property>
                             <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="show_tabs">False</property>
-                            <property name="show_border">False</property>
+                            <property name="can_focus">False</property>
+                            <property name="use_action_appearance">False</property>
                             <child>
-                              <object class="GtkScrolledWindow" id="scrolledwindow1">
+                              <object class="GtkBox" id="box1">
                                 <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="hscrollbar_policy">never</property>
-                                <property name="vscrollbar_policy">automatic</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkAlignment" id="alignment2">
+                                    <property name="width_request">24</property>
+                                    <property name="height_request">24</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="padding">10</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
                                 <child>
-                                  <object class="GtkTreeView" id="network-devices-treeview">
+                                  <object class="GtkSearchEntry" id="search-entry">
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
-                                    <property name="headers_visible">False</property>
-                                    <property name="headers_clickable">False</property>
+                                    <property name="has_tooltip">True</property>
+                                    <property name="invisible_char">â</property>
+                                    <property name="truncate_multiline">True</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="secondary_icon_stock">gtk-find</property>
+                                    <property name="secondary_icon_tooltip_text" translatable="yes">Search for network printers or filter result</property>
+                                    <property name="secondary_icon_tooltip_markup" translatable="yes">Search for network printers or filter result</property>
+                                    <property name="placeholder_text">Enter address of a printer or a text to filter results</property>
                                   </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkAlignment" id="alignment3">
+                                    <property name="width_request">24</property>
+                                    <property name="height_request">24</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <child>
+                                      <object class="GtkSpinner" id="spinner">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="no_show_all">True</property>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="padding">10</property>
+                                    <property name="position">2</property>
+                                  </packing>
                                 </child>
                               </object>
                             </child>
-                            <child type="tab">
-                              <object class="GtkLabel" id="label6">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="label" translatable="no">page 1</property>
-                              </object>
-                              <packing>
-                                <property name="tab_fill">False</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkTextView" id="network-warning">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="pixels_above_lines">6</property>
-                                <property name="editable">False</property>
-                                <property name="wrap_mode">word</property>
-                                <property name="left_margin">10</property>
-                                <property name="right_margin">10</property>
-                              </object>
-                              <packing>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                            <child type="tab">
-                              <object class="GtkLabel" id="label7">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="label" translatable="no">page 2</property>
-                              </object>
-                              <packing>
-                                <property name="position">1</property>
-                                <property name="tab_fill">False</property>
-                              </packing>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="position">0</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkHBox" id="hbox2">
-                            <property name="visible">True</property>
-                            <child>
-                              <object class="GtkLabel" id="label5">
-                                <property name="visible">True</property>
-                                <property name="xalign">0</property>
-                                <property name="label" translatable="yes">A_ddress:</property>
-                                <property name="use_underline">True</property>
-                                <property name="mnemonic_widget">address-entry</property>
-                              </object>
-                              <packing>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkEntry" id="address-entry">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="invisible_char">&#x25CF;</property>
-                              </object>
-                              <packing>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkHBox" id="hbox3">
-                            <property name="visible">True</property>
-                            <child>
-                              <object class="GtkCheckButton" id="search-by-address-checkbutton">
-                                <property name="label" translatable="yes">_Search by Address</property>
-                                <property name="use_underline">True</property>
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">False</property>
-                                <property name="draw_indicator">True</property>
-                              </object>
-                              <packing>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkLabel" id="search-state-label">
-                                <property name="visible">True</property>
-                              </object>
-                              <packing>
-                                <property name="position">2</property>
-                              </packing>
-                            </child>
                           </object>
                           <packing>
-                            <property name="expand">False</property>
-                            <property name="position">2</property>
+                            <property name="expand">True</property>
+                            <property name="homogeneous">True</property>
                           </packing>
                         </child>
                       </object>
                       <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
                         <property name="position">1</property>
                       </packing>
                     </child>
-                    <child type="tab">
-                      <object class="GtkLabel" id="label3">
-                        <property name="visible">True</property>
-                        <property name="label">page 2</property>
-                      </object>
-                      <packing>
-                        <property name="position">1</property>
-                        <property name="tab_fill">False</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkTextView" id="warning-textview">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="pixels_above_lines">6</property>
-                        <property name="editable">False</property>
-                        <property name="wrap_mode">word</property>
-                        <property name="left_margin">10</property>
-                        <property name="right_margin">10</property>
-                      </object>
-                      <packing>
-                        <property name="position">2</property>
-                      </packing>
-                    </child>
-                    <child type="tab">
-                      <object class="GtkLabel" id="label4">
-                        <property name="visible">True</property>
-                        <property name="label">page 3</property>
-                      </object>
-                      <packing>
-                        <property name="position">2</property>
-                        <property name="tab_fill">False</property>
-                      </packing>
-                    </child>
                   </object>
                   <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
                     <property name="position">1</property>
                   </packing>
                 </child>
               </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
             </child>
           </object>
           <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
             <property name="position">1</property>
           </packing>
         </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkHBox" id="hbox4">
-                <property name="visible">True</property>
-                <child>
-                  <object class="GtkSpinner" id="spinner">
-                    <property name="visible">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkLabel" id="get-devices-status-label">
-                    <property name="visible">True</property>
-                    <property name="xalign">0</property>
-                    <property name="xpad">5</property>
-                    <property name="label" translatable="yes"></property>
-                  </object>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-                <property name="secondary">True</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="new-printer-cancel-button">
-                <property name="label" translatable="yes">_Cancel</property>
-                <property name="use_underline">True</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="new-printer-add-button">
-                <property name="label" translatable="yes">_Add</property>
-                <property name="use_underline">True</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-              </object>
-              <packing>
-                <property name="position">2</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
       </object>
     </child>
     <action-widgets>
-      <action-widget response="0">new-printer-cancel-button</action-widget>
-      <action-widget response="0">new-printer-add-button</action-widget>
+      <action-widget response="-6">new-printer-cancel-button</action-widget>
+      <action-widget response="-5">new-printer-add-button</action-widget>
     </action-widgets>
   </object>
 </interface>
diff --git a/panels/printers/pp-new-printer-dialog.c b/panels/printers/pp-new-printer-dialog.c
index 0d3ddb0..88c7a9d 100644
--- a/panels/printers/pp-new-printer-dialog.c
+++ b/panels/printers/pp-new-printer-dialog.c
@@ -22,8 +22,6 @@
 
 #include <unistd.h>
 #include <stdlib.h>
-#include <sys/types.h>
-#include <sys/wait.h>
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -31,26 +29,17 @@
 #include <gtk/gtk.h>
 
 #include <cups/cups.h>
-#include <cups/ppd.h>
 
 #include "pp-new-printer-dialog.h"
 #include "pp-utils.h"
-
-#include <libnotify/notify.h>
+#include "pp-host.h"
+#include "pp-cups.h"
+#include "pp-new-printer.h"
 
 #ifdef GDK_WINDOWING_X11
 #include <gdk/gdkx.h>
 #endif
 
-#define PACKAGE_KIT_BUS "org.freedesktop.PackageKit"
-#define PACKAGE_KIT_PATH "/org/freedesktop/PackageKit"
-#define PACKAGE_KIT_MODIFY_IFACE "org.freedesktop.PackageKit.Modify"
-#define PACKAGE_KIT_QUERY_IFACE  "org.freedesktop.PackageKit.Query"
-
-#define FIREWALLD_BUS "org.fedoraproject.FirewallD"
-#define FIREWALLD_PATH "/org/fedoraproject/FirewallD"
-#define FIREWALLD_IFACE "org.fedoraproject.FirewallD"
-
 #if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
 #define HAVE_CUPS_1_6 1
 #endif
@@ -59,2048 +48,1475 @@
 #define ippGetState(ipp) ipp->state
 #endif
 
-static void pp_new_printer_dialog_hide (PpNewPrinterDialog *pp);
-static void actualize_devices_list (PpNewPrinterDialog *pp);
-
-enum
-{
-  NOTEBOOK_LOCAL_PAGE = 0,
-  NOTEBOOK_NETWORK_PAGE,
-  NOTEBOOK_N_PAGES
-};
-
-enum
-{
-  DEVICE_TYPE_ID_COLUMN = 0,
-  DEVICE_TYPE_NAME_COLUMN,
-  DEVICE_TYPE_TYPE_COLUMN,
-  DEVICE_TYPE_N_COLUMNS
-};
+static void actualize_devices_list (PpNewPrinterDialog *dialog);
+static void populate_devices_list (PpNewPrinterDialog *dialog);
+static void search_address_cb2 (GtkEntry             *entry,
+                                GtkEntryIconPosition  icon_pos,
+                                GdkEvent             *event,
+                                gpointer              user_data);
+static void search_address_cb (GtkEntry *entry,
+                               gpointer  user_data);
+static void new_printer_dialog_response_cb (GtkDialog *_dialog,
+                                            gint       response_id,
+                                            gpointer   user_data);
+static void t_device_free (gpointer data);
 
 enum
 {
-  DEVICE_ID_COLUMN = 0,
+  DEVICE_ICON_COLUMN = 0,
   DEVICE_NAME_COLUMN,
+  DEVICE_DISPLAY_NAME_COLUMN,
   DEVICE_N_COLUMNS
 };
 
-enum
+typedef struct
 {
-  DEVICE_TYPE_LOCAL = 0,
-  DEVICE_TYPE_NETWORK
-};
-
-enum
+  gchar    *display_name;
+  gchar    *device_name;
+  gchar    *device_original_name;
+  gchar    *device_info;
+  gchar    *device_location;
+  gchar    *device_make_and_model;
+  gchar    *device_uri;
+  gchar    *device_id;
+  gchar    *device_ppd;
+  gchar    *host_name;
+  gint      host_port;
+  gboolean  network_device;
+  gint      acquisition_method;
+  gboolean  show;
+} TDevice;
+
+struct _PpNewPrinterDialogPrivate
 {
-  STANDARD_TAB = 0,
-  WARNING_TAB
-};
-
-typedef struct{
-  gchar *device_class;
-  gchar *device_id;
-  gchar *device_info;
-  gchar *device_make_and_model;
-  gchar *device_uri;
-  gchar *device_location;
-  gchar *device_ppd_uri;
-  gchar *display_name;
-  gchar *hostname;
-  gint   host_port;
-  gboolean show;
-  gboolean found;
-} CupsDevice;
-
-struct _PpNewPrinterDialog {
   GtkBuilder *builder;
-  GtkWidget  *parent;
-
-  GtkWidget  *dialog;
 
-  gchar **device_connection_types;
-  gint    num_device_connection_types;
+  GList *devices;
+  GList *new_devices;
 
-  CupsDevice *devices;
-  gint        num_devices;
-
-  UserResponseCallback user_callback;
-  gpointer             user_data;
+  cups_dest_t *dests;
+  gint         num_of_dests;
 
   GCancellable *cancellable;
 
-  gchar    *warning;
-  gboolean  show_warning;
-  gboolean  searching;
-};
+  gboolean  cups_searching;
+  gboolean  remote_cups_searching;
+  gboolean  snmp_searching;
 
-static void
-show_notification (gchar *primary_text,
-                   gchar *secondary_text,
-                   gchar *icon_name)
-{
-  if (primary_text)
-    {
-      NotifyNotification *notification;
-      notification = notify_notification_new (primary_text,
-                                              secondary_text,
-                                              icon_name);
-      notify_notification_set_app_name (notification, _("Printers"));
-      notify_notification_set_hint (notification, "transient", g_variant_new_boolean (TRUE));
-
-      notify_notification_show (notification, NULL);
-      g_object_unref (notification);
-    }
-}
+  GtkCellRenderer *text_renderer;
+  GtkCellRenderer *icon_renderer;
 
-static void
-device_type_selection_changed_cb (GtkTreeSelection *selection,
-                                  gpointer          user_data)
-{
-  PpNewPrinterDialog *pp = (PpNewPrinterDialog *) user_data;
-  GtkTreeModel       *model;
-  GtkTreeIter         iter;
-  GtkWidget          *treeview = NULL;
-  GtkWidget          *notebook = NULL;
-  GtkWidget          *widget;
-  gchar              *device_type_name = NULL;
-  gint                device_type_id = -1;
-  gint                device_type = -1;
-
-  if (gtk_tree_selection_get_selected (selection, &model, &iter))
-    {
-      gtk_tree_model_get (model, &iter,
-			  DEVICE_TYPE_ID_COLUMN, &device_type_id,
-			  DEVICE_TYPE_NAME_COLUMN, &device_type_name,
-			  DEVICE_TYPE_TYPE_COLUMN, &device_type,
-			  -1);
-    }
+  GtkWidget *dialog;
+};
 
-  if (device_type >= 0)
-    {
-      widget = (GtkWidget*)
-        gtk_builder_get_object (pp->builder, "device-type-notebook");
+#define PP_NEW_PRINTER_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PP_TYPE_NEW_PRINTER_DIALOG, PpNewPrinterDialogPrivate))
 
-      gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), device_type);
+static void pp_new_printer_dialog_finalize (GObject *object);
 
-      if (device_type == DEVICE_TYPE_LOCAL)
-        {
-          treeview = (GtkWidget*)
-            gtk_builder_get_object (pp->builder, "local-devices-treeview");
-          notebook = (GtkWidget*)
-            gtk_builder_get_object (pp->builder, "local-devices-notebook");
-        }
-      else if (device_type == DEVICE_TYPE_NETWORK)
-        {
-          treeview = (GtkWidget*)
-            gtk_builder_get_object (pp->builder, "network-devices-treeview");
-          notebook = (GtkWidget*)
-            gtk_builder_get_object (pp->builder, "network-devices-notebook");
-        }
+enum {
+  PRE_RESPONSE,
+  RESPONSE,
+  LAST_SIGNAL
+};
 
-      if (notebook)
-        {
-          if (pp->show_warning && device_type == DEVICE_TYPE_NETWORK)
-            gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), WARNING_TAB);
-          else
-            gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), STANDARD_TAB);
-        }
+static guint signals[LAST_SIGNAL] = { 0 };
 
-      widget = (GtkWidget*)
-        gtk_builder_get_object (pp->builder, "new-printer-add-button");
+G_DEFINE_TYPE (PpNewPrinterDialog, pp_new_printer_dialog, G_TYPE_OBJECT)
 
-      if (treeview)
-        gtk_widget_set_sensitive (widget,
-          gtk_tree_selection_get_selected (
-            gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
-            &model,
-            &iter));
-    }
+static void
+pp_new_printer_dialog_class_init (PpNewPrinterDialogClass *klass)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (klass);
+  object_class->finalize = pp_new_printer_dialog_finalize;
+
+  g_type_class_add_private (object_class, sizeof (PpNewPrinterDialogPrivate));
+
+  /**
+   * PpNewPrinterDialog::pre-response:
+   * @device: the device that is being added
+   *
+   * The signal which gets emitted when the new printer dialog is closed.
+   */
+  signals[PRE_RESPONSE] =
+    g_signal_new ("pre-response",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (PpNewPrinterDialogClass, pre_response),
+                  NULL, NULL,
+                  g_cclosure_marshal_generic,
+                  G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
+
+  /**
+   * PpNewPrinterDialog::response:
+   * @response-id: response id of dialog
+   *
+   * The signal which gets emitted after the printer is added and configured.
+   */
+  signals[RESPONSE] =
+    g_signal_new ("response",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (PpNewPrinterDialogClass, response),
+                  NULL, NULL,
+                  g_cclosure_marshal_generic,
+                  G_TYPE_NONE, 1, G_TYPE_INT);
 }
 
-static void
-device_selection_changed_cb (GtkTreeSelection *selection,
-                             gpointer          user_data)
+
+PpNewPrinterDialog *
+pp_new_printer_dialog_new (GtkWindow *parent)
 {
-  PpNewPrinterDialog *pp = (PpNewPrinterDialog *) user_data;
-  GtkTreeModel       *model;
-  GtkTreeIter         iter;
-  GtkWidget          *treeview = NULL;
-  GtkWidget          *widget;
-  gchar              *device_type_name = NULL;
-  gint                device_type_id = -1;
-  gint                device_type = -1;
+  PpNewPrinterDialogPrivate *priv;
+  PpNewPrinterDialog        *dialog;
 
-  treeview = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "device-types-treeview");
-
-  if (gtk_tree_selection_get_selected (
-        gtk_tree_view_get_selection (
-          GTK_TREE_VIEW (treeview)), &model, &iter))
-    gtk_tree_model_get (model, &iter,
-			DEVICE_TYPE_ID_COLUMN, &device_type_id,
-			DEVICE_TYPE_NAME_COLUMN, &device_type_name,
-			DEVICE_TYPE_TYPE_COLUMN, &device_type,
-			-1);
-
-  if (device_type == DEVICE_TYPE_LOCAL)
-    treeview = (GtkWidget*)
-      gtk_builder_get_object (pp->builder, "local-devices-treeview");
-  else if (device_type == DEVICE_TYPE_NETWORK)
-    treeview = (GtkWidget*)
-      gtk_builder_get_object (pp->builder, "network-devices-treeview");
+  dialog = g_object_new (PP_TYPE_NEW_PRINTER_DIALOG, NULL);
+  priv = dialog->priv;
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "new-printer-add-button");
+  gtk_window_set_transient_for (GTK_WINDOW (priv->dialog), GTK_WINDOW (parent));
 
-  if (treeview)
-    gtk_widget_set_sensitive (widget,
-      gtk_tree_selection_get_selected (
-        gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
-        &model,
-        &iter));
+  return PP_NEW_PRINTER_DIALOG (dialog);
 }
 
 static void
-free_devices (PpNewPrinterDialog *pp)
+emit_pre_response (PpNewPrinterDialog *dialog,
+                   const gchar        *device_name,
+                   const gchar        *device_location,
+                   const gchar        *device_make_and_model,
+                   gboolean            network_device)
 {
-  int i;
-
-  for (i = 0; i < pp->num_devices; i++)
-    {
-      g_free (pp->devices[i].device_class);
-      g_free (pp->devices[i].device_id);
-      g_free (pp->devices[i].device_info);
-      g_free (pp->devices[i].device_make_and_model);
-      g_free (pp->devices[i].device_uri);
-      g_free (pp->devices[i].device_location);
-      g_free (pp->devices[i].device_ppd_uri);
-      g_free (pp->devices[i].display_name);
-      g_free (pp->devices[i].hostname);
-    }
-
-  pp->num_devices = 0;
-  pp->devices = NULL;
+  g_signal_emit (dialog,
+                 signals[PRE_RESPONSE],
+                 0,
+                 device_name,
+                 device_location,
+                 device_make_and_model,
+                 network_device);
 }
 
 static void
-store_device_parameter (gpointer key,
-                        gpointer value,
-                        gpointer user_data)
+emit_response (PpNewPrinterDialog *dialog,
+               gint                response_id)
 {
-  PpNewPrinterDialog *pp = (PpNewPrinterDialog *) user_data;
-  gchar *cut;
-  gint   index = -1;
-
-  cut = g_strrstr ((gchar *)key, ":");
-  if (cut)
-    index = atoi ((gchar *)cut + 1);
-
-  if (index >= 0)
-    {
-      if (g_str_has_prefix ((gchar *)key, "device-class"))
-        pp->devices[index].device_class = g_strdup ((gchar *)value);
-      else if (g_str_has_prefix ((gchar *)key, "device-id"))
-        pp->devices[index].device_id = g_strdup ((gchar *)value);
-      else if (g_str_has_prefix ((gchar *)key, "device-info"))
-        pp->devices[index].device_info = g_strdup ((gchar *)value);
-      else if (g_str_has_prefix ((gchar *)key, "device-make-and-model"))
-        pp->devices[index].device_make_and_model = g_strdup ((gchar *)value);
-      else if (g_str_has_prefix ((gchar *)key, "device-uri"))
-        pp->devices[index].device_uri = g_strdup ((gchar *)value);
-      else if (g_str_has_prefix ((gchar *)key, "device-location"))
-        pp->devices[index].device_location = g_strdup ((gchar *)value);
-    }
+  g_signal_emit (dialog, signals[RESPONSE], 0, response_id);
 }
 
+/*
+ * Modify padding of the content area of the GtkDialog
+ * so it is aligned with the action area.
+ */
 static void
-devices_get_cb (GObject      *source_object,
-                GAsyncResult *res,
-                gpointer      user_data)
+update_alignment_padding (GtkWidget     *widget,
+                          GtkAllocation *allocation,
+                          gpointer       user_data)
 {
-  PpNewPrinterDialog *pp = user_data;
-  cups_dest_t        *dests;
-  GHashTable         *devices = NULL;
-  GDBusConnection    *bus;
-  GtkWidget          *widget = NULL;
-  GVariant           *dg_output = NULL;
-  gboolean            already_present;
-  GError             *error = NULL;
-  gchar              *new_name = NULL;
-  gchar              *device_uri = NULL;
-  char               *ret_error = NULL;
-  gint                i, j, k;
-  gint                name_index;
-  gint                num_dests;
-
-
-  dg_output = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
-                                        res,
-                                        &error);
-
-  /* Do nothing if cancelled */
-  if (!dg_output && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+  PpNewPrinterDialog        *dialog = (PpNewPrinterDialog*) user_data;
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  GtkAllocation              allocation1, allocation2;
+  GtkWidget                 *action_area;
+  GtkWidget                 *content_area;
+  gint                       offset_left, offset_right;
+  guint                      padding_left, padding_right,
+                             padding_top, padding_bottom;
+
+  action_area = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "dialog-action-area1");
+  gtk_widget_get_allocation (action_area, &allocation2);
+
+  content_area = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "content-alignment");
+  gtk_widget_get_allocation (content_area, &allocation1);
+
+  offset_left = allocation2.x - allocation1.x;
+  offset_right = (allocation1.x + allocation1.width) -
+                 (allocation2.x + allocation2.width);
+
+  gtk_alignment_get_padding  (GTK_ALIGNMENT (content_area),
+                              &padding_top, &padding_bottom,
+                              &padding_left, &padding_right);
+  if (allocation1.x >= 0 && allocation2.x >= 0)
     {
-      g_error_free (error);
-      return;
+      if (offset_left > 0 && offset_left != padding_left)
+        gtk_alignment_set_padding (GTK_ALIGNMENT (content_area),
+                                   padding_top, padding_bottom,
+                                   offset_left, padding_right);
+
+      gtk_alignment_get_padding  (GTK_ALIGNMENT (content_area),
+                                  &padding_top, &padding_bottom,
+                                  &padding_left, &padding_right);
+      if (offset_right > 0 && offset_right != padding_right)
+        gtk_alignment_set_padding (GTK_ALIGNMENT (content_area),
+                                   padding_top, padding_bottom,
+                                   padding_left, offset_right);
     }
+}
 
-  if (dg_output)
-    {
-      if (g_variant_n_children (dg_output) == 2)
-        {
-          GVariant *devices_variant = NULL;
+static void
+pp_new_printer_dialog_init (PpNewPrinterDialog *dialog)
+{
+  PpNewPrinterDialogPrivate *priv;
+  GtkStyleContext           *context;
+  GtkWidget                 *widget;
+  GError                    *error = NULL;
+  gchar                     *objects[] = { "dialog", NULL };
+  guint                      builder_result;
 
-          g_variant_get (dg_output, "(&s a{ss})",
-                         &ret_error,
-                         &devices_variant);
+  priv = PP_NEW_PRINTER_DIALOG_GET_PRIVATE (dialog);
+  dialog->priv = priv;
 
-          if (devices_variant)
-            {
-              if (g_variant_is_of_type (devices_variant, G_VARIANT_TYPE ("a{ss}")))
-                {
-                  GVariantIter *iter;
-                  GVariant *item;
-                  g_variant_get (devices_variant,
-                                 "a{ss}",
-                                 &iter);
-                  devices = g_hash_table_new (g_str_hash, g_str_equal);
-                  while ((item = g_variant_iter_next_value (iter)))
-                    {
-                      gchar *key;
-                      gchar *value;
-                      g_variant_get (item,
-                                     "{ss}",
-                                     &key,
-                                     &value);
+  priv->builder = gtk_builder_new ();
 
-                      g_hash_table_insert (devices, key, value);
+  builder_result = gtk_builder_add_objects_from_file (priv->builder,
+                                                      DATADIR"/new-printer-dialog.ui",
+                                                      objects, &error);
 
-                      g_variant_unref (item);
-                    }
-                }
-              g_variant_unref (devices_variant);
-            }
-        }
-      g_variant_unref (dg_output);
-    }
-  else
+  if (builder_result == 0)
     {
-      g_warning ("%s", error->message);
+      g_warning ("Could not load ui: %s", error->message);
       g_error_free (error);
     }
 
-  g_object_unref (source_object);
-
-  if (ret_error && ret_error[0] != '\0')
-    g_warning ("%s", ret_error);
-
-  free_devices (pp);
-  if (devices)
-    {
-      GList *keys;
-      GList *iter;
-      gchar *cut;
-      gint   max_index = -1;
-      gint   index;
-
-      keys = g_hash_table_get_keys (devices);
-      for (iter = keys; iter; iter = iter->next)
-        {
-          index = -1;
-
-          cut = g_strrstr ((gchar *)iter->data, ":");
-          if (cut)
-            index = atoi (cut + 1);
-
-          if (index > max_index)
-            max_index = index;
-        }
-
-      if (max_index >= 0)
-        {
-          pp->num_devices = max_index + 1;
-          pp->devices = g_new0 (CupsDevice, pp->num_devices);
-
-          g_hash_table_foreach (devices, store_device_parameter, pp);
-
-          /* Assign names to devices */
-          for (i = 0; i < pp->num_devices; i++)
-            {
-              gchar *name = NULL;
-
-              if (pp->devices[i].device_id)
-                {
-                  name = get_tag_value (pp->devices[i].device_id, "mdl");
-                  if (!name)
-                    name = get_tag_value (pp->devices[i].device_id, "model");
-
-                  if (name)
-                    name = g_strcanon (name, ALLOWED_CHARACTERS, '-');
-                }
-
-              if (!name &&
-                  pp->devices[i].device_info)
-                {
-                  name = g_strdup (pp->devices[i].device_info);
-                  if (name)
-                    name = g_strcanon (name, ALLOWED_CHARACTERS, '-');
-                }
-
-              name_index = 2;
-              already_present = FALSE;
-              num_dests = cupsGetDests (&dests);
-              do
-                {
-                  if (already_present)
-                    {
-                      new_name = g_strdup_printf ("%s-%d", name, name_index);
-                      name_index++;
-                    }
-                  else
-                    new_name = g_strdup (name);
-
-                  already_present = FALSE;
-                  for (j = 0; j < num_dests; j++)
-                    if (g_strcmp0 (dests[j].name, new_name) == 0)
-                      already_present = TRUE;
-
-                  if (already_present)
-                    g_free (new_name);
-                  else
-                    {
-                      g_free (name);
-                      name = new_name;
-                    }
-                } while (already_present);
-              cupsFreeDests (num_dests, dests);
-
-              pp->devices[i].display_name = name;
-            }
+  /* GCancellable for cancelling of async operations */
+  priv->cancellable = g_cancellable_new ();
 
-          /* Set show bool
-           * Don't show duplicates.
-           * Show devices with device-id.
-           * Other preferences should apply here.
-           */
-          bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-          if (bus)
-            {
-              GVariantBuilder  device_list;
-              GVariantBuilder  device_hash;
-              GVariant        *output = NULL;
-              GVariant        *array = NULL;
-              GVariant        *subarray = NULL;
+  priv->devices = NULL;
+  priv->new_devices = NULL;
+  priv->dests = NULL;
+  priv->num_of_dests = 0;
+  priv->cups_searching = FALSE;
+  priv->remote_cups_searching = FALSE;
+  priv->snmp_searching = FALSE;
+  priv->text_renderer = NULL;
+  priv->icon_renderer = NULL;
 
-              g_variant_builder_init (&device_list, G_VARIANT_TYPE ("a{sv}"));
+  /* Construct dialog */
+  priv->dialog = (GtkWidget*) gtk_builder_get_object (priv->builder, "dialog");
 
-              for (i = 0; i < pp->num_devices; i++)
-                {
-                  if (pp->devices[i].device_uri)
-                    {
-                      g_variant_builder_init (&device_hash, G_VARIANT_TYPE ("a{ss}"));
-
-                      if (pp->devices[i].device_id)
-                        g_variant_builder_add (&device_hash,
-                                               "{ss}",
-                                               "device-id",
-                                               pp->devices[i].device_id);
-
-                      if (pp->devices[i].device_make_and_model)
-                        g_variant_builder_add (&device_hash,
-                                               "{ss}",
-                                               "device-make-and-model",
-                                               pp->devices[i].device_make_and_model);
-
-                      if (pp->devices[i].device_class)
-                        g_variant_builder_add (&device_hash,
-                                               "{ss}",
-                                               "device-class",
-                                               pp->devices[i].device_class);
-
-                      g_variant_builder_add (&device_list,
-                                             "{sv}",
-                                             pp->devices[i].device_uri,
-                                             g_variant_builder_end (&device_hash));
-                    }
-                }
+  /* Connect signals */
+  g_signal_connect (priv->dialog, "response", G_CALLBACK (new_printer_dialog_response_cb), dialog);
+  g_signal_connect (priv->dialog, "size-allocate", G_CALLBACK (update_alignment_padding), dialog);
 
-              output = g_dbus_connection_call_sync (bus,
-                                                    SCP_BUS,
-                                                    SCP_PATH,
-                                                    SCP_IFACE,
-                                                    "GroupPhysicalDevices",
-                                                    g_variant_new ("(v)", g_variant_builder_end (&device_list)),
-                                                    NULL,
-                                                    G_DBUS_CALL_FLAGS_NONE,
-                                                    60000,
-                                                    NULL,
-                                                    &error);
-
-              if (output && g_variant_n_children (output) == 1)
-                {
-                  array = g_variant_get_child_value (output, 0);
-                  if (array)
-                    {
-                      for (i = 0; i < g_variant_n_children (array); i++)
-                        {
-                          subarray = g_variant_get_child_value (array, i);
-                          if (subarray)
-                            {
-                              device_uri = g_strdup (g_variant_get_string (
-                                             g_variant_get_child_value (subarray, 0),
-                                             NULL));
+  widget = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "search-entry");
+  g_signal_connect (widget, "icon-press", G_CALLBACK (search_address_cb2), dialog);
+  g_signal_connect (widget, "activate", G_CALLBACK (search_address_cb), dialog);
 
-                              for (k = 0; k < pp->num_devices; k++)
-                                if (g_str_has_prefix (pp->devices[k].device_uri, device_uri))
-                                  pp->devices[k].show = TRUE;
+  /* Set junctions */
+  widget = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "scrolledwindow1");
+  context = gtk_widget_get_style_context (widget);
+  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
 
-                              g_free (device_uri);
-                            }
-                        }
-                    }
-                }
+  widget = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "toolbar1");
+  context = gtk_widget_get_style_context (widget);
+  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
 
-              if (output)
-                g_variant_unref (output);
-              g_object_unref (bus);
-            }
+  /* Fill with data */
+  populate_devices_list (dialog);
 
-          if (error)
-            {
-              if (bus == NULL ||
-                  (error->domain == G_DBUS_ERROR &&
-                   (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN ||
-                    error->code == G_DBUS_ERROR_UNKNOWN_METHOD)))
-                g_warning ("Install system-config-printer which provides \
-DBus method \"GroupPhysicalDevices\" to group duplicates in device list.");
+  gtk_widget_show (priv->dialog);
+}
 
-              for (i = 0; i < pp->num_devices; i++)
-                pp->devices[i].show = TRUE;
-            }
+static void
+pp_new_printer_dialog_finalize (GObject *object)
+{
+  PpNewPrinterDialog *dialog = PP_NEW_PRINTER_DIALOG (object);
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
 
-          for (i = 0; i < pp->num_devices; i++)
-            if (!pp->devices[i].device_id)
-              pp->devices[i].show = FALSE;
-        }
+  priv->text_renderer = NULL;
+  priv->icon_renderer = NULL;
 
-      g_hash_table_destroy (devices);
-      actualize_devices_list (pp);
+  if (priv->cancellable)
+    {
+      g_cancellable_cancel (priv->cancellable);
+      g_clear_object (&priv->cancellable);
     }
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "get-devices-status-label");
-  gtk_label_set_text (GTK_LABEL (widget), " ");
+  if (priv->builder)
+    g_clear_object (&priv->builder);
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "spinner");
-  gtk_spinner_stop (GTK_SPINNER (widget));
-  gtk_widget_set_sensitive (widget, FALSE);
-  gtk_widget_hide (widget);
+  g_list_free_full (priv->devices, t_device_free);
+  priv->devices = NULL;
 
-  if (pp->cancellable != NULL)
+  g_list_free_full (priv->new_devices, t_device_free);
+  priv->new_devices = NULL;
+
+  if (priv->num_of_dests > 0)
     {
-      g_object_unref (pp->cancellable);
-      pp->cancellable = NULL;
+      cupsFreeDests (priv->num_of_dests, priv->dests);
+      priv->num_of_dests = 0;
+      priv->dests = NULL;
     }
+
+  G_OBJECT_CLASS (pp_new_printer_dialog_parent_class)->finalize (object);
 }
 
 static void
-devices_get (PpNewPrinterDialog *pp)
+device_selection_changed_cb (GtkTreeSelection *selection,
+                             gpointer          user_data)
 {
-  GDBusProxy *proxy;
-  GError     *error = NULL;
-  GVariantBuilder *in_include = NULL;
-  GVariantBuilder *in_exclude = NULL;
-  GtkWidget *widget = NULL;
-
-  pp->searching = TRUE;
-
-  proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
-                                         G_DBUS_PROXY_FLAGS_NONE,
-                                         NULL,
-                                         MECHANISM_BUS,
-                                         "/",
-                                         MECHANISM_BUS,
-                                         NULL,
-                                         &error);
-
-  if (!proxy)
-    {
-      g_warning ("%s", error->message);
-      g_error_free (error);
-      pp->searching = FALSE;
-      return;
-    }
-
-  if (pp->show_warning)
-    {
-      widget = (GtkWidget*)
-        gtk_builder_get_object (pp->builder, "local-devices-notebook");
-      gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), WARNING_TAB);
+  PpNewPrinterDialog        *dialog = PP_NEW_PRINTER_DIALOG (user_data);
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  GtkTreeModel              *model;
+  GtkTreeIter                iter;
+  GtkWidget                 *treeview = NULL;
+  GtkWidget                 *widget;
 
-      widget = (GtkWidget*)
-        gtk_builder_get_object (pp->builder, "network-devices-notebook");
-      gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), WARNING_TAB);
-    }
-
-  in_include = g_variant_builder_new (G_VARIANT_TYPE ("as"));
-  in_exclude = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+  treeview = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "devices-treeview");
 
   widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "get-devices-status-label");
-  gtk_label_set_text (GTK_LABEL (widget), _("Getting devices..."));
+    gtk_builder_get_object (priv->builder, "new-printer-add-button");
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "spinner");
-  gtk_spinner_start (GTK_SPINNER (widget));
-  gtk_widget_set_sensitive (widget, TRUE);
-  gtk_widget_show (widget);
-
-  pp->cancellable = g_cancellable_new ();
-
-  g_dbus_proxy_call (proxy,
-                     "DevicesGet",
-                     g_variant_new ("(iiasas)",
-                                    0,
-                                    60,
-                                    in_include,
-                                    in_exclude),
-                     G_DBUS_CALL_FLAGS_NONE,
-                     60000,
-                     pp->cancellable,
-                     devices_get_cb,
-                     pp);
-
-  pp->searching = FALSE;
+  if (treeview)
+    gtk_widget_set_sensitive (widget,
+      gtk_tree_selection_get_selected (
+        gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
+        &model,
+        &iter));
 }
 
-static gchar **
-line_split (gchar *line)
+static void
+add_device_to_list (PpNewPrinterDialog *dialog,
+                    PpPrintDevice      *device,
+                    gboolean            new_device)
 {
-  gboolean   escaped = FALSE;
-  gboolean   quoted = FALSE;
-  gboolean   in_word = FALSE;
-  gchar    **words = NULL;
-  gchar    **result = NULL;
-  gchar     *buffer = NULL;
-  gchar      ch;
-  gint       n = 0;
-  gint       i, j = 0, k = 0;
-
-  if (line)
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  gboolean  network_device;
+  gboolean  already_present;
+  TDevice  *store_device;
+  TDevice  *item;
+  GList    *iter;
+  gchar    *name = NULL;
+  gchar    *canonized_name = NULL;
+  gchar    *new_name;
+  gchar    *new_canonized_name = NULL;
+  gint      name_index, j;
+
+  if (device)
     {
-      n = strlen (line);
-      words = g_new0 (gchar *, n + 1);
-      buffer = g_new0 (gchar, n + 1);
-
-      for (i = 0; i < n; i++)
+      if (device->device_id ||
+          device->device_ppd ||
+          (device->host_name &&
+           device->acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER))
         {
-          ch = line[i];
+          network_device = FALSE;
+
+          if (device->device_class &&
+              g_strcmp0 (device->device_class, "network") == 0)
+            network_device = TRUE;
+
+          store_device = g_new0 (TDevice, 1);
+          store_device->device_original_name = g_strdup (device->device_name);
+          store_device->device_info = g_strdup (device->device_info);
+          store_device->device_location = g_strdup (device->device_location);
+          store_device->device_make_and_model = g_strdup (device->device_make_and_model);
+          store_device->device_uri = g_strdup (device->device_uri);
+          store_device->device_id = g_strdup (device->device_id);
+          store_device->device_ppd = g_strdup (device->device_ppd);
+          store_device->host_name = g_strdup (device->host_name);
+          store_device->host_port = device->host_port;
+          store_device->network_device = network_device;
+          store_device->acquisition_method = device->acquisition_method;
+          store_device->show = TRUE;
+
+          if (device->device_id)
+            {
+              name = get_tag_value (device->device_id, "mdl");
+              if (!name)
+                name = get_tag_value (device->device_id, "model");
+            }
+
+          if (!name &&
+              device->device_make_and_model &&
+              device->device_make_and_model[0] != '\0')
+            {
+              name = g_strdup (device->device_make_and_model);
+            }
 
-          if (escaped)
+          if (!name &&
+              device->device_name &&
+              device->device_name[0] != '\0')
             {
-              buffer[k++] = ch;
-              escaped = FALSE;
-              continue;
+              name = g_strdup (device->device_name);
             }
 
-          if (ch == '\\')
+          if (!name &&
+              device->device_info &&
+              device->device_info[0] != '\0')
             {
-              in_word = TRUE;
-              escaped = TRUE;
-              continue;
+              name = g_strdup (device->device_info);
             }
 
-          if (in_word)
+          g_strstrip (name);
+
+          name_index = 2;
+          already_present = FALSE;
+          do
             {
-              if (quoted)
+              if (already_present)
                 {
-                  if (ch == '"')
-                    quoted = FALSE;
-                  else
-                    buffer[k++] = ch;
+                  new_name = g_strdup_printf ("%s %d", name, name_index);
+                  name_index++;
                 }
-              else if (g_ascii_isspace (ch))
+              else
                 {
-                  words[j++] = g_strdup (buffer);
-                  memset (buffer, 0, n + 1);
-                  k = 0;
-                  in_word = FALSE;
+                  new_name = g_strdup (name);
                 }
-              else if (ch == '"')
-                quoted = TRUE;
-              else
-                buffer[k++] = ch;
-            }
-          else
-            {
-              if (ch == '"')
+
+              if (new_name)
                 {
-                  in_word = TRUE;
-                  quoted = TRUE;
+                  new_canonized_name = g_strcanon (g_strdup (new_name), ALLOWED_CHARACTERS, '-');
                 }
-              else if (!g_ascii_isspace (ch))
+
+              already_present = FALSE;
+              for (j = 0; j < priv->num_of_dests; j++)
+                if (g_strcmp0 (priv->dests[j].name, new_canonized_name) == 0)
+                  already_present = TRUE;
+
+              for (iter = priv->devices; iter; iter = iter->next)
                 {
-                  in_word = TRUE;
-                  buffer[k++] = ch;
+                  item = (TDevice *) iter->data;
+                  if (g_strcmp0 (item->device_name, new_canonized_name) == 0)
+                    already_present = TRUE;
+                }
+
+              for (iter = priv->new_devices; iter; iter = iter->next)
+                {
+                  item = (TDevice *) iter->data;
+                  if (g_strcmp0 (item->device_name, new_canonized_name) == 0)
+                    already_present = TRUE;
                 }
-            }
-        }
-    }
 
-  if (buffer && buffer[0] != '\0')
-    words[j++] = g_strdup (buffer);
+              if (already_present)
+                {
+                  g_free (new_name);
+                  g_free (new_canonized_name);
+                }
+              else
+                {
+                  g_free (name);
+                  g_free (canonized_name);
+                  name = new_name;
+                  canonized_name = new_canonized_name;
+                }
+            } while (already_present);
 
-  result = g_strdupv (words);
-  g_strfreev (words);
-  g_free (buffer);
+          store_device->display_name = g_strdup (canonized_name);
+          store_device->device_name = canonized_name;
+          g_free (name);
 
-  return result;
+          if (new_device)
+            priv->new_devices = g_list_append (priv->new_devices, store_device);
+          else
+            priv->devices = g_list_append (priv->devices, store_device);
+        }
+    }
 }
 
 static void
-service_enable (gchar *service_name,
-                gint   service_timeout)
+add_devices_to_list (PpNewPrinterDialog  *dialog,
+                     GList               *devices,
+                     gboolean             new_device)
 {
-  GDBusConnection *bus;
-  GVariant   *output = NULL;
-  GError     *error = NULL;
+  GList *iter;
 
-  bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
-  if (!bus)
+  for (iter = devices; iter; iter = iter->next)
     {
-      g_warning ("%s", error->message);
-      g_error_free (error);
-      return;
+      add_device_to_list (dialog, (PpPrintDevice *) iter->data, new_device);
     }
+}
 
-  output = g_dbus_connection_call_sync (bus,
-                                        FIREWALLD_BUS,
-                                        FIREWALLD_PATH,
-                                        FIREWALLD_IFACE,
-                                        "enableService",
-                                        g_variant_new ("(si)",
-                                                       service_name,
-                                                       service_timeout),
-                                        NULL,
-                                        G_DBUS_CALL_FLAGS_NONE,
-                                        60000,
-                                        NULL,
-                                        &error);
-
-  g_object_unref (bus);
+static TDevice *
+device_in_list (gchar *device_uri,
+                GList *device_list)
+{
+  GList   *iter;
+  TDevice *device;
 
-  if (output)
-    {
-      g_variant_unref (output);
-    }
-  else
+  for (iter = device_list; iter; iter = iter->next)
     {
-      g_warning ("%s", error->message);
-      g_error_free (error);
+      device = (TDevice *) iter->data;
+      /* GroupPhysicalDevices returns uris without port numbers */
+      if (g_str_has_prefix (device->device_uri, device_uri))
+        return device;
     }
+
+  return NULL;
 }
 
 static void
-service_disable (gchar *service_name)
+t_device_free (gpointer data)
 {
-  GDBusConnection *bus;
-  GVariant   *output = NULL;
-  GError     *error = NULL;
-
-  bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
-  if (!bus)
+  if (data)
     {
-      g_warning ("%s", error->message);
-      g_error_free (error);
-      return;
+      TDevice *device = (TDevice *) data;
+
+      g_free (device->display_name);
+      g_free (device->device_name);
+      g_free (device->device_original_name);
+      g_free (device->device_info);
+      g_free (device->device_location);
+      g_free (device->device_make_and_model);
+      g_free (device->device_uri);
+      g_free (device->device_id);
+      g_free (device->device_ppd);
+      g_free (device);
     }
+}
 
-  output = g_dbus_connection_call_sync (bus,
-                                        FIREWALLD_BUS,
-                                        FIREWALLD_PATH,
-                                        FIREWALLD_IFACE,
-                                        "disableService",
-                                        g_variant_new ("(s)", service_name),
-                                        NULL,
-                                        G_DBUS_CALL_FLAGS_NONE,
-                                        60000,
-                                        NULL,
-                                        &error);
-
-  g_object_unref (bus);
+static void
+update_spinner_state (PpNewPrinterDialog *dialog)
+{
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  GtkWidget *spinner;
 
-  if (output)
+  if (priv->cups_searching ||
+      priv->remote_cups_searching ||
+      priv->snmp_searching)
     {
-      g_variant_unref (output);
+      spinner = (GtkWidget*)
+        gtk_builder_get_object (priv->builder, "spinner");
+      gtk_spinner_start (GTK_SPINNER (spinner));
+      gtk_widget_show (spinner);
     }
   else
     {
-      g_warning ("%s", error->message);
-      g_error_free (error);
+      spinner = (GtkWidget*)
+        gtk_builder_get_object (priv->builder, "spinner");
+      gtk_spinner_stop (GTK_SPINNER (spinner));
+      gtk_widget_hide (spinner);
     }
 }
 
-static gboolean
-service_enabled (gchar *service_name)
+static void
+group_physical_devices_cb (gchar    ***device_uris,
+                           gpointer    user_data)
 {
-  GDBusConnection *bus;
-  GVariant   *output = NULL;
-  GError     *error = NULL;
-  gint        query_result = 0;
+  PpNewPrinterDialog        *dialog = (PpNewPrinterDialog *) user_data;
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  TDevice                   *device, *tmp;
+  gint                       i, j;
 
-  bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
-  if (!bus)
+  if (device_uris)
     {
-      g_warning ("%s", error->message);
-      g_error_free (error);
-      return FALSE;
-    }
+      for (i = 0; device_uris[i]; i++)
+        {
+          if (device_uris[i])
+            {
+              for (j = 0; device_uris[i][j]; j++)
+                {
+                  device = device_in_list (device_uris[i][j], priv->devices);
+                  if (device)
+                    break;
+                }
+
+              if (device)
+                {
+                  for (j = 0; device_uris[i][j]; j++)
+                    {
+                      tmp = device_in_list (device_uris[i][j], priv->new_devices);
+                      if (tmp)
+                        {
+                          priv->new_devices = g_list_remove (priv->new_devices, tmp);
+                          t_device_free (tmp);
+                        }
+                    }
+                }
+              else
+                {
+                  for (j = 0; device_uris[i][j]; j++)
+                    {
+                      tmp = device_in_list (device_uris[i][j], priv->new_devices);
+                      if (tmp)
+                        {
+                          priv->new_devices = g_list_remove (priv->new_devices, tmp);
+                          if (j == 0)
+                            {
+                              priv->devices = g_list_append (priv->devices, tmp);
+                            }
+                          else
+                            {
+                              t_device_free (tmp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
 
-  output = g_dbus_connection_call_sync (bus,
-                                        FIREWALLD_BUS,
-                                        FIREWALLD_PATH,
-                                        FIREWALLD_IFACE,
-                                        "queryService",
-                                        g_variant_new ("(s)", service_name),
-                                        G_VARIANT_TYPE ("(i)"),
-                                        G_DBUS_CALL_FLAGS_NONE,
-                                        60000,
-                                        NULL,
-                                        &error);
+      for (i = 0; device_uris[i]; i++)
+        {
+          for (j = 0; device_uris[i][j]; j++)
+            {
+              g_free (device_uris[i][j]);
+            }
 
-  g_object_unref (bus);
+          g_free (device_uris[i]);
+        }
 
-  if (output)
-    {
-      if (g_variant_n_children (output) == 1)
-        g_variant_get (output, "(i)", &query_result);
-      g_variant_unref (output);
+      g_free (device_uris);
     }
   else
     {
-      g_warning ("%s", error->message);
-      g_error_free (error);
-      return FALSE;
+      priv->devices = g_list_concat (priv->devices, priv->new_devices);
+      priv->new_devices = NULL;
     }
 
-  if (query_result > 0)
-    return TRUE;
-  else
-    return FALSE;
+  actualize_devices_list (dialog);
 }
 
-static gboolean
-dbus_method_available (gchar *name,
-                       gchar *path,
-                       gchar *iface,
-                       gchar *method)
+static void
+group_physical_devices_dbus_cb (GObject      *source_object,
+                                GAsyncResult *res,
+                                gpointer      user_data)
 {
-  GDBusConnection *bus;
+  GVariant   *output;
   GError     *error = NULL;
-  GVariant   *output = NULL;
-  gboolean    result = FALSE;
+  gchar    ***result = NULL;
+  gint        i, j;
 
-  bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
-  if (!bus)
-    {
-      g_warning ("%s", error->message);
-      g_error_free (error);
-      return FALSE;
-    }
-
-  output = g_dbus_connection_call_sync (bus,
-                                        name,
-                                        path,
-                                        iface,
-                                        method,
-                                        NULL,
-                                        NULL,
-                                        G_DBUS_CALL_FLAGS_NONE,
-                                        60000,
-                                        NULL,
-                                        &error);
-
-  g_object_unref (bus);
+  output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+                                          res,
+                                          &error);
+  g_object_unref (source_object);
 
   if (output)
     {
+      GVariant *array;
+
+      g_variant_get (output, "(@aas)", &array);
+
+      if (array)
+        {
+          GVariantIter *iter;
+          GVariantIter *subiter;
+          GVariant     *item;
+          GVariant     *subitem;
+          gchar        *device_uri;
+
+          result = g_new0 (gchar **, g_variant_n_children (array) + 1);
+          g_variant_get (array, "aas", &iter);
+          i = 0;
+          while ((item = g_variant_iter_next_value (iter)))
+            {
+              result[i] = g_new0 (gchar *, g_variant_n_children (item) + 1);
+              g_variant_get (item, "as", &subiter);
+              j = 0;
+              while ((subitem = g_variant_iter_next_value (subiter)))
+                {
+                  g_variant_get (subitem, "s", &device_uri);
+
+                  result[i][j] = device_uri;
+
+                  g_variant_unref (subitem);
+                  j++;
+                }
+
+              g_variant_unref (item);
+              i++;
+            }
+
+          g_variant_unref (array);
+        }
+
       g_variant_unref (output);
-      result = TRUE;
+    }
+  else if (error &&
+           error->domain == G_DBUS_ERROR &&
+           (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN ||
+            error->code == G_DBUS_ERROR_UNKNOWN_METHOD))
+    {
+      g_warning ("Install system-config-printer which provides \
+DBus method \"GroupPhysicalDevices\" to group duplicates in device list.");
     }
   else
     {
-      if (error->domain == G_DBUS_ERROR &&
-          error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
-        result = FALSE;
-      else
-        result = TRUE;
+      if (error->domain != G_IO_ERROR ||
+          error->code != G_IO_ERROR_CANCELLED)
+        g_warning ("%s", error->message);
     }
 
-  return result;
+  if (!error ||
+      error->domain != G_IO_ERROR ||
+      error->code != G_IO_ERROR_CANCELLED)
+    group_physical_devices_cb (result, user_data);
+
+  if (error)
+    g_error_free (error);
 }
 
 static void
-search_address_cb (GtkToggleButton *togglebutton,
-                   gpointer         user_data)
+get_cups_devices_cb (GList    *devices,
+                     gboolean  finished,
+                     gboolean  cancelled,
+                     gpointer  user_data)
 {
-  PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
-  GtkWidget *widget;
-  gint i;
-
-  pp->searching = TRUE;
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "search-by-address-checkbutton");
-
-  if (widget && gtk_toggle_button_get_active (togglebutton))
+  PpNewPrinterDialog         *dialog;
+  PpNewPrinterDialogPrivate  *priv;
+  GDBusConnection            *bus;
+  GVariantBuilder             device_list;
+  GVariantBuilder             device_hash;
+  PpPrintDevice             **all_devices;
+  PpPrintDevice              *pp_device;
+  TDevice                    *device;
+  GError                     *error = NULL;
+  GList                      *iter;
+  gint                        length, i;
+
+
+  if (!cancelled)
     {
-      gchar *uri = NULL;
+      dialog = (PpNewPrinterDialog*) user_data;
+      priv = dialog->priv;
 
-      widget = (GtkWidget*)
-        gtk_builder_get_object (pp->builder, "address-entry");
-      uri = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
-
-      if (uri && uri[0] != '\0')
+      if (finished)
         {
-          cups_dest_t *dests = NULL;
-          http_t      *http;
-          GError      *error = NULL;
-          gchar       *tmp = NULL;
-          gchar       *host = NULL;
-          gchar       *port_string = NULL;
-          gchar       *position;
-          gchar       *command;
-          gchar       *standard_output = NULL;
-          gint         exit_status = -1;
-          gint         num_dests = 0;
-          gint         length;
-          int          port = 631;
-
-          if (g_strrstr (uri, "://"))
-            tmp = g_strrstr (uri, "://") + 3;
-          else
-            tmp = uri;
-
-          if (g_strrstr (tmp, "@"))
-            tmp = g_strrstr (tmp, "@") + 1;
+          priv->cups_searching = FALSE;
+        }
 
-          if ((position = g_strrstr (tmp, "/")))
-            {
-              *position = '\0';
-              host = g_strdup (tmp);
-              *position = '/';
-            }
-          else
-            host = g_strdup (tmp);
+      if (devices)
+        {
+          add_devices_to_list (dialog,
+                               devices,
+                               TRUE);
 
-          if ((position = g_strrstr (host, ":")))
+          length = g_list_length (priv->devices) + g_list_length (devices);
+          if (length > 0)
             {
-              *position = '\0';
-              port_string = position + 1;
-            }
-
-          if (port_string)
-            port = atoi (port_string);
+              all_devices = g_new0 (PpPrintDevice *, length);
 
-          if (host)
-            {
-              /* Use CUPS to get printer's informations */
-              http = httpConnectEncrypt (host, port, cupsEncryption ());
-              if (http)
+              i = 0;
+              for (iter = priv->devices; iter; iter = iter->next)
                 {
-                  gchar *device_uri = NULL;
-                  gchar *device_ppd_uri = NULL;
-
-                  num_dests = cupsGetDests2 (http, &dests);
-
-                  if (num_dests > 0)
+                  device = (TDevice *) iter->data;
+                  if (device)
                     {
-                      CupsDevice *devices = NULL;
-                      devices = g_new0 (CupsDevice, pp->num_devices + num_dests);
-
-                      for (i = 0; i < pp->num_devices; i++)
-                        {
-                          devices[i] = pp->devices[i];
-                          pp->devices[i].device_class = NULL;
-                          pp->devices[i].device_id = NULL;
-                          pp->devices[i].device_info = NULL;
-                          pp->devices[i].device_make_and_model = NULL;
-                          pp->devices[i].device_uri = NULL;
-                          pp->devices[i].device_location = NULL;
-                          pp->devices[i].device_ppd_uri = NULL;
-                          pp->devices[i].display_name = NULL;
-                          pp->devices[i].hostname = NULL;
-                        }
-
-                      g_free (pp->devices);
-                      pp->devices = devices;
-
-                      for (i = 0; i < num_dests; i++)
-                        {
-                          device_uri = g_strdup_printf ("ipp://%s:%d/printers/%s", host, port, dests[i].name);
-                          device_ppd_uri = g_strdup_printf ("%s.ppd", device_uri);
-
-                          pp->devices[pp->num_devices + i].device_class = g_strdup ("network");
-                          pp->devices[pp->num_devices + i].device_uri = device_uri;
-                          pp->devices[pp->num_devices + i].display_name = g_strdup (dests[i].name);
-                          pp->devices[pp->num_devices + i].device_ppd_uri = device_ppd_uri;
-                          pp->devices[pp->num_devices + i].show = TRUE;
-                          pp->devices[pp->num_devices + i].hostname = g_strdup (host);
-                          pp->devices[pp->num_devices + i].host_port = port;
-                          pp->devices[pp->num_devices + i].found = TRUE;
-                        }
-
-                      pp->num_devices += num_dests;
+                      all_devices[i] = g_new0 (PpPrintDevice, 1);
+                      all_devices[i]->device_id = g_strdup (device->device_id);
+                      all_devices[i]->device_make_and_model = g_strdup (device->device_make_and_model);
+                      all_devices[i]->device_class = device->network_device ? g_strdup ("network") : strdup ("direct");
+                      all_devices[i]->device_uri = g_strdup (device->device_uri);
                     }
-
-                  httpClose (http);
+                  i++;
                 }
 
-              /* Use SNMP to get printer's informations */
-              command = g_strdup_printf ("/usr/lib/cups/backend/snmp %s", host);
-              if (g_spawn_command_line_sync (command, &standard_output, NULL, &exit_status, &error))
+              for (iter = devices; iter; iter = iter->next)
                 {
-                  if (exit_status == 0 && standard_output)
+                  pp_device = (PpPrintDevice *) iter->data;
+                  if (pp_device)
                     {
-                      gchar **printer_informations = NULL;
+                      all_devices[i] = g_new0 (PpPrintDevice, 1);
+                      all_devices[i]->device_id = g_strdup (pp_device->device_id);
+                      all_devices[i]->device_make_and_model = g_strdup (pp_device->device_make_and_model);
+                      all_devices[i]->device_class = g_strdup (pp_device->device_class);
+                      all_devices[i]->device_uri = g_strdup (pp_device->device_uri);
+                    }
+                  i++;
+                }
 
-                      printer_informations = line_split (standard_output);
-                      length = g_strv_length (printer_informations);
+              bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+              if (bus)
+                {
+                  g_variant_builder_init (&device_list, G_VARIANT_TYPE ("a{sv}"));
 
-                      if (length >= 4)
+                  for (i = 0; i < length; i++)
+                    {
+                      if (all_devices[i]->device_uri)
                         {
-                          CupsDevice *devices = NULL;
-                          devices = g_new0 (CupsDevice, pp->num_devices + 1);
-
-                          for (i = 0; i < pp->num_devices; i++)
-                            {
-                              devices[i] = pp->devices[i];
-                              pp->devices[i].device_class = NULL;
-                              pp->devices[i].device_id = NULL;
-                              pp->devices[i].device_info = NULL;
-                              pp->devices[i].device_make_and_model = NULL;
-                              pp->devices[i].device_uri = NULL;
-                              pp->devices[i].device_location = NULL;
-                              pp->devices[i].device_ppd_uri = NULL;
-                              pp->devices[i].display_name = NULL;
-                              pp->devices[i].hostname = NULL;
-                            }
-
-                          g_free (pp->devices);
-                          pp->devices = devices;
-
-                          pp->devices[pp->num_devices].device_class = g_strdup (printer_informations[0]);
-                          pp->devices[pp->num_devices].device_uri = g_strdup (printer_informations[1]);
-                          pp->devices[pp->num_devices].device_make_and_model = g_strdup (printer_informations[2]);
-                          pp->devices[pp->num_devices].device_info = g_strdup (printer_informations[3]);
-                          pp->devices[pp->num_devices].display_name = g_strdup (printer_informations[3]);
-                          pp->devices[pp->num_devices].display_name =
-                            g_strcanon (pp->devices[pp->num_devices].display_name, ALLOWED_CHARACTERS, '-');
-                          pp->devices[pp->num_devices].show = TRUE;
-                          pp->devices[pp->num_devices].hostname = g_strdup (host);
-                          pp->devices[pp->num_devices].host_port = port;
-                          pp->devices[pp->num_devices].found = TRUE;
-
-                          if (length >= 5 && printer_informations[4][0] != '\0')
-                            pp->devices[pp->num_devices].device_id = g_strdup (printer_informations[4]);
-
-                          if (length >= 6 && printer_informations[5][0] != '\0')
-                            pp->devices[pp->num_devices].device_location = g_strdup (printer_informations[5]);
-
-                          pp->num_devices++;
+                          g_variant_builder_init (&device_hash, G_VARIANT_TYPE ("a{ss}"));
+
+                          if (all_devices[i]->device_id)
+                            g_variant_builder_add (&device_hash,
+                                                   "{ss}",
+                                                   "device-id",
+                                                   all_devices[i]->device_id);
+
+                          if (all_devices[i]->device_make_and_model)
+                            g_variant_builder_add (&device_hash,
+                                                   "{ss}",
+                                                   "device-make-and-model",
+                                                   all_devices[i]->device_make_and_model);
+
+                          if (all_devices[i]->device_class)
+                            g_variant_builder_add (&device_hash,
+                                                   "{ss}",
+                                                   "device-class",
+                                                   all_devices[i]->device_class);
+
+                          g_variant_builder_add (&device_list,
+                                                 "{sv}",
+                                                 all_devices[i]->device_uri,
+                                                 g_variant_builder_end (&device_hash));
                         }
-                      g_strfreev (printer_informations);
-                      g_free (standard_output);
                     }
+
+                  g_dbus_connection_call (bus,
+                                          SCP_BUS,
+                                          SCP_PATH,
+                                          SCP_IFACE,
+                                          "GroupPhysicalDevices",
+                                          g_variant_new ("(v)", g_variant_builder_end (&device_list)),
+                                          G_VARIANT_TYPE ("(aas)"),
+                                          G_DBUS_CALL_FLAGS_NONE,
+                                          -1,
+                                          priv->cancellable,
+                                          group_physical_devices_dbus_cb,
+                                          dialog);
                 }
               else
                 {
-                  g_warning ("%s", error->message);
+                  g_warning ("Failed to get system bus: %s", error->message);
                   g_error_free (error);
+                  group_physical_devices_cb (NULL, user_data);
                 }
 
-              g_free (command);
-              g_free (host);
-            }
-        }
-      g_free (uri);
-    }
-  else
-    {
-      gint length = 0;
-      gint j = 0;
-
-      for (i = 0; i < pp->num_devices; i++)
-        if (!pp->devices[i].found)
-          length++;
-
-      CupsDevice *devices = NULL;
-      devices = g_new0 (CupsDevice, length);
+              for (i = 0; i < length; i++)
+                {
+                  if (all_devices[i])
+                    {
+                      g_free (all_devices[i]->device_id);
+                      g_free (all_devices[i]->device_make_and_model);
+                      g_free (all_devices[i]->device_class);
+                      g_free (all_devices[i]->device_uri);
+                      g_free (all_devices[i]);
+                    }
+                }
 
-      for (i = 0; i < pp->num_devices; i++)
-        {
-          if (!pp->devices[i].found)
+              g_free (all_devices);
+            }
+          else
             {
-              devices[j] = pp->devices[i];
-              pp->devices[i].device_class = NULL;
-              pp->devices[i].device_id = NULL;
-              pp->devices[i].device_info = NULL;
-              pp->devices[i].device_make_and_model = NULL;
-              pp->devices[i].device_uri = NULL;
-              pp->devices[i].device_location = NULL;
-              pp->devices[i].device_ppd_uri = NULL;
-              pp->devices[i].display_name = NULL;
-              pp->devices[i].hostname = NULL;
-              j++;
+              actualize_devices_list (dialog);
             }
         }
-
-      g_free (pp->devices);
-      pp->devices = devices;
-      pp->num_devices = length;
+      else
+        {
+          actualize_devices_list (dialog);
+        }
     }
 
-  pp->searching = FALSE;
-
-  actualize_devices_list (pp);
+  for (iter = devices; iter; iter = iter->next)
+    pp_print_device_free ((PpPrintDevice *) iter->data);
+  g_list_free (devices);
 }
 
 static void
-actualize_devices_list (PpNewPrinterDialog *pp)
+get_snmp_devices_cb (GObject      *source_object,
+                     GAsyncResult *res,
+                     gpointer      user_data)
 {
-  GtkListStore *network_store;
-  GtkListStore *local_store;
-  GtkTreeModel *model;
-  GtkTreeView  *network_treeview;
-  GtkTreeView  *local_treeview;
-  GtkTreeIter   iter;
-  GtkWidget    *treeview;
-  GtkWidget    *widget;
-  GtkWidget    *local_notebook;
-  GtkWidget    *network_notebook;
-  gboolean      no_local_device = TRUE;
-  gboolean      no_network_device = TRUE;
-  gint          i;
-  gint          device_type = -1;
-
-  network_treeview = (GtkTreeView*)
-    gtk_builder_get_object (pp->builder, "network-devices-treeview");
-
-  local_treeview = (GtkTreeView*)
-    gtk_builder_get_object (pp->builder, "local-devices-treeview");
-
-  network_store = gtk_list_store_new (DEVICE_N_COLUMNS,
-                                      G_TYPE_INT,
-                                      G_TYPE_STRING);
-
-  local_store = gtk_list_store_new (DEVICE_N_COLUMNS,
-                                    G_TYPE_INT,
-                                    G_TYPE_STRING);
-
-  for (i = 0; i < pp->num_devices; i++)
+  PpNewPrinterDialog        *dialog;
+  PpNewPrinterDialogPrivate *priv;
+  PpHost                    *host = (PpHost *) source_object;
+  GError                    *error = NULL;
+  PpDevicesList             *result;
+  GList                     *iter;
+
+  result = pp_host_get_snmp_devices_finish (host, res, &error);
+  g_object_unref (source_object);
+
+  if (result)
     {
-      if ((pp->devices[i].device_id || pp->devices[i].device_ppd_uri) &&
-          pp->devices[i].show)
+      dialog = PP_NEW_PRINTER_DIALOG (user_data);
+      priv = dialog->priv;
+
+      priv->snmp_searching = FALSE;
+      update_spinner_state (dialog);
+
+      if (result->devices)
         {
-          if (g_strcmp0 (pp->devices[i].device_class, "network") == 0)
-            {
-              gtk_list_store_append (network_store, &iter);
-              gtk_list_store_set (network_store, &iter,
-                                  DEVICE_ID_COLUMN, i,
-                                  DEVICE_NAME_COLUMN, pp->devices[i].display_name,
-                                  -1);
-              pp->show_warning = FALSE;
-              no_network_device = FALSE;
-            }
-          else if (g_strcmp0 (pp->devices[i].device_class, "direct") == 0)
-            {
-              gtk_list_store_append (local_store, &iter);
-              gtk_list_store_set (local_store, &iter,
-                                  DEVICE_ID_COLUMN, i,
-                                  DEVICE_NAME_COLUMN, pp->devices[i].display_name,
-                                  -1);
-              no_local_device = FALSE;
-            }
+          add_devices_to_list (dialog,
+                               result->devices,
+                               FALSE);
         }
-    }
 
-  if (no_local_device && !pp->searching)
-    {
-      gtk_list_store_append (local_store, &iter);
-      gtk_list_store_set (local_store, &iter,
-                          DEVICE_ID_COLUMN, 0,
-      /* Translators: No localy connected printers were found */
-                          DEVICE_NAME_COLUMN, _("No local printers found"),
-                          -1);
-      gtk_widget_set_sensitive (GTK_WIDGET (local_treeview), FALSE);
-    }
-  else
-    gtk_widget_set_sensitive (GTK_WIDGET (local_treeview), TRUE);
+      actualize_devices_list (dialog);
 
-  if (no_network_device && !pp->show_warning && !pp->searching)
-    {
-      gtk_list_store_append (network_store, &iter);
-      gtk_list_store_set (network_store, &iter,
-                          DEVICE_ID_COLUMN, 0,
-      /* Translators: No network printers were found */
-                          DEVICE_NAME_COLUMN, _("No network printers found"),
-                          -1);
-      gtk_widget_set_sensitive (GTK_WIDGET (network_treeview), FALSE);
+      for (iter = result->devices; iter; iter = iter->next)
+        pp_print_device_free ((PpPrintDevice *) iter->data);
+      g_list_free (result->devices);
+      g_free (result);
     }
   else
-    gtk_widget_set_sensitive (GTK_WIDGET (network_treeview), TRUE);
-
-  gtk_tree_view_set_model (network_treeview, GTK_TREE_MODEL (network_store));
-  gtk_tree_view_set_model (local_treeview, GTK_TREE_MODEL (local_store));
-
-  if (!no_network_device &&
-      gtk_tree_model_get_iter_first ((GtkTreeModel *) network_store, &iter))
-    gtk_tree_selection_select_iter (
-      gtk_tree_view_get_selection (GTK_TREE_VIEW (network_treeview)),
-      &iter);
-
-  if (!no_local_device &&
-      gtk_tree_model_get_iter_first ((GtkTreeModel *) local_store, &iter))
-    gtk_tree_selection_select_iter (
-      gtk_tree_view_get_selection (GTK_TREE_VIEW (local_treeview)),
-      &iter);
-
-  treeview = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "device-types-treeview");
-
-  if (gtk_tree_selection_get_selected (
-        gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
-    gtk_tree_model_get (model, &iter,
-                        DEVICE_TYPE_TYPE_COLUMN, &device_type,
-                        -1);
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "device-type-notebook");
-
-  local_notebook = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "local-devices-notebook");
+    {
+      if (error->domain != G_IO_ERROR ||
+          error->code != G_IO_ERROR_CANCELLED)
+        {
+          dialog = PP_NEW_PRINTER_DIALOG (user_data);
+          priv = dialog->priv;
 
-  network_notebook = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "network-devices-notebook");
+          g_warning ("%s", error->message);
 
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (network_notebook), pp->show_warning ? WARNING_TAB : STANDARD_TAB);
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (local_notebook), STANDARD_TAB);
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), device_type);
+          priv->snmp_searching = FALSE;
+          update_spinner_state (dialog);
+        }
 
-  g_object_unref (network_store);
-  g_object_unref (local_store);
+      g_error_free (error);
+    }
 }
 
 static void
-populate_devices_list (PpNewPrinterDialog *pp)
+get_remote_cups_devices_cb (GObject      *source_object,
+                            GAsyncResult *res,
+                            gpointer      user_data)
 {
-  GtkTreeViewColumn *column;
-  GtkCellRenderer   *renderer;
-  GtkTextBuffer     *text_buffer;
-  GtkTextView       *warning_textview;
-  GtkTextIter        text_iter;
-  GtkWidget         *network_treeview;
-  GtkWidget         *local_treeview;
-
-  network_treeview = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "network-devices-treeview");
-
-  local_treeview = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "local-devices-treeview");
-
-  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (network_treeview)),
-                    "changed", G_CALLBACK (device_selection_changed_cb), pp);
-
-  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (local_treeview)),
-                    "changed", G_CALLBACK (device_selection_changed_cb), pp);
-
-  actualize_devices_list (pp);
+  PpNewPrinterDialog        *dialog;
+  PpNewPrinterDialogPrivate *priv;
+  PpHost                    *host = (PpHost *) source_object;
+  GError                    *error = NULL;
+  PpDevicesList             *result;
+  GList                     *iter;
+
+  result = pp_host_get_remote_cups_devices_finish (host, res, &error);
+  g_object_unref (source_object);
 
-  if (dbus_method_available (FIREWALLD_BUS,
-                             FIREWALLD_PATH,
-                             FIREWALLD_IFACE,
-                             "getServices"))
+  if (result)
     {
-      if (!service_enabled ("mdns"))
-        service_enable ("mdns", 300);
+      dialog = PP_NEW_PRINTER_DIALOG (user_data);
+      priv = dialog->priv;
+
+      priv->remote_cups_searching = FALSE;
+      update_spinner_state (dialog);
 
-      if (!service_enabled ("ipp"))
-        service_enable ("ipp", 300);
+      if (result->devices)
+        {
+          add_devices_to_list (dialog,
+                               result->devices,
+                               FALSE);
+        }
 
-      if (!service_enabled ("ipp-client"))
-        service_enable ("ipp-client", 300);
+      actualize_devices_list (dialog);
 
-      if (!service_enabled ("samba-client"))
-        service_enable ("samba-client", 300);
+      for (iter = result->devices; iter; iter = iter->next)
+        pp_print_device_free ((PpPrintDevice *) iter->data);
+      g_list_free (result->devices);
+      g_free (result);
     }
   else
     {
-      pp->warning = g_strdup (_("FirewallD is not running. \
-Network printer detection needs services mdns, ipp, ipp-client \
-and samba-client enabled on firewall."));
-
-      warning_textview = (GtkTextView*)
-        gtk_builder_get_object (pp->builder, "local-warning");
-      text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (warning_textview));
-
-      gtk_text_buffer_set_text (text_buffer, "", 0);
-      gtk_text_buffer_get_iter_at_offset (text_buffer, &text_iter, 0);
-      gtk_text_buffer_insert (text_buffer, &text_iter, pp->warning, -1);
+      if (error->domain != G_IO_ERROR ||
+          error->code != G_IO_ERROR_CANCELLED)
+        {
+          dialog = PP_NEW_PRINTER_DIALOG (user_data);
+          priv = dialog->priv;
 
-      warning_textview = (GtkTextView*)
-        gtk_builder_get_object (pp->builder, "network-warning");
-      text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (warning_textview));
+          g_warning ("%s", error->message);
 
-      gtk_text_buffer_set_text (text_buffer, "", 0);
-      gtk_text_buffer_get_iter_at_offset (text_buffer, &text_iter, 0);
-      gtk_text_buffer_insert (text_buffer, &text_iter, pp->warning, -1);
+          priv->remote_cups_searching = FALSE;
+          update_spinner_state (dialog);
+        }
 
-      pp->show_warning = TRUE;
+      g_error_free (error);
     }
-
-  devices_get (pp);
-
-  renderer = gtk_cell_renderer_text_new ();
-
-  /* Translators: Column of devices which can be installed */
-  column = gtk_tree_view_column_new_with_attributes (_("Devices"), renderer,
-                                                     "text", DEVICE_NAME_COLUMN, NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (network_treeview), column);
-
-  /* Translators: Column of devices which can be installed */
-  column = gtk_tree_view_column_new_with_attributes (_("Devices"), renderer,
-                                                     "text", DEVICE_NAME_COLUMN, NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (local_treeview), column);
 }
 
 static void
-actualize_device_types_list (PpNewPrinterDialog *pp)
+get_cups_devices (PpNewPrinterDialog *dialog)
 {
-  GtkListStore *store;
-  GtkTreeView  *treeview;
-  GtkTreeIter   iter;
-  gint          i;
-
-  treeview = (GtkTreeView*)
-    gtk_builder_get_object (pp->builder, "device-types-treeview");
-
-  store = gtk_list_store_new (DEVICE_TYPE_N_COLUMNS,
-                              G_TYPE_INT,
-                              G_TYPE_STRING,
-                              G_TYPE_INT);
-
-  pp->device_connection_types = g_new (gchar*, 2);
-  pp->num_device_connection_types = 2;
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
 
-  /* Translators: Local means local printers */
-  pp->device_connection_types[0] = g_strdup (C_("printer type", "Local"));
-  /* Translators: Network means network printers */
-  pp->device_connection_types[1] = g_strdup (C_("printer type", "Network"));
+  priv->cups_searching = TRUE;
+  update_spinner_state (dialog);
 
-  for (i = 0; i < pp->num_device_connection_types; i++)
-    {
-      gtk_list_store_append (store, &iter);
-      gtk_list_store_set (store, &iter,
-                          DEVICE_TYPE_ID_COLUMN, i,
-                          DEVICE_TYPE_NAME_COLUMN, pp->device_connection_types[i],
-                          DEVICE_TYPE_TYPE_COLUMN, i,
-                          -1);
-    }
-
-  gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
-
-  gtk_tree_model_get_iter_first ((GtkTreeModel *) store,
-                                 &iter);
-
-  gtk_tree_selection_select_iter (
-    gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
-    &iter);
-
-  g_object_unref (store);
+  get_cups_devices_async (priv->cancellable,
+                          get_cups_devices_cb,
+                          dialog);
 }
 
-static void
-populate_device_types_list (PpNewPrinterDialog *pp)
+static gboolean
+parse_uri (gchar  *uri,
+           gchar **host,
+           gint   *port)
 {
-  GtkTreeViewColumn *column;
-  GtkCellRenderer   *renderer;
-  GtkWidget         *treeview;
-
-  treeview = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "device-types-treeview");
-
-  actualize_device_types_list (pp);
-
-  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
-                    "changed", G_CALLBACK (device_type_selection_changed_cb), pp);
+  gchar *tmp = NULL;
+  gchar *resulting_host = NULL;
+  gchar *port_string = NULL;
+  gchar *position;
+  int    resulting_port = 631;
+
+  if (g_strrstr (uri, "://"))
+    tmp = g_strrstr (uri, "://") + 3;
+  else
+    tmp = uri;
 
-  renderer = gtk_cell_renderer_text_new ();
-  /* Translators: Device types column (network or local) */
-  column = gtk_tree_view_column_new_with_attributes (_("Device types"), renderer,
-                                                     "text", DEVICE_TYPE_NAME_COLUMN, NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
-}
+  if (g_strrstr (tmp, "@"))
+    tmp = g_strrstr (tmp, "@") + 1;
 
-static GList *
-glist_uniq (GList *list)
-{
-  GList *result = NULL;
-  GList *iter = NULL;
-  GList *tmp = NULL;
+  if ((position = g_strrstr (tmp, "/")))
+    {
+      *position = '\0';
+      resulting_host = g_strdup (tmp);
+      *position = '/';
+    }
+  else
+    resulting_host = g_strdup (tmp);
 
-  for (iter = list; iter; iter = iter->next)
+  if ((position = g_strrstr (resulting_host, ":")))
     {
-      if (tmp == NULL ||
-          g_strcmp0 ((gchar *) tmp->data, (gchar *) iter->data) != 0)
-        {
-          tmp = iter;
-          result = g_list_append (result, g_strdup (iter->data));
-        }
+      *position = '\0';
+      port_string = position + 1;
     }
 
-  g_list_free_full (list, g_free);
+  if (port_string)
+    resulting_port = atoi (port_string);
 
-  return result;
+  *host = resulting_host;
+  *port = resulting_port;
+
+  return TRUE;
 }
 
+
 static void
-new_printer_add_button_cb (GtkButton *button,
-                           gpointer   user_data)
+search_address_cb (GtkEntry *entry,
+                   gpointer  user_data)
 {
-  PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
-  GtkResponseType     dialog_response = GTK_RESPONSE_OK;
-  GtkTreeModel       *model;
-  cups_dest_t        *dests;
-  GtkTreeIter         iter;
-  GtkWidget          *treeview;
-  gboolean            success = FALSE;
-  PPDName            *ppd_name = NULL;
-  gchar              *device_name = NULL;
-  gint                device_id = -1;
-  gint                device_type = -1;
-  gint                i;
-  int                 num_dests;
-
-  treeview = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "device-types-treeview");
-
-  if (gtk_tree_selection_get_selected (
-        gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
-    gtk_tree_model_get (model, &iter,
-                        DEVICE_TYPE_TYPE_COLUMN, &device_type,
-                        -1);
-
-  switch (device_type)
+  PpNewPrinterDialog        *dialog = PP_NEW_PRINTER_DIALOG (user_data);
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  gboolean             found = FALSE;
+  gboolean             subfound;
+  TDevice             *device;
+  GList               *iter, *tmp;
+  gchar               *text;
+  gchar               *lowercase_name;
+  gchar               *lowercase_location;
+  gchar               *lowercase_text;
+  gchar              **words;
+  gint                 words_length = 0;
+  gint                 i;
+
+  text = g_strdup (gtk_entry_get_text (entry));
+
+  lowercase_text = g_ascii_strdown (text, -1);
+  words = g_strsplit_set (lowercase_text, " ", -1);
+  g_free (lowercase_text);
+
+  if (words)
     {
-      case DEVICE_TYPE_LOCAL:
-        treeview = (GtkWidget*)
-          gtk_builder_get_object (pp->builder, "local-devices-treeview");
-        break;
-      case DEVICE_TYPE_NETWORK:
-        treeview = (GtkWidget*)
-          gtk_builder_get_object (pp->builder, "network-devices-treeview");
-        break;
-      default:
-        treeview = NULL;
-        break;
-    }
+      words_length = g_strv_length (words);
 
-  if (treeview &&
-      gtk_tree_selection_get_selected (
-        gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
-    {
-      gtk_tree_model_get (model, &iter,
-			  DEVICE_ID_COLUMN, &device_id,
-			  DEVICE_NAME_COLUMN, &device_name,
-			  -1);
-    }
-
-  if (device_id >= 0)
-    {
-      if (pp->devices[device_id].device_ppd_uri)
+      for (iter = priv->devices; iter; iter = iter->next)
         {
-          http_t *http;
+          device = iter->data;
 
-          http = httpConnectEncrypt (pp->devices[device_id].hostname,
-                                     pp->devices[device_id].host_port,
-                                     cupsEncryption ());
+          lowercase_name = g_ascii_strdown (device->device_name, -1);
+          if (device->device_location)
+            lowercase_location = g_ascii_strdown (device->device_location, -1);
+          else
+            lowercase_location = NULL;
 
-          if (http)
+          subfound = TRUE;
+          for (i = 0; words[i]; i++)
             {
-              const char *ppd_file_name;
-
-              ppd_file_name = cupsGetPPD2 (http, pp->devices[device_id].display_name);
-
-              if (ppd_file_name)
-                {
-                  GDBusConnection *bus;
-                  GError     *error = NULL;
-
-                  bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
-                  if (!bus)
-                    {
-                      g_warning ("Failed to get system bus: %s", error->message);
-                      g_error_free (error);
-                    }
-                  else
-                    {
-                      GVariant *output;
-
-                      output = g_dbus_connection_call_sync (bus,
-                                                            MECHANISM_BUS,
-                                                            "/",
-                                                            MECHANISM_BUS,
-                                                            "PrinterAddWithPpdFile",
-                                                            g_variant_new ("(sssss)",
-                                                                           pp->devices[device_id].display_name,
-                                                                           pp->devices[device_id].device_uri,
-                                                                           ppd_file_name,
-                                                                           pp->devices[device_id].device_info ? pp->devices[device_id].device_info : "",
-                                                                           pp->devices[device_id].device_location ? pp->devices[device_id].device_location : ""),
-                                                            G_VARIANT_TYPE ("(s)"),
-                                                            G_DBUS_CALL_FLAGS_NONE,
-                                                            -1,
-                                                            NULL,
-                                                            &error);
-                      g_object_unref (bus);
-
-                      if (output)
-                        {
-                          const gchar *ret_error;
-
-                          g_variant_get (output, "(&s)", &ret_error);
-                          if (ret_error[0] != '\0')
-                            {
-                              g_warning ("%s", ret_error);
-                              dialog_response = GTK_RESPONSE_REJECT;
-                            }
-                          else
-                            success = TRUE;
-
-                          g_variant_unref (output);
-                        }
-                      else
-                        {
-                          g_warning ("%s", error->message);
-                          g_error_free (error);
-                          dialog_response = GTK_RESPONSE_REJECT;
-                        }
-                    }
-
-                  g_unlink (ppd_file_name);
-                }
-              else
-                {
-                  dialog_response = GTK_RESPONSE_REJECT;
-                  g_warning ("Getting of PPD for %s from %s:%d failed.",
-                             pp->devices[device_id].display_name,
-                             pp->devices[device_id].hostname,
-                             pp->devices[device_id].host_port);
-                }
+              if (!g_strrstr (lowercase_name, words[i]) &&
+                  (!lowercase_location || !g_strrstr (lowercase_location, words[i])))
+                subfound = FALSE;
             }
-        }
-      else if (pp->devices[device_id].device_id)
-        {
-          /* Try whether CUPS has a driver for the new printer */
-          ppd_name = get_ppd_name (pp->devices[device_id].device_id,
-                       pp->devices[device_id].device_make_and_model,
-                       pp->devices[device_id].device_uri);
 
-          if (ppd_name == NULL || ppd_name->ppd_match_level < PPD_EXACT_MATCH)
+          if (subfound)
             {
-              /* Try PackageKit to install printer driver */
-              GDBusConnection *bus;
-              GError     *error = NULL;
-
-              bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-              if (!bus)
-                {
-                  g_warning ("Failed to get session bus: %s", error->message);
-                  g_error_free (error);
-                }
-              else
-                {
-                  GVariantBuilder array_builder;
-                  GVariant *output;
-                  guint window_id = 0;
-
-                  g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
-                  g_variant_builder_add (&array_builder, "s", pp->devices[device_id].device_id);
-
-#ifdef GDK_WINDOWING_X11
-                  window_id = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (pp->dialog)));
-#endif
-
-                  output = g_dbus_connection_call_sync (bus,
-                                                        PACKAGE_KIT_BUS,
-                                                        PACKAGE_KIT_PATH,
-                                                        PACKAGE_KIT_MODIFY_IFACE,
-                                                        "InstallPrinterDrivers",
-                                                        g_variant_new ("(uass)",
-                                                                       window_id,
-                                                                       &array_builder,
-                                                                       "hide-finished"),
-                                                        G_VARIANT_TYPE ("()"),
-                                                        G_DBUS_CALL_FLAGS_NONE,
-                                                        3600000,
-                                                        NULL,
-                                                        &error);
-                  g_object_unref (bus);
-
-                  if (output)
-                    g_variant_unref (output);
-                  else
-                    {
-                      g_warning ("%s", error->message);
-                      g_error_free (error);
-                    }
-
-                  if (ppd_name)
-                    {
-                      g_free (ppd_name->ppd_name);
-                      g_free (ppd_name);
-                    }
-
-                  /* Search CUPS for driver */
-                  ppd_name = get_ppd_name (pp->devices[device_id].device_id,
-                               pp->devices[device_id].device_make_and_model,
-                               pp->devices[device_id].device_uri);
-                }
+              device->show = TRUE;
+              found = TRUE;
             }
-
-          /* Add the new printer */
-          if (ppd_name && ppd_name->ppd_name)
+          else
             {
-              GDBusConnection *bus;
-              GError     *error = NULL;
-              GVariant   *output;
-
-              bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
-              if (!bus)
-                {
-                  g_warning ("Failed to get system bus: %s", error->message);
-                  g_error_free (error);
-                }
-              else
-                {
-                  output = g_dbus_connection_call_sync (bus,
-                                                        MECHANISM_BUS,
-                                                        "/",
-                                                        MECHANISM_BUS,
-                                                        "PrinterAdd",
-                                                        g_variant_new ("(sssss)",
-                                                                       pp->devices[device_id].display_name,
-                                                                       pp->devices[device_id].device_uri,
-                                                                       ppd_name->ppd_name,
-                                                                       pp->devices[device_id].device_info ? pp->devices[device_id].device_info : "",
-                                                                       pp->devices[device_id].device_location ? pp->devices[device_id].device_location : ""),
-                                                        G_VARIANT_TYPE ("(s)"),
-                                                        G_DBUS_CALL_FLAGS_NONE,
-                                                        -1,
-                                                        NULL,
-                                                        &error);
-                  g_object_unref (bus);
-
-                  if (output)
-                    {
-                      const gchar *ret_error;
-
-                      g_variant_get (output, "(&s)", &ret_error);
-                      if (ret_error[0] != '\0')
-                        {
-                          g_warning ("%s", ret_error);
-                          dialog_response = GTK_RESPONSE_REJECT;
-                        }
-
-                      g_variant_unref (output);
-                    }
-                  else
-                    {
-                      g_warning ("%s", error->message);
-                      g_error_free (error);
-                      dialog_response = GTK_RESPONSE_REJECT;
-                    }
-                }
-
-              g_free (ppd_name->ppd_name);
-              g_free (ppd_name);
+              device->show = FALSE;
             }
 
-          num_dests = cupsGetDests (&dests);
-          for (i = 0; i < num_dests; i++)
-            if (g_strcmp0 (dests[i].name, pp->devices[device_id].display_name) == 0)
-              success = TRUE;
-          cupsFreeDests (num_dests, dests);
+          g_free (lowercase_location);
+          g_free (lowercase_name);
         }
 
-      /* Set some options of the new printer */
-      if (success)
-        {
-          const char *ppd_file_name = NULL;
-          GDBusConnection *bus;
-          GError     *error = NULL;
-
-          ppd_file_name = cupsGetPPD (pp->devices[device_id].display_name);
+      g_strfreev (words);
+  }
 
-          printer_set_accepting_jobs (pp->devices[device_id].display_name, TRUE, NULL);
-          printer_set_enabled (pp->devices[device_id].display_name, TRUE);
+  if (!found && words_length == 1)
+    {
+      iter = priv->devices;
+      while (iter)
+        {
+          device = iter->data;
+          device->show = TRUE;
 
-          if (g_strcmp0 (pp->devices[device_id].device_class, "direct") == 0)
+          if (device->acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER ||
+              device->acquisition_method == ACQUISITION_METHOD_SNMP)
             {
-              gchar *commands = get_dest_attr (pp->devices[device_id].display_name, "printer-commands");
-              gchar *commands_lowercase = g_ascii_strdown (commands, -1);
-              ipp_t *response = NULL;
-
-              if (g_strrstr (commands_lowercase, "autoconfigure"))
-                {
-                  response = execute_maintenance_command (pp->devices[device_id].display_name,
-                                                          "AutoConfigure",
-                  /* Translators: Name of job which makes printer to autoconfigure itself */
-                                                          _("Automatic configuration"));
-                  if (response)
-                    {
-                      if (ippGetState (response) == IPP_ERROR)
-                        g_warning ("An error has occured during automatic configuration of new printer.");
-                      ippDelete (response);
-                    }
-                }
-              g_free (commands);
-              g_free (commands_lowercase);
+              tmp = iter;
+              iter = iter->next;
+              priv->devices = g_list_remove_link (priv->devices, tmp);
+              g_list_free_full (tmp, t_device_free);
             }
+          else
+            iter = iter->next;
+        }
 
-          printer_set_default_media_size (pp->devices[device_id].display_name);
+      iter = priv->new_devices;
+      while (iter)
+        {
+          device = iter->data;
 
-          if (pp->devices[device_id].device_uri &&
-              dbus_method_available (FIREWALLD_BUS,
-                                     FIREWALLD_PATH,
-                                     FIREWALLD_IFACE,
-                                     "getServices"))
+          if (device->acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER ||
+              device->acquisition_method == ACQUISITION_METHOD_SNMP)
             {
-              if (g_str_has_prefix (pp->devices[device_id].device_uri, "dnssd:") ||
-                  g_str_has_prefix (pp->devices[device_id].device_uri, "mdns:"))
-                {
-                  show_notification (_("Opening firewall for mDNS connections"),
-                                     NULL,
-                                     "dialog-information-symbolic");
-                  service_disable ("mdns");
-                  service_enable ("mdns", 0);
-                }
+              tmp = iter;
+              iter = iter->next;
+              priv->new_devices = g_list_remove_link (priv->new_devices, tmp);
+              g_list_free_full (tmp, t_device_free);
+            }
+          else
+            iter = iter->next;
+        }
 
-              if (g_strrstr (pp->devices[device_id].device_uri, "smb:") != NULL)
-                {
-                  show_notification (_("Opening firewall for Samba connections"),
-                                     NULL,
-                                     "dialog-information-symbolic");
-                  service_disable ("samba-client");
-                  service_enable ("samba-client", 0);
-                }
+      if (text && text[0] != '\0')
+        {
+          gchar *host = NULL;
+          gint   port = 631;
 
-              if (g_strrstr (pp->devices[device_id].device_uri, "ipp:") != NULL)
-                {
-                  show_notification (_("Opening firewall for IPP connections"),
-                                     NULL,
-                                     "dialog-information-symbolic");
-                  service_disable ("ipp");
-                  service_enable ("ipp", 0);
-                  service_disable ("ipp-client");
-                  service_enable ("ipp-client", 0);
-                }
-            }
+          parse_uri (text, &host, &port);
 
-          if (ppd_file_name)
+          if (host)
             {
-              GVariant   *output;
-              GVariant   *array;
-              GList      *executables = NULL;
-              GList      *packages = NULL;
+              PpHost *snmp_host;
+              PpHost *remote_cups_host;
 
-              error = NULL;
+              snmp_host = pp_host_new (host, port);
+              remote_cups_host = g_object_ref (snmp_host);
 
-              bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-              if (bus)
-                {
-                  output = g_dbus_connection_call_sync (bus,
-                                                        SCP_BUS,
-                                                        SCP_PATH,
-                                                        SCP_IFACE,
-                                                        "MissingExecutables",
-                                                        g_variant_new ("(s)", ppd_file_name),
-                                                        NULL,
-                                                        G_DBUS_CALL_FLAGS_NONE,
-                                                        60000,
-                                                        NULL,
-                                                        &error);
-                  g_object_unref (bus);
-
-                  if (output)
-                    {
-                      if (g_variant_n_children (output) == 1)
-                        {
-                          array = g_variant_get_child_value (output, 0);
-                          if (array)
-                            {
-                              for (i = 0; i < g_variant_n_children (array); i++)
-                                {
-                                  executables = g_list_append (
-                                                  executables,
-                                                    g_strdup (g_variant_get_string (
-                                                      g_variant_get_child_value (array, i),
-                                                      NULL)));
-                                }
-                            }
-                        }
-                      g_variant_unref (output);
-                    }
-                }
+              priv->remote_cups_searching = TRUE;
+              priv->snmp_searching = TRUE;
+              update_spinner_state (dialog);
 
-              if (bus == NULL ||
-                  (error &&
-                   error->domain == G_DBUS_ERROR &&
-                   (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN ||
-                    error->code == G_DBUS_ERROR_UNKNOWN_METHOD)))
-                {
-                  g_warning ("Install system-config-printer which provides \
-DBus method \"MissingExecutables\" to find missing executables and filters.");
-                  g_error_free (error);
-                }
+              pp_host_get_remote_cups_devices_async (snmp_host,
+                                                     priv->cancellable,
+                                                     get_remote_cups_devices_cb,
+                                                     dialog);
 
-              executables = g_list_sort (executables, (GCompareFunc) g_strcmp0);
-              executables = glist_uniq (executables);
+              pp_host_get_snmp_devices_async (remote_cups_host,
+                                              priv->cancellable,
+                                              get_snmp_devices_cb,
+                                              dialog);
 
-              if (executables)
-                {
-                  bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-                  if (bus)
-                    {
-                      GList *exec_iter;
+              g_free (host);
+            }
+        }
+    }
 
-                      for (exec_iter = executables; exec_iter; exec_iter = exec_iter->next)
-                        {
-                          output = g_dbus_connection_call_sync (bus,
-                                                                PACKAGE_KIT_BUS,
-                                                                PACKAGE_KIT_PATH,
-                                                                PACKAGE_KIT_QUERY_IFACE,
-                                                                "SearchFile",
-                                                                g_variant_new ("(ss)",
-                                                                               (gchar *) exec_iter->data,
-                                                                               ""),
-                                                                G_VARIANT_TYPE ("(bs)"),
-                                                                G_DBUS_CALL_FLAGS_NONE,
-                                                                60000,
-                                                                NULL,
-                                                                &error);
-
-                          if (output)
-                            {
-                              gboolean  installed;
-                              gchar    *package;
-
-                              g_variant_get (output,
-                                             "(bs)",
-                                             &installed,
-                                             &package);
-                              if (!installed)
-                                packages = g_list_append (packages, g_strdup (package));
-                              g_variant_unref (output);
-                            }
-                          else
-                            {
-                              g_warning ("%s", error->message);
-                              g_error_free (error);
-                            }
-                        }
+  actualize_devices_list (dialog);
 
-                      g_object_unref (bus);
-                    }
-                  else
-                    {
-                      g_warning ("%s", error->message);
-                      g_error_free (error);
-                    }
+  g_free (text);
+}
 
-                  g_list_free_full (executables, g_free);
-                }
+static void
+search_address_cb2 (GtkEntry             *entry,
+                    GtkEntryIconPosition  icon_pos,
+                    GdkEvent             *event,
+                    gpointer              user_data)
+{
+  search_address_cb (entry, user_data);
+}
 
-              packages = g_list_sort (packages, (GCompareFunc) g_strcmp0);
-              packages = glist_uniq (packages);
+static void
+actualize_devices_list (PpNewPrinterDialog *dialog)
+{
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  GtkTreeViewColumn *column;
+  GtkTreeSelection  *selection;
+  GtkListStore      *store;
+  GtkTreeView       *treeview;
+  GtkTreeIter        iter;
+  gboolean           no_device = TRUE;
+  TDevice           *device;
+  gfloat             yalign;
+  GList             *item;
+  gchar             *display_string;
+
+  treeview = (GtkTreeView *)
+    gtk_builder_get_object (priv->builder, "devices-treeview");
+
+  store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+  for (item = priv->devices; item; item = item->next)
+    {
+      device = (TDevice *) item->data;
+
+      if (device->display_name &&
+          (device->device_id ||
+           device->device_ppd ||
+           (device->host_name &&
+            device->acquisition_method == ACQUISITION_METHOD_REMOTE_CUPS_SERVER)) &&
+          device->show)
+        {
+          if (device->device_location)
+            display_string = g_markup_printf_escaped ("<b>%s</b>\n<small><span foreground=\"#555555\">%s</span></small>",
+                                                      device->display_name,
+                                                      device->device_location);
+          else
+            display_string = g_markup_printf_escaped ("<b>%s</b>\n ",
+                                                      device->display_name);
+
+          gtk_list_store_append (store, &iter);
+          gtk_list_store_set (store, &iter,
+                              DEVICE_ICON_COLUMN, device->network_device ? "printer-network" : "printer",
+                              DEVICE_NAME_COLUMN, device->device_name,
+                              DEVICE_DISPLAY_NAME_COLUMN, display_string,
+                              -1);
+          no_device = FALSE;
+
+          g_free (display_string);
+        }
+    }
 
-              if (packages)
-                {
-                  bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-                  if (bus)
-                    {
-                      GVariantBuilder  array_builder;
-                      GList           *pkg_iter;
-                      guint            window_id = 0;
+  column = gtk_tree_view_get_column (treeview, 0);
+  if (priv->text_renderer)
+    gtk_cell_renderer_get_alignment (priv->text_renderer, NULL, &yalign);
 
-                      g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("as"));
+  if (no_device &&
+      !priv->cups_searching &&
+      !priv->remote_cups_searching &&
+      !priv->snmp_searching)
+    {
+      if (priv->text_renderer)
+        gtk_cell_renderer_set_alignment (priv->text_renderer, 0.5, yalign);
 
-                      for (pkg_iter = packages; pkg_iter; pkg_iter = pkg_iter->next)
-                        g_variant_builder_add (&array_builder,
-                                               "s",
-                                               (gchar *) pkg_iter->data);
+      if (column)
+        gtk_tree_view_column_set_max_width (column, 0);
 
-#ifdef GDK_WINDOWING_X11
-                      window_id = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (pp->dialog))),
-#endif
+      gtk_widget_set_sensitive (GTK_WIDGET (treeview), FALSE);
 
-                      output = g_dbus_connection_call_sync (bus,
-                                                            PACKAGE_KIT_BUS,
-                                                            PACKAGE_KIT_PATH,
-                                                            PACKAGE_KIT_MODIFY_IFACE,
-                                                            "InstallPackageNames",
-                                                            g_variant_new ("(uass)",
-                                                                           window_id,
-                                                                           &array_builder,
-                                                                           "hide-finished"),
-                                                            NULL,
-                                                            G_DBUS_CALL_FLAGS_NONE,
-                                                            60000,
-                                                            NULL,
-                                                            &error);
-                      g_object_unref (bus);
-
-                      if (output)
-                        {
-                          g_variant_unref (output);
-                        }
-                      else
-                        {
-                          g_warning ("%s", error->message);
-                          g_error_free (error);
-                        }
-                    }
-                  else
-                    {
-                      g_warning ("%s", error->message);
-                      g_error_free (error);
-                    }
+      display_string = g_markup_printf_escaped ("<b>%s</b>\n",
+      /* Translators: No printers were found */
+                                                _("No printers detected."));
 
-                  g_list_free_full (packages, g_free);
-                }
-            }
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter,
+                          DEVICE_DISPLAY_NAME_COLUMN, display_string,
+                          -1);
+
+      g_free (display_string);
+    }
+  else
+    {
+      if (priv->text_renderer)
+        gtk_cell_renderer_set_alignment (priv->text_renderer, 0.0, yalign);
 
-          if (ppd_file_name)
-            g_unlink (ppd_file_name);
+      if (column)
+        {
+          gtk_tree_view_column_set_max_width (column, -1);
+          gtk_tree_view_column_set_min_width (column, 80);
         }
+      gtk_widget_set_sensitive (GTK_WIDGET (treeview), TRUE);
     }
 
-  pp_new_printer_dialog_hide (pp);
-  pp->user_callback (GTK_DIALOG (pp->dialog), dialog_response, pp->user_data);
-}
+  gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
 
-static void
-new_printer_cancel_button_cb (GtkButton *button,
-                              gpointer   user_data)
-{
-  PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
+  if (!no_device &&
+      gtk_tree_model_get_iter_first ((GtkTreeModel *) store, &iter) &&
+      (selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview))) != NULL)
+    gtk_tree_selection_select_iter (selection, &iter);
 
-  pp_new_printer_dialog_hide (pp);
-  pp->user_callback (GTK_DIALOG (pp->dialog), GTK_RESPONSE_CANCEL, pp->user_data);
+  g_object_unref (store);
+  update_spinner_state (dialog);
 }
 
-PpNewPrinterDialog *
-pp_new_printer_dialog_new (GtkWindow            *parent,
-                           UserResponseCallback  user_callback,
-                           gpointer              user_data)
+static void
+cups_get_dests_cb (GObject      *source_object,
+                   GAsyncResult *res,
+                   gpointer      user_data)
 {
-  PpNewPrinterDialog *pp;
-  GtkWidget          *widget;
-  GError             *error = NULL;
-  gchar              *objects[] = { "dialog", "main-vbox", NULL };
-  guint               builder_result;
+  PpNewPrinterDialog        *dialog;
+  PpNewPrinterDialogPrivate *priv;
+  PpCupsDests               *dests;
+  PpCups                    *cups = (PpCups *) source_object;
+  GError                    *error = NULL;
 
-  pp = g_new0 (PpNewPrinterDialog, 1);
+  dests = pp_cups_get_dests_finish (cups, res, &error);
+  g_object_unref (source_object);
 
-  pp->builder = gtk_builder_new ();
-  pp->parent = GTK_WIDGET (parent);
+  if (dests)
+    {
+      dialog = PP_NEW_PRINTER_DIALOG (user_data);
+      priv = dialog->priv;
 
-  builder_result = gtk_builder_add_objects_from_file (pp->builder,
-                                                      DATADIR"/new-printer-dialog.ui",
-                                                      objects, &error);
+      priv->dests = dests->dests;
+      priv->num_of_dests = dests->num_of_dests;
 
-  if (builder_result == 0)
+      get_cups_devices (dialog);
+    }
+  else
     {
-      g_warning ("Could not load ui: %s", error->message);
+      if (error->domain != G_IO_ERROR ||
+          error->code != G_IO_ERROR_CANCELLED)
+        {
+          dialog = PP_NEW_PRINTER_DIALOG (user_data);
+
+          g_warning ("%s", error->message);
+
+          get_cups_devices (dialog);
+        }
+
       g_error_free (error);
-      return NULL;
     }
+}
 
-  pp->device_connection_types = NULL;
-  pp->num_device_connection_types = 0;
+static void
+populate_devices_list (PpNewPrinterDialog *dialog)
+{
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  GtkTreeViewColumn         *column;
+  GtkWidget                 *treeview;
+  PpCups                    *cups;
 
-  pp->devices = NULL;
-  pp->num_devices = 0;
+  treeview = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "devices-treeview");
 
-  pp->dialog = (GtkWidget *) gtk_builder_get_object (pp->builder, "dialog");
+  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
+                    "changed", G_CALLBACK (device_selection_changed_cb), dialog);
+
+  priv->icon_renderer = gtk_cell_renderer_pixbuf_new ();
+  g_object_set (priv->icon_renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL);
+  gtk_cell_renderer_set_alignment (priv->icon_renderer, 1.0, 0.5);
+  gtk_cell_renderer_set_padding (priv->icon_renderer, 4, 4);
+  column = gtk_tree_view_column_new_with_attributes ("Icon", priv->icon_renderer,
+                                                     "icon-name", DEVICE_ICON_COLUMN, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
-  pp->user_callback = user_callback;
-  pp->user_data = user_data;
 
-  pp->cancellable = NULL;
-  pp->warning = NULL;
-  pp->show_warning = FALSE;
+  priv->text_renderer = gtk_cell_renderer_text_new ();
+  column = gtk_tree_view_column_new_with_attributes ("Devices", priv->text_renderer,
+                                                     "markup", DEVICE_DISPLAY_NAME_COLUMN, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
 
-  /* connect signals */
-  g_signal_connect (pp->dialog, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+  cups = pp_cups_new ();
+  pp_cups_get_dests_async (cups, priv->cancellable, cups_get_dests_cb, dialog);
+}
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "new-printer-add-button");
-  g_signal_connect (widget, "clicked", G_CALLBACK (new_printer_add_button_cb), pp);
-  gtk_widget_set_sensitive (widget, FALSE);
+static void
+printer_add_async_cb (GObject      *source_object,
+                      GAsyncResult *res,
+                      gpointer      user_data)
+{
+  PpNewPrinterDialog        *dialog;
+  GtkResponseType            response_id = GTK_RESPONSE_OK;
+  PpNewPrinter              *new_printer = (PpNewPrinter *) source_object;
+  gboolean                   success;
+  GError                    *error = NULL;
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "new-printer-cancel-button");
-  g_signal_connect (widget, "clicked", G_CALLBACK (new_printer_cancel_button_cb), pp);
+  success = pp_new_printer_add_finish (new_printer, res, &error);
+  g_object_unref (source_object);
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (pp->builder, "search-by-address-checkbutton");
-  g_signal_connect (widget, "toggled", G_CALLBACK (search_address_cb), pp);
+  if (success)
+    {
+      dialog = PP_NEW_PRINTER_DIALOG (user_data);
+
+      emit_response (dialog, response_id);
+    }
+  else
+    {
+      if (error->domain != G_IO_ERROR ||
+          error->code != G_IO_ERROR_CANCELLED)
+        {
+          dialog = PP_NEW_PRINTER_DIALOG (user_data);
 
-  gtk_window_set_transient_for (GTK_WINDOW (pp->dialog), GTK_WINDOW (parent));
-  gtk_window_set_modal (GTK_WINDOW (pp->dialog), TRUE);
-  gtk_window_present (GTK_WINDOW (pp->dialog));
-  gtk_widget_show_all (GTK_WIDGET (pp->dialog));
+          g_warning ("%s", error->message);
 
-  pp->searching = TRUE;
-  populate_device_types_list (pp);
-  populate_devices_list (pp);
+          response_id = GTK_RESPONSE_REJECT;
 
-  return pp;
+          emit_response (dialog, response_id);
+        }
+
+      g_error_free (error);
+    }
 }
 
-void
-pp_new_printer_dialog_free (PpNewPrinterDialog *pp)
+static void
+new_printer_dialog_response_cb (GtkDialog *_dialog,
+                                gint       response_id,
+                                gpointer   user_data)
 {
-  gint i;
-
-  for (i = 0; i < pp->num_device_connection_types; i++)
-    g_free (pp->device_connection_types[i]);
-  g_free (pp->device_connection_types);
-  pp->device_connection_types = NULL;
+  PpNewPrinterDialog        *dialog = (PpNewPrinterDialog*) user_data;
+  PpNewPrinterDialogPrivate *priv = dialog->priv;
+  GtkTreeModel              *model;
+  GtkTreeIter                iter;
+  GtkWidget                 *treeview;
+  TDevice                   *device = NULL;
+  TDevice                   *tmp;
+  GList                     *list_iter;
+  gchar                     *device_name = NULL;
+
+  gtk_widget_hide (GTK_WIDGET (_dialog));
+
+  if (response_id == GTK_RESPONSE_OK)
+    {
+      g_cancellable_cancel (priv->cancellable);
+      g_clear_object (&priv->cancellable);
 
-  free_devices (pp);
+      treeview = (GtkWidget*)
+        gtk_builder_get_object (priv->builder, "devices-treeview");
 
-  gtk_widget_destroy (GTK_WIDGET (pp->dialog));
-  pp->dialog = NULL;
+      if (treeview &&
+          gtk_tree_selection_get_selected (
+            gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
+        {
+          gtk_tree_model_get (model, &iter,
+                              DEVICE_NAME_COLUMN, &device_name,
+                              -1);
+        }
 
-  g_object_unref (pp->builder);
-  pp->builder = NULL;
+      for (list_iter = priv->devices; list_iter; list_iter = list_iter->next)
+        {
+          tmp = (TDevice *) list_iter->data;
+          if (tmp && g_strcmp0 (tmp->device_name, device_name) == 0)
+            {
+              device = tmp;
+              break;
+            }
+        }
 
-  if (pp->cancellable)
-    {
-      g_cancellable_cancel (pp->cancellable);
-      g_object_unref (pp->cancellable);
-    }
+      if (device)
+        {
+          PpNewPrinter *new_printer;
+          guint         window_id = 0;
 
-  g_free (pp->warning);
+          emit_pre_response (dialog,
+                             device->device_name,
+                             device->device_location,
+                             device->device_make_and_model,
+                             device->network_device);
 
-  g_free (pp);
-}
+#ifdef GDK_WINDOWING_X11
+          window_id = GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (_dialog)));
+#endif
 
-static void
-pp_new_printer_dialog_hide (PpNewPrinterDialog *pp)
-{
-  gtk_widget_hide (GTK_WIDGET (pp->dialog));
+          new_printer = pp_new_printer_new ();
+          g_object_set (new_printer,
+                        "name", device->device_name,
+                        "original-name""", device->device_original_name,
+                        "device-uri", device->device_uri,
+                        "device-id", device->device_id,
+                        "ppd-name", device->device_ppd,
+                        "ppd-file-name", device->device_ppd,
+                        "info", device->device_info,
+                        "location", device->device_location,
+                        "make-and-model", device->device_make_and_model,
+                        "host-name", device->host_name,
+                        "host-port", device->host_port,
+                        "is-network-device", device->network_device,
+                        "window-id", window_id,
+                        NULL);
+
+          priv->cancellable = g_cancellable_new ();
+
+          pp_new_printer_add_async (new_printer,
+                                    priv->cancellable,
+                                    printer_add_async_cb,
+                                    dialog);
+        }
+    }
+  else
+    {
+      emit_response (dialog, GTK_RESPONSE_CANCEL);
+    }
 }
diff --git a/panels/printers/pp-new-printer-dialog.h b/panels/printers/pp-new-printer-dialog.h
index 618c0d7..ba4eb88 100644
--- a/panels/printers/pp-new-printer-dialog.h
+++ b/panels/printers/pp-new-printer-dialog.h
@@ -25,15 +25,40 @@
 
 G_BEGIN_DECLS
 
-typedef struct _PpNewPrinterDialog PpNewPrinterDialog;
+#define PP_TYPE_NEW_PRINTER_DIALOG            (pp_new_printer_dialog_get_type ())
+#define PP_NEW_PRINTER_DIALOG(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), PP_TYPE_NEW_PRINTER_DIALOG, PpNewPrinterDialog))
+#define PP_NEW_PRINTER_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PP_TYPE_NEW_PRINTER_DIALOG, PpNewPrinterDialogClass))
+#define PP_IS_NEW_PRINTER_DIALOG(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), PP_TYPE_NEW_PRINTER_DIALOG))
+#define PP_IS_NEW_PRINTER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PP_TYPE_NEW_PRINTER_DIALOG))
+#define PP_NEW_PRINTER_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PP_TYPE_NEW_PRINTER_DIALOG, PpNewPrinterDialogClass))
 
-typedef void (*UserResponseCallback) (GtkDialog *dialog, gint response_id, gpointer user_data);
+typedef struct _PpNewPrinterDialog        PpNewPrinterDialog;
+typedef struct _PpNewPrinterDialogClass   PpNewPrinterDialogClass;
+typedef struct _PpNewPrinterDialogPrivate PpNewPrinterDialogPrivate;
 
-PpNewPrinterDialog *pp_new_printer_dialog_new  (GtkWindow            *parent,
-                                                UserResponseCallback  user_callback,
-                                                gpointer              user_data);
-void                pp_new_printer_dialog_free (PpNewPrinterDialog   *dialog);
+struct _PpNewPrinterDialog
+{
+  GObject                    parent_instance;
+  PpNewPrinterDialogPrivate *priv;
+};
+
+struct _PpNewPrinterDialogClass
+{
+  GObjectClass parent_class;
+
+  void (*pre_response)  (PpNewPrinterDialog *dialog,
+                         const gchar        *device_name,
+                         const gchar        *device_location,
+                         const gchar        *device_make_and_model,
+                         gboolean            is_network_device);
+
+  void (*response)      (PpNewPrinterDialog *dialog,
+                         gint                response_id);
+};
+
+GType               pp_new_printer_dialog_get_type (void) G_GNUC_CONST;
+PpNewPrinterDialog *pp_new_printer_dialog_new      (GtkWindow *parent);
 
 G_END_DECLS
 
-#endif
+#endif /* __PP_NEW_PRINTER_DIALOG_H__ */



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