[gnome-control-center] printers: Place jobs to separate dialog



commit c6d8b9c8252cbf4e439cad0a225b841b2189fec0
Author: Marek Kasik <mkasik redhat com>
Date:   Tue Aug 7 14:09:33 2012 +0200

    printers: Place jobs to separate dialog
    
    This commit places list of jobs to separate dialog. The dialog
    is updated through calling of pp_jobs_dialog_update()
    from "Printers" panel because the panel is already subscribed
    to cups notifications.

 panels/printers/Makefile.am         |    7 +-
 panels/printers/cc-printers-panel.c |  446 ++++-------------------------
 panels/printers/jobs-dialog.ui      |  183 ++++++++++++
 panels/printers/pp-jobs-dialog.c    |  541 +++++++++++++++++++++++++++++++++++
 panels/printers/pp-jobs-dialog.h    |   42 +++
 panels/printers/pp-utils.c          |  265 +++++++++++++++++
 panels/printers/pp-utils.h          |   26 ++
 panels/printers/printers.ui         |  154 +----------
 8 files changed, 1122 insertions(+), 542 deletions(-)
---
diff --git a/panels/printers/Makefile.am b/panels/printers/Makefile.am
index 249ce69..0fb0c60 100644
--- a/panels/printers/Makefile.am
+++ b/panels/printers/Makefile.am
@@ -5,6 +5,7 @@ dist_ui_DATA = \
 	new-printer-dialog.ui	\
 	ppd-selection-dialog.ui	\
 	options-dialog.ui	\
+	jobs-dialog.ui		\
 	printers.ui
 
 INCLUDES = 						\
@@ -31,8 +32,10 @@ libprinters_la_SOURCES =		\
 	pp-new-printer-dialog.h		\
 	pp-ppd-selection-dialog.c	\
 	pp-ppd-selection-dialog.h	\
-	pp-options-dialog.c	\
-	pp-options-dialog.h	\
+	pp-options-dialog.c		\
+	pp-options-dialog.h		\
+	pp-jobs-dialog.c		\
+	pp-jobs-dialog.h		\
 	cc-printers-panel.c		\
 	cc-printers-panel.h
 
diff --git a/panels/printers/cc-printers-panel.c b/panels/printers/cc-printers-panel.c
index 88cccff..436e3ee 100644
--- a/panels/printers/cc-printers-panel.c
+++ b/panels/printers/cc-printers-panel.c
@@ -35,6 +35,7 @@
 #include "pp-new-printer-dialog.h"
 #include "pp-ppd-selection-dialog.h"
 #include "pp-options-dialog.h"
+#include "pp-jobs-dialog.h"
 #include "pp-utils.h"
 
 G_DEFINE_DYNAMIC_TYPE (CcPrintersPanel, cc_printers_panel, CC_TYPE_PANEL)
@@ -42,15 +43,10 @@ G_DEFINE_DYNAMIC_TYPE (CcPrintersPanel, cc_printers_panel, CC_TYPE_PANEL)
 #define PRINTERS_PANEL_PRIVATE(o) \
   (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_PRINTERS_PANEL, CcPrintersPanelPrivate))
 
-#define MECHANISM_BUS "org.opensuse.CupsPkHelper.Mechanism"
-
 #define SUPPLY_BAR_HEIGHT 20
 
 #define EMPTY_TEXT "\xe2\x80\x94"
 
-#define CLOCK_SCHEMA "org.gnome.desktop.interface"
-#define CLOCK_FORMAT_KEY "clock-format"
-
 #define RENEW_INTERVAL        500
 #define SUBSCRIPTION_DURATION 600
 
@@ -70,9 +66,7 @@ struct _CcPrintersPanelPrivate
   int num_dests;
   int current_dest;
 
-  cups_job_t *jobs;
   int num_jobs;
-  int current_job;
 
   GdkRGBA background_color;
 
@@ -80,9 +74,10 @@ struct _CcPrintersPanelPrivate
 
   GSettings *lockdown_settings;
 
-  PpNewPrinterDialog *pp_new_printer_dialog;
+  PpNewPrinterDialog   *pp_new_printer_dialog;
   PpPPDSelectionDialog *pp_ppd_selection_dialog;
-  PpOptionsDialog *pp_options_dialog;
+  PpOptionsDialog      *pp_options_dialog;
+  PpJobsDialog         *pp_jobs_dialog;
 
   GDBusProxy      *cups_proxy;
   GDBusConnection *cups_bus_connection;
@@ -108,7 +103,7 @@ typedef struct
   GCancellable *cancellable;
 } SetPPDItem;
 
-static void actualize_jobs_list (CcPrintersPanel *self);
+static void update_jobs_count (CcPrintersPanel *self);
 static void actualize_printers_list (CcPrintersPanel *self);
 static void update_sensitivity (gpointer user_data);
 static void printer_disable_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data);
@@ -155,12 +150,6 @@ cc_printers_panel_dispose (GObject *object)
 
   free_dests (CC_PRINTERS_PANEL (object));
 
-  if (priv->num_jobs > 0)
-    cupsFreeJobs (priv->num_jobs, priv->jobs);
-  priv->jobs = NULL;
-  priv->num_jobs = 0;
-  priv->current_job = -1;
-
   if (priv->builder)
     {
       g_object_unref (priv->builder);
@@ -375,7 +364,7 @@ on_cups_notification (GDBusConnection *connection,
                       priv->dests != NULL &&
                       g_strcmp0 (g_strrstr (attr_printer_uri->values[0].string.text, "/") + 1,
                                  priv->dests[priv->current_dest].name) == 0)
-                    actualize_jobs_list (self);
+                    update_jobs_count (self);
                 }
               ippDelete(response);
             }
@@ -517,7 +506,6 @@ free_dests (CcPrintersPanel *self)
 enum
 {
   NOTEBOOK_INFO_PAGE = 0,
-  NOTEBOOK_JOBS_PAGE,
   NOTEBOOK_OPTIONS_PAGE,
   NOTEBOOK_NO_PRINTERS_PAGE,
   NOTEBOOK_NO_CUPS_PAGE,
@@ -556,14 +544,12 @@ printer_selection_changed_cb (GtkTreeSelection *selection,
   gchar                  *printer_name = NULL;
   gchar                  *printer_icon = NULL;
   gchar                  *printer_type = NULL;
-  gchar                  *active_jobs = NULL;
   gchar                  *supply_type = NULL;
   gchar                  *printer_uri = NULL;
   gchar                  *location = NULL;
   gchar                  *status = NULL;
   gchar                  *device_uri = NULL;
   gchar                  *printer_hostname = NULL;
-  guint                   num_jobs;
   int                     printer_state = 3;
   int                     id = -1;
   int                     i, j;
@@ -639,29 +625,7 @@ printer_selection_changed_cb (GtkTreeSelection *selection,
 
   priv->current_dest = id;
 
-  if (!(priv->current_dest >= 0 &&
-        priv->current_dest < priv->num_dests &&
-        priv->dests != NULL &&
-        priv->current_job >= 0 &&
-        priv->current_job < priv->num_jobs &&
-        priv->jobs != NULL &&
-        g_strcmp0 (priv->dests[priv->current_dest].name,
-                   priv->jobs[priv->current_job].dest) == 0))
-    {
-      widget = (GtkWidget*)
-        gtk_builder_get_object (priv->builder, "job-release-button");
-      gtk_widget_set_sensitive (widget, FALSE);
-
-      widget = (GtkWidget*)
-        gtk_builder_get_object (priv->builder, "job-hold-button");
-      gtk_widget_set_sensitive (widget, FALSE);
-
-      widget = (GtkWidget*)
-        gtk_builder_get_object (priv->builder, "job-cancel-button");
-      gtk_widget_set_sensitive (widget, FALSE);
-
-      actualize_jobs_list (self);
-    }
+  update_jobs_count (self);
 
   if (priv->current_dest >= 0 &&
       priv->current_dest < priv->num_dests &&
@@ -936,21 +900,6 @@ printer_selection_changed_cb (GtkTreeSelection *selection,
         }
       else
         gtk_label_set_text (GTK_LABEL (widget), EMPTY_TEXT);
-
-
-      widget = (GtkWidget*)
-        gtk_builder_get_object (priv->builder, "printer-jobs-label");
-      num_jobs = priv->num_jobs < 0 ? 0 : (guint) priv->num_jobs;
-      /* Translators: there is n active print jobs on this printer */
-      active_jobs = g_strdup_printf (ngettext ("%u active", "%u active", num_jobs), num_jobs);
-
-      if (active_jobs)
-        {
-          cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), active_jobs);
-          g_free (active_jobs);
-        }
-      else
-        cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
     }
   else
     {
@@ -1307,319 +1256,49 @@ enum
 };
 
 static void
-actualize_jobs_list (CcPrintersPanel *self)
+update_jobs_count (CcPrintersPanel *self)
 {
   CcPrintersPanelPrivate *priv;
-  GtkListStore           *store;
-  GtkTreeView            *treeview;
-  GtkTreeIter             iter;
-  GSettings              *settings;
+  cups_job_t             *jobs;
   GtkWidget              *widget;
-  gchar                  *active_jobs;
+  gchar                  *active_jobs = NULL;
   gint                    num_jobs;
-  gint                    i;
 
   priv = PRINTERS_PANEL_PRIVATE (self);
 
-  treeview = (GtkTreeView*)
-    gtk_builder_get_object (priv->builder, "job-treeview");
-
-  if (priv->num_jobs > 0)
-    cupsFreeJobs (priv->num_jobs, priv->jobs);
   priv->num_jobs = -1;
-  priv->jobs = NULL;
 
-  priv->current_job = -1;
   if (priv->current_dest >= 0 &&
       priv->current_dest < priv->num_dests &&
       priv->dests != NULL)
     {
-      priv->num_jobs = cupsGetJobs (&priv->jobs, priv->dests[priv->current_dest].name, 1, CUPS_WHICHJOBS_ACTIVE);
-
-      widget = (GtkWidget*)
-        gtk_builder_get_object (priv->builder, "printer-jobs-label");
+      priv->num_jobs = cupsGetJobs (&jobs, priv->dests[priv->current_dest].name, 1, CUPS_WHICHJOBS_ACTIVE);
+      if (priv->num_jobs > 0)
+        cupsFreeJobs (priv->num_jobs, jobs);
 
       num_jobs = priv->num_jobs < 0 ? 0 : (guint) priv->num_jobs;
       /* Translators: there is n active print jobs on this printer */
       active_jobs = g_strdup_printf (ngettext ("%u active", "%u active", num_jobs), num_jobs);
-
-      if (active_jobs)
-        {
-          cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), active_jobs);
-          g_free (active_jobs);
-        }
-      else
-        cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
     }
 
-  store = gtk_list_store_new (JOB_N_COLUMNS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+  widget = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "printer-jobs-label");
 
-  for (i = 0; i < priv->num_jobs; i++)
+  if (active_jobs)
     {
-      GDesktopClockFormat  value;
-      GDateTime           *time;
-      struct tm *ts;
-      gchar     *time_string;
-      gchar     *state = NULL;
-
-      ts = localtime (&(priv->jobs[i].creation_time));
-      time = g_date_time_new_local (ts->tm_year,
-                                    ts->tm_mon,
-                                    ts->tm_mday,
-                                    ts->tm_hour,
-                                    ts->tm_min,
-                                    ts->tm_sec);
-
-      settings = g_settings_new (CLOCK_SCHEMA);
-      value = g_settings_get_enum (settings, CLOCK_FORMAT_KEY);
-
-      if (value == G_DESKTOP_CLOCK_FORMAT_24H)
-        time_string = g_date_time_format (time, "%k:%M");
-      else
-        time_string = g_date_time_format (time, "%l:%M %p");
-
-      g_date_time_unref (time);
-
-      switch (priv->jobs[i].state)
-        {
-          case IPP_JOB_PENDING:
-            /* Translators: Job's state (job is waiting to be printed) */
-            state = g_strdup (C_("print job", "Pending"));
-            break;
-          case IPP_JOB_HELD:
-            /* Translators: Job's state (job is held for printing) */
-            state = g_strdup (C_("print job", "Held"));
-            break;
-          case IPP_JOB_PROCESSING:
-            /* Translators: Job's state (job is currently printing) */
-            state = g_strdup (C_("print job", "Processing"));
-            break;
-          case IPP_JOB_STOPPED:
-            /* Translators: Job's state (job has been stopped) */
-            state = g_strdup (C_("print job", "Stopped"));
-            break;
-          case IPP_JOB_CANCELED:
-            /* Translators: Job's state (job has been canceled) */
-            state = g_strdup (C_("print job", "Canceled"));
-            break;
-          case IPP_JOB_ABORTED:
-            /* Translators: Job's state (job has aborted due to error) */
-            state = g_strdup (C_("print job", "Aborted"));
-            break;
-          case IPP_JOB_COMPLETED:
-            /* Translators: Job's state (job has completed successfully) */
-            state = g_strdup (C_("print job", "Completed"));
-            break;
-        }
-
-      gtk_list_store_append (store, &iter);
-      gtk_list_store_set (store, &iter,
-                          JOB_ID_COLUMN, i,
-                          JOB_TITLE_COLUMN, priv->jobs[i].title,
-                          JOB_STATE_COLUMN, state,
-                          JOB_CREATION_TIME_COLUMN, time_string,
-                          -1);
-
-      g_free (time_string);
-      g_free (state);
+      cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), active_jobs);
+      g_free (active_jobs);
     }
-
-  gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
-  g_object_unref (store);
-}
-
-static void
-job_selection_changed_cb (GtkTreeSelection *selection,
-                          gpointer          user_data)
-{
-  CcPrintersPanelPrivate *priv;
-  CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
-  GtkTreeModel           *model;
-  GtkTreeIter             iter;
-  GtkWidget              *widget;
-  int                     id = -1;
-
-  priv = PRINTERS_PANEL_PRIVATE (self);
-
-  if (gtk_tree_selection_get_selected (selection, &model, &iter))
-    gtk_tree_model_get (model, &iter,
-			JOB_ID_COLUMN, &id,
-			-1);
   else
-    id = -1;
-
-  priv->current_job = id;
+    cc_editable_entry_set_text (CC_EDITABLE_ENTRY (widget), EMPTY_TEXT);
 
-  if (priv->current_job >= 0 &&
-      priv->current_job < priv->num_jobs &&
-      priv->jobs != NULL)
+  if (priv->pp_jobs_dialog)
     {
-      ipp_jstate_t job_state = priv->jobs[priv->current_job].state;
-
-      widget = (GtkWidget*)
-        gtk_builder_get_object (priv->builder, "job-release-button");
-      gtk_widget_set_sensitive (widget, job_state == IPP_JOB_HELD);
-
-      widget = (GtkWidget*)
-        gtk_builder_get_object (priv->builder, "job-hold-button");
-      gtk_widget_set_sensitive (widget, job_state == IPP_JOB_PENDING);
-
-      widget = (GtkWidget*)
-        gtk_builder_get_object (priv->builder, "job-cancel-button");
-      gtk_widget_set_sensitive (widget, job_state < IPP_JOB_CANCELED);
+      pp_jobs_dialog_update (priv->pp_jobs_dialog);
     }
 }
 
 static void
-populate_jobs_list (CcPrintersPanel *self)
-{
-  CcPrintersPanelPrivate *priv;
-  GtkTreeViewColumn      *column;
-  GtkCellRenderer        *renderer;
-  GtkCellRenderer        *title_renderer;
-  GtkTreeView            *treeview;
-
-  priv = PRINTERS_PANEL_PRIVATE (self);
-
-  treeview = (GtkTreeView*)
-    gtk_builder_get_object (priv->builder, "job-treeview");
-
-  renderer = gtk_cell_renderer_text_new ();
-  title_renderer = gtk_cell_renderer_text_new ();
-
-  /* Translators: Name of column showing titles of print jobs */
-  column = gtk_tree_view_column_new_with_attributes (_("Job Title"), title_renderer,
-                                                     "text", JOB_TITLE_COLUMN, NULL);
-  g_object_set (G_OBJECT (title_renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-  gtk_tree_view_column_set_fixed_width (column, 180);
-  gtk_tree_view_column_set_min_width (column, 180);
-  gtk_tree_view_column_set_max_width (column, 180);
-  gtk_tree_view_append_column (treeview, column);
-
-  /* Translators: Name of column showing statuses of print jobs */
-  column = gtk_tree_view_column_new_with_attributes (_("Job State"), renderer,
-                                                     "text", JOB_STATE_COLUMN, NULL);
-  gtk_tree_view_column_set_expand (column, TRUE);
-  gtk_tree_view_append_column (treeview, column);
-
-  /* Translators: Name of column showing times of creation of print jobs */
-  column = gtk_tree_view_column_new_with_attributes (_("Time"), renderer,
-                                                     "text", JOB_CREATION_TIME_COLUMN, NULL);
-  gtk_tree_view_column_set_expand (column, TRUE);
-  gtk_tree_view_append_column (treeview, column);
-
-  g_signal_connect (gtk_tree_view_get_selection (treeview),
-                    "changed", G_CALLBACK (job_selection_changed_cb), self);
-
-  actualize_jobs_list (self);
-}
-
-static void
-job_process_cb (GtkButton *button,
-                gpointer   user_data)
-{
-  CcPrintersPanelPrivate *priv;
-  CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
-  GDBusConnection        *bus;
-  GtkWidget              *widget;
-  GError                 *error = NULL;
-  GVariant               *output = NULL;
-  int                     id = -1;
-
-  priv = PRINTERS_PANEL_PRIVATE (self);
-
-  if (priv->current_job >= 0 &&
-      priv->current_job < priv->num_jobs &&
-      priv->jobs != NULL)
-    id = priv->jobs[priv->current_job].id;
-
-  if (id >= 0)
-    {
-      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);
-          return;
-        }
-
-      if ((GtkButton*) gtk_builder_get_object (priv->builder,
-                                               "job-cancel-button") ==
-          button)
-        output = g_dbus_connection_call_sync (bus,
-                                              MECHANISM_BUS,
-                                              "/",
-                                              MECHANISM_BUS,
-                                              "JobCancelPurge",
-                                              g_variant_new ("(ib)", id, FALSE),
-                                              G_VARIANT_TYPE ("(s)"),
-                                              G_DBUS_CALL_FLAGS_NONE,
-                                              -1,
-                                              NULL,
-                                              &error);
-      else if ((GtkButton*) gtk_builder_get_object (priv->builder,
-                                                        "job-hold-button") ==
-               button)
-        output = g_dbus_connection_call_sync (bus,
-                                              MECHANISM_BUS,
-                                              "/",
-                                              MECHANISM_BUS,
-                                              "JobSetHoldUntil",
-                                              g_variant_new ("(is)", id, "indefinite"),
-                                              G_VARIANT_TYPE ("(s)"),
-                                              G_DBUS_CALL_FLAGS_NONE,
-                                              -1,
-                                              NULL,
-                                              &error);
-      else if ((GtkButton*) gtk_builder_get_object (priv->builder,
-                                                        "job-release-button") ==
-               button)
-        output = g_dbus_connection_call_sync (bus,
-                                              MECHANISM_BUS,
-                                              "/",
-                                              MECHANISM_BUS,
-                                              "JobSetHoldUntil",
-                                              g_variant_new ("(is)", id, "no-hold"),
-                                              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);
-          else
-            actualize_jobs_list (self);
-
-          g_variant_unref (output);
-        }
-      else
-        {
-          g_warning ("%s", error->message);
-          g_error_free (error);
-        }
-  }
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "job-release-button");
-  gtk_widget_set_sensitive (widget, FALSE);
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "job-hold-button");
-  gtk_widget_set_sensitive (widget, FALSE);
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "job-cancel-button");
-  gtk_widget_set_sensitive (widget, FALSE);
-}
-
-static void
 printer_disable_cb (GObject    *gobject,
                     GParamSpec *pspec,
                     gpointer    user_data)
@@ -2784,21 +2463,6 @@ go_back_cb (GtkButton *button,
 }
 
 static void
-switch_to_jobs_cb (GtkButton *button,
-                   gpointer   user_data)
-{
-  CcPrintersPanelPrivate  *priv;
-  CcPrintersPanel         *self = (CcPrintersPanel*) user_data;
-  GtkWidget               *widget;
-
-  priv = PRINTERS_PANEL_PRIVATE (self);
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "notebook");
-  gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), NOTEBOOK_JOBS_PAGE);
-}
-
-static void
 printer_options_response_cb (GtkDialog *dialog,
                              gint       response_id,
                              gpointer   user_data)
@@ -2925,6 +2589,43 @@ update_label_padding (GtkWidget     *widget,
 }
 
 static void
+jobs_dialog_response_cb (GtkDialog *dialog,
+                         gint       response_id,
+                         gpointer   user_data)
+{
+  CcPrintersPanelPrivate *priv;
+  CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  pp_jobs_dialog_free (priv->pp_jobs_dialog);
+  priv->pp_jobs_dialog = NULL;
+}
+
+static void
+printer_jobs_cb (GtkToolButton *toolbutton,
+                 gpointer       user_data)
+{
+  CcPrintersPanelPrivate *priv;
+  CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
+  GtkWidget              *widget;
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "main-vbox");
+
+  if (priv->current_dest >= 0 &&
+      priv->current_dest < priv->num_dests &&
+      priv->dests != NULL)
+    priv->pp_jobs_dialog = pp_jobs_dialog_new (
+      GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+      jobs_dialog_response_cb,
+      self,
+      priv->dests[priv->current_dest].name);
+}
+
+static void
 cc_printers_panel_init (CcPrintersPanel *self)
 {
   CcPrintersPanelPrivate *priv;
@@ -2946,9 +2647,7 @@ cc_printers_panel_init (CcPrintersPanel *self)
   priv->num_dests = 0;
   priv->current_dest = -1;
 
-  priv->jobs = NULL;
   priv->num_jobs = 0;
-  priv->current_job = -1;
 
   priv->pp_new_printer_dialog = NULL;
   priv->pp_options_dialog = NULL;
@@ -2988,18 +2687,6 @@ cc_printers_panel_init (CcPrintersPanel *self)
 
   /* connect signals */
   widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "job-cancel-button");
-  g_signal_connect (widget, "clicked", G_CALLBACK (job_process_cb), self);
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "job-hold-button");
-  g_signal_connect (widget, "clicked", G_CALLBACK (job_process_cb), self);
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "job-release-button");
-  g_signal_connect (widget, "clicked", G_CALLBACK (job_process_cb), self);
-
-  widget = (GtkWidget*)
     gtk_builder_get_object (priv->builder, "printer-add-button");
   g_signal_connect (widget, "clicked", G_CALLBACK (printer_add_cb), self);
 
@@ -3028,16 +2715,12 @@ cc_printers_panel_init (CcPrintersPanel *self)
   g_signal_connect (widget, "clicked", G_CALLBACK (test_page_cb), self);
 
   widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "back-button-1");
-  g_signal_connect (widget, "clicked", G_CALLBACK (go_back_cb), self);
-
-  widget = (GtkWidget*)
     gtk_builder_get_object (priv->builder, "back-button-2");
   g_signal_connect (widget, "clicked", G_CALLBACK (go_back_cb), self);
 
   widget = (GtkWidget*)
     gtk_builder_get_object (priv->builder, "printer-jobs-button");
-  g_signal_connect (widget, "clicked", G_CALLBACK (switch_to_jobs_cb), self);
+  g_signal_connect (widget, "clicked", G_CALLBACK (printer_jobs_cb), self);
 
   widget = (GtkWidget*)
     gtk_builder_get_object (priv->builder, "printer-options-button");
@@ -3075,16 +2758,6 @@ cc_printers_panel_init (CcPrintersPanel *self)
   context = gtk_widget_get_style_context (widget);
   gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
 
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "queue-scrolledwindow");
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
-
-  widget = (GtkWidget*)
-    gtk_builder_get_object (priv->builder, "queue-toolbar");
-  context = gtk_widget_get_style_context (widget);
-  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
-
 
   /* Make model label and ip-address label selectable */
   widget = (GtkWidget*)
@@ -3111,7 +2784,6 @@ Please check your installation");
                                           &priv->background_color);
 
   populate_printers_list (self);
-  populate_jobs_list (self);
   attach_to_cups_notifier (self);
 
   priv->get_all_ppds_cancellable = g_cancellable_new ();
diff --git a/panels/printers/jobs-dialog.ui b/panels/printers/jobs-dialog.ui
new file mode 100644
index 0000000..d58be2c
--- /dev/null
+++ b/panels/printers/jobs-dialog.ui
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkDialog" id="jobs-dialog">
+    <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="title" translatable="yes"> </property>
+    <property name="modal">True</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="resizable">False</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="main-vbox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action-area1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="jobs-close-button">
+                <property name="label" translatable="yes">Close</property>
+                <property name="use_action_appearance">False</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</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="GtkBox" id="box1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">10</property>
+                <child>
+                  <object class="GtkLabel" id="jobs-title">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes" comments="Translators: This tab contains list of active print jobs of the selected printer">Active Jobs</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox" id="box2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkScrolledWindow" id="queue-scrolledwindow">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="GtkTreeView" id="job-treeview">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <child internal-child="selection">
+                              <object class="GtkTreeSelection" id="treeview-selection"/>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkToolbar" id="queue-toolbar">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="icon_size">1</property>
+                        <child>
+                          <object class="GtkToolButton" id="job-release-button">
+                            <property name="use_action_appearance">False</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="label" translatable="yes">Resume Printing</property>
+                            <property name="use_underline">True</property>
+                            <property name="icon_name">media-playback-start-symbolic</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="homogeneous">True</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkToolButton" id="job-hold-button">
+                            <property name="use_action_appearance">False</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="label" translatable="yes">Pause Printing</property>
+                            <property name="use_underline">True</property>
+                            <property name="icon_name">media-playback-pause-symbolic</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="homogeneous">True</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkToolButton" id="job-cancel-button">
+                            <property name="use_action_appearance">False</property>
+                            <property name="visible">True</property>
+                            <property name="sensitive">False</property>
+                            <property name="can_focus">False</property>
+                            <property name="use_action_appearance">False</property>
+                            <property name="label" translatable="yes">Cancel Print Job</property>
+                            <property name="use_underline">True</property>
+                            <property name="icon_name">media-playback-stop-symbolic</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</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>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">jobs-close-button</action-widget>
+    </action-widgets>
+  </object>
+  <object class="GtkSizeGroup" id="sizegroup1"/>
+</interface>
diff --git a/panels/printers/pp-jobs-dialog.c b/panels/printers/pp-jobs-dialog.c
new file mode 100644
index 0000000..eac73f6
--- /dev/null
+++ b/panels/printers/pp-jobs-dialog.c
@@ -0,0 +1,541 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2012  Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Marek Kasik <mkasik redhat com>
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include <gdesktop-enums.h>
+
+#include <cups/cups.h>
+
+#include "pp-jobs-dialog.h"
+#include "pp-utils.h"
+
+#define EMPTY_TEXT "\xe2\x80\x94"
+
+#define CLOCK_SCHEMA "org.gnome.desktop.interface"
+#define CLOCK_FORMAT_KEY "clock-format"
+
+static void pp_jobs_dialog_hide (PpJobsDialog *dialog);
+
+struct _PpJobsDialog {
+  GtkBuilder *builder;
+  GtkWidget  *parent;
+
+  GtkWidget  *dialog;
+
+  UserResponseCallback user_callback;
+  gpointer             user_data;
+
+  gchar *printer_name;
+
+  cups_job_t *jobs;
+  gint num_jobs;
+  gint current_job_id;
+
+  gint ref_count;
+};
+
+enum
+{
+  JOB_ID_COLUMN,
+  JOB_TITLE_COLUMN,
+  JOB_STATE_COLUMN,
+  JOB_CREATION_TIME_COLUMN,
+  JOB_N_COLUMNS
+};
+
+static void
+update_jobs_list_cb (cups_job_t *jobs,
+                     gint        num_of_jobs,
+                     gpointer    user_data)
+{
+  GtkTreeSelection *selection;
+  PpJobsDialog     *dialog = (PpJobsDialog *) user_data;
+  GtkListStore     *store;
+  GtkTreeView      *treeview;
+  GtkTreeIter       select_iter;
+  GtkTreeIter       iter;
+  GSettings        *settings;
+  gboolean          select_iter_set = FALSE;
+  gint              i;
+  gint              select_index = 0;
+
+  treeview = (GtkTreeView*)
+    gtk_builder_get_object (dialog->builder, "job-treeview");
+
+  if (dialog->num_jobs > 0)
+    cupsFreeJobs (dialog->num_jobs, dialog->jobs);
+
+  dialog->num_jobs = num_of_jobs;
+  dialog->jobs = jobs;
+
+  store = gtk_list_store_new (JOB_N_COLUMNS,
+                              G_TYPE_INT,
+                              G_TYPE_STRING,
+                              G_TYPE_STRING,
+                              G_TYPE_STRING);
+
+  if (dialog->current_job_id >= 0)
+    {
+      for (i = 0; i < dialog->num_jobs; i++)
+        {
+          select_index = i;
+          if (dialog->jobs[i].id >= dialog->current_job_id)
+            break;
+        }
+    }
+
+  for (i = 0; i < dialog->num_jobs; i++)
+    {
+      GDesktopClockFormat  value;
+      GDateTime           *time;
+      struct tm *ts;
+      gchar     *time_string;
+      gchar     *state = NULL;
+
+      ts = localtime (&(dialog->jobs[i].creation_time));
+      time = g_date_time_new_local (ts->tm_year,
+                                    ts->tm_mon,
+                                    ts->tm_mday,
+                                    ts->tm_hour,
+                                    ts->tm_min,
+                                    ts->tm_sec);
+
+      settings = g_settings_new (CLOCK_SCHEMA);
+      value = g_settings_get_enum (settings, CLOCK_FORMAT_KEY);
+
+      if (value == G_DESKTOP_CLOCK_FORMAT_24H)
+        time_string = g_date_time_format (time, "%k:%M");
+      else
+        time_string = g_date_time_format (time, "%l:%M %p");
+
+      g_date_time_unref (time);
+
+      switch (dialog->jobs[i].state)
+        {
+          case IPP_JOB_PENDING:
+            /* Translators: Job's state (job is waiting to be printed) */
+            state = g_strdup (C_("print job", "Pending"));
+            break;
+          case IPP_JOB_HELD:
+            /* Translators: Job's state (job is held for printing) */
+            state = g_strdup (C_("print job", "Held"));
+            break;
+          case IPP_JOB_PROCESSING:
+            /* Translators: Job's state (job is currently printing) */
+            state = g_strdup (C_("print job", "Processing"));
+            break;
+          case IPP_JOB_STOPPED:
+            /* Translators: Job's state (job has been stopped) */
+            state = g_strdup (C_("print job", "Stopped"));
+            break;
+          case IPP_JOB_CANCELED:
+            /* Translators: Job's state (job has been canceled) */
+            state = g_strdup (C_("print job", "Canceled"));
+            break;
+          case IPP_JOB_ABORTED:
+            /* Translators: Job's state (job has aborted due to error) */
+            state = g_strdup (C_("print job", "Aborted"));
+            break;
+          case IPP_JOB_COMPLETED:
+            /* Translators: Job's state (job has completed successfully) */
+            state = g_strdup (C_("print job", "Completed"));
+            break;
+        }
+
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter,
+                          JOB_ID_COLUMN, dialog->jobs[i].id,
+                          JOB_TITLE_COLUMN, dialog->jobs[i].title,
+                          JOB_STATE_COLUMN, state,
+                          JOB_CREATION_TIME_COLUMN, time_string,
+                          -1);
+
+      if (i == select_index)
+        {
+          select_iter = iter;
+          select_iter_set = TRUE;
+          dialog->current_job_id = dialog->jobs[i].id;
+        }
+
+      g_free (time_string);
+      g_free (state);
+    }
+
+  gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
+
+  if (select_iter_set &&
+      (selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview))))
+    {
+      gtk_tree_selection_select_iter (selection, &select_iter);
+    }
+
+  g_object_unref (store);
+  dialog->ref_count--;
+}
+
+static void
+update_jobs_list (PpJobsDialog *dialog)
+{
+  if (dialog->printer_name)
+    {
+      dialog->ref_count++;
+      cups_get_jobs_async (dialog->printer_name,
+                           TRUE,
+                           CUPS_WHICHJOBS_ACTIVE,
+                           update_jobs_list_cb,
+                           dialog);
+    }
+}
+
+static void
+job_selection_changed_cb (GtkTreeSelection *selection,
+                          gpointer          user_data)
+{
+  PpJobsDialog *dialog = (PpJobsDialog *) user_data;
+  GtkTreeModel *model;
+  GtkTreeIter   iter;
+  GtkWidget    *widget;
+  gboolean      release_button_sensitive = FALSE;
+  gboolean      hold_button_sensitive = FALSE;
+  gboolean      cancel_button_sensitive = FALSE;
+  gint          id = -1;
+  gint          i;
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      gtk_tree_model_get (model, &iter,
+                          JOB_ID_COLUMN, &id,
+                          -1);
+    }
+  else
+    {
+      id = -1;
+    }
+
+  dialog->current_job_id = id;
+
+  if (dialog->current_job_id >= 0 &&
+      dialog->jobs != NULL)
+    {
+      for (i = 0; i < dialog->num_jobs; i++)
+        {
+          if (dialog->jobs[i].id == dialog->current_job_id)
+            {
+              ipp_jstate_t job_state = dialog->jobs[i].state;
+
+              release_button_sensitive = job_state == IPP_JOB_HELD;
+              hold_button_sensitive = job_state == IPP_JOB_PENDING;
+              cancel_button_sensitive = job_state < IPP_JOB_CANCELED;
+
+              break;
+            }
+        }
+    }
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-release-button");
+  gtk_widget_set_sensitive (widget, release_button_sensitive);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-hold-button");
+  gtk_widget_set_sensitive (widget, hold_button_sensitive);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-cancel-button");
+  gtk_widget_set_sensitive (widget, cancel_button_sensitive);
+}
+
+static void
+populate_jobs_list (PpJobsDialog *dialog)
+{
+  GtkTreeViewColumn *column;
+  GtkCellRenderer   *renderer;
+  GtkCellRenderer   *title_renderer;
+  GtkTreeView       *treeview;
+
+  treeview = (GtkTreeView*)
+    gtk_builder_get_object (dialog->builder, "job-treeview");
+
+  renderer = gtk_cell_renderer_text_new ();
+  title_renderer = gtk_cell_renderer_text_new ();
+
+  /* Translators: Name of column showing titles of print jobs */
+  column = gtk_tree_view_column_new_with_attributes (_("Job Title"), title_renderer,
+                                                     "text", JOB_TITLE_COLUMN, NULL);
+  g_object_set (G_OBJECT (title_renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+  gtk_tree_view_column_set_fixed_width (column, 180);
+  gtk_tree_view_column_set_min_width (column, 180);
+  gtk_tree_view_column_set_max_width (column, 180);
+  gtk_tree_view_append_column (treeview, column);
+
+  /* Translators: Name of column showing statuses of print jobs */
+  column = gtk_tree_view_column_new_with_attributes (_("Job State"), renderer,
+                                                     "text", JOB_STATE_COLUMN, NULL);
+  gtk_tree_view_column_set_expand (column, TRUE);
+  gtk_tree_view_append_column (treeview, column);
+
+  /* Translators: Name of column showing times of creation of print jobs */
+  column = gtk_tree_view_column_new_with_attributes (_("Time"), renderer,
+                                                     "text", JOB_CREATION_TIME_COLUMN, NULL);
+  gtk_tree_view_column_set_expand (column, TRUE);
+  gtk_tree_view_append_column (treeview, column);
+
+  g_signal_connect (gtk_tree_view_get_selection (treeview),
+                    "changed", G_CALLBACK (job_selection_changed_cb), dialog);
+
+  update_jobs_list (dialog);
+}
+
+static void
+job_process_cb_cb (gpointer user_data)
+{
+}
+
+static void
+job_process_cb (GtkButton *button,
+                gpointer   user_data)
+{
+  PpJobsDialog *dialog = (PpJobsDialog *) user_data;
+  GtkWidget    *widget;
+
+  if (dialog->current_job_id >= 0)
+    {
+      if ((GtkButton*) gtk_builder_get_object (dialog->builder,
+                                               "job-cancel-button") ==
+          button)
+        {
+          job_cancel_purge_async (dialog->current_job_id,
+                                  FALSE,
+                                  NULL,
+                                  job_process_cb_cb,
+                                  dialog);
+        }
+      else if ((GtkButton*) gtk_builder_get_object (dialog->builder,
+                                                    "job-hold-button") ==
+               button)
+        {
+          job_set_hold_until_async (dialog->current_job_id,
+                                    "indefinite",
+                                    NULL,
+                                    job_process_cb_cb,
+                                    dialog);
+        }
+      else
+        {
+          job_set_hold_until_async (dialog->current_job_id,
+                                    "no-hold",
+                                    NULL,
+                                    job_process_cb_cb,
+                                    dialog);
+        }
+  }
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-release-button");
+  gtk_widget_set_sensitive (widget, FALSE);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-hold-button");
+  gtk_widget_set_sensitive (widget, FALSE);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-cancel-button");
+  gtk_widget_set_sensitive (widget, FALSE);
+}
+
+static void
+jobs_dialog_response_cb (GtkDialog *dialog,
+                         gint       response_id,
+                         gpointer   user_data)
+{
+  PpJobsDialog *jobs_dialog = (PpJobsDialog*) user_data;
+
+  pp_jobs_dialog_hide (jobs_dialog);
+
+  jobs_dialog->user_callback (GTK_DIALOG (jobs_dialog->dialog),
+                              response_id,
+                              jobs_dialog->user_data);
+}
+
+static void
+update_alignment_padding (GtkWidget     *widget,
+                          GtkAllocation *allocation,
+                          gpointer       user_data)
+{
+  GtkAllocation  allocation2;
+  PpJobsDialog  *dialog = (PpJobsDialog*) user_data;
+  GtkWidget     *action_area;
+  gint           offset_left, offset_right;
+  guint          padding_left, padding_right,
+                 padding_top, padding_bottom;
+
+  action_area = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "dialog-action-area1");
+  gtk_widget_get_allocation (action_area, &allocation2);
+
+  offset_left = allocation2.x - allocation->x;
+  offset_right = (allocation->x + allocation->width) -
+                 (allocation2.x + allocation2.width);
+
+  gtk_alignment_get_padding  (GTK_ALIGNMENT (widget),
+                              &padding_top, &padding_bottom,
+                              &padding_left, &padding_right);
+  if (allocation->x >= 0 && allocation2.x >= 0)
+    {
+      if (offset_left > 0 && offset_left != padding_left)
+        gtk_alignment_set_padding (GTK_ALIGNMENT (widget),
+                                   padding_top, padding_bottom,
+                                   offset_left, padding_right);
+
+      gtk_alignment_get_padding  (GTK_ALIGNMENT (widget),
+                                  &padding_top, &padding_bottom,
+                                  &padding_left, &padding_right);
+      if (offset_right > 0 && offset_right != padding_right)
+        gtk_alignment_set_padding (GTK_ALIGNMENT (widget),
+                                   padding_top, padding_bottom,
+                                   padding_left, offset_right);
+    }
+}
+
+PpJobsDialog *
+pp_jobs_dialog_new (GtkWindow            *parent,
+                    UserResponseCallback  user_callback,
+                    gpointer              user_data,
+                    gchar                *printer_name)
+{
+  PpJobsDialog *dialog;
+  GtkWidget    *widget;
+  GError       *error = NULL;
+  gchar        *objects[] = { "jobs-dialog", NULL };
+  guint         builder_result;
+  gchar        *title;
+
+  dialog = g_new0 (PpJobsDialog, 1);
+
+  dialog->builder = gtk_builder_new ();
+  dialog->parent = GTK_WIDGET (parent);
+
+  builder_result = gtk_builder_add_objects_from_file (dialog->builder,
+                                                      DATADIR"/jobs-dialog.ui",
+                                                      objects, &error);
+
+  if (builder_result == 0)
+    {
+      g_warning ("Could not load ui: %s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  dialog->dialog = (GtkWidget *) gtk_builder_get_object (dialog->builder, "jobs-dialog");
+  dialog->user_callback = user_callback;
+  dialog->user_data = user_data;
+  dialog->printer_name = g_strdup (printer_name);
+  dialog->current_job_id = -1;
+  dialog->ref_count = 0;
+
+  /* connect signals */
+  g_signal_connect (dialog->dialog, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+  g_signal_connect (dialog->dialog, "response", G_CALLBACK (jobs_dialog_response_cb), dialog);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "content-alignment");
+  g_signal_connect (widget, "size-allocate", G_CALLBACK (update_alignment_padding), dialog);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-cancel-button");
+  g_signal_connect (widget, "clicked", G_CALLBACK (job_process_cb), dialog);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-hold-button");
+  g_signal_connect (widget, "clicked", G_CALLBACK (job_process_cb), dialog);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "job-release-button");
+  g_signal_connect (widget, "clicked", G_CALLBACK (job_process_cb), dialog);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (dialog->builder, "jobs-title");
+  title = g_strdup_printf (_("%s Active Jobs"), printer_name);
+  gtk_label_set_label (GTK_LABEL (widget), title);
+  g_free (title);
+
+  populate_jobs_list (dialog);
+
+  gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), GTK_WINDOW (parent));
+  gtk_window_present (GTK_WINDOW (dialog->dialog));
+  gtk_widget_show_all (GTK_WIDGET (dialog->dialog));
+
+  return dialog;
+}
+
+void
+pp_jobs_dialog_update (PpJobsDialog *dialog)
+{
+  update_jobs_list (dialog);
+}
+
+static gboolean
+pp_jobs_dialog_free_idle (gpointer user_data)
+{
+  PpJobsDialog *dialog = (PpJobsDialog*) user_data;
+
+  if (dialog->ref_count == 0)
+    {
+      gtk_widget_destroy (GTK_WIDGET (dialog->dialog));
+      dialog->dialog = NULL;
+
+      g_object_unref (dialog->builder);
+      dialog->builder = NULL;
+
+      if (dialog->num_jobs > 0)
+        cupsFreeJobs (dialog->num_jobs, dialog->jobs);
+
+      g_free (dialog->printer_name);
+
+      g_free (dialog);
+
+      return FALSE;
+    }
+  else
+    {
+      return TRUE;
+    }
+}
+
+void
+pp_jobs_dialog_free (PpJobsDialog *dialog)
+{
+  g_idle_add (pp_jobs_dialog_free_idle, dialog);
+}
+
+static void
+pp_jobs_dialog_hide (PpJobsDialog *dialog)
+{
+  gtk_widget_hide (GTK_WIDGET (dialog->dialog));
+}
diff --git a/panels/printers/pp-jobs-dialog.h b/panels/printers/pp-jobs-dialog.h
new file mode 100644
index 0000000..72ae66b
--- /dev/null
+++ b/panels/printers/pp-jobs-dialog.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2012  Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Marek Kasik <mkasik redhat com>
+ */
+
+#ifndef __PP_JOBS_DIALOG_H__
+#define __PP_JOBS_DIALOG_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _PpJobsDialog PpJobsDialog;
+
+typedef void (*UserResponseCallback) (GtkDialog *dialog, gint response_id, gpointer user_data);
+
+PpJobsDialog *pp_jobs_dialog_new    (GtkWindow            *parent,
+                                     UserResponseCallback  user_callback,
+                                     gpointer              user_data,
+                                     gchar                *printer_name);
+void          pp_jobs_dialog_update (PpJobsDialog         *dialog);
+void          pp_jobs_dialog_free   (PpJobsDialog         *dialog);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/printers/pp-utils.c b/panels/printers/pp-utils.c
index 599bd1a..b53c0bd 100644
--- a/panels/printers/pp-utils.c
+++ b/panels/printers/pp-utils.c
@@ -4551,3 +4551,268 @@ printer_add_option_async (const gchar   *printer_name,
                           printer_add_option_async_dbus_cb,
                           data);
 }
+
+typedef struct
+{
+  gchar        *printer_name;
+  gboolean      my_jobs;
+  gint          which_jobs;
+  cups_job_t   *jobs;
+  gint          num_of_jobs;
+  CGJCallback   callback;
+  gpointer      user_data;
+  GMainContext *context;
+} CGJData;
+
+static gboolean
+cups_get_jobs_idle_cb (gpointer user_data)
+{
+  CGJData *data = (CGJData *) user_data;
+
+  data->callback (data->jobs,
+                  data->num_of_jobs,
+                  data->user_data);
+
+  return FALSE;
+}
+
+static void
+cups_get_jobs_data_free (gpointer user_data)
+{
+  CGJData *data = (CGJData *) user_data;
+
+  if (data->context)
+    g_main_context_unref (data->context);
+  g_free (data->printer_name);
+  g_free (data);
+}
+
+static void
+cups_get_jobs_cb (gpointer user_data)
+{
+  CGJData *data = (CGJData *) user_data;
+  GSource *idle_source;
+
+  idle_source = g_idle_source_new ();
+  g_source_set_callback (idle_source,
+                         cups_get_jobs_idle_cb,
+                         data,
+                         cups_get_jobs_data_free);
+  g_source_attach (idle_source, data->context);
+  g_source_unref (idle_source);
+}
+
+static gpointer
+cups_get_jobs_func (gpointer user_data)
+{
+  CGJData *data = (CGJData *) user_data;
+
+  data->num_of_jobs = cupsGetJobs (&data->jobs,
+                                   data->printer_name,
+                                   data->my_jobs ? 1 : 0,
+                                   data->which_jobs);
+
+  cups_get_jobs_cb (data);
+
+  return NULL;
+}
+
+void
+cups_get_jobs_async (const gchar *printer_name,
+                     gboolean     my_jobs,
+                     gint         which_jobs,
+                     CGJCallback  callback,
+                     gpointer     user_data)
+{
+  CGJData *data;
+  GThread *thread;
+  GError  *error = NULL;
+
+  data = g_new0 (CGJData, 1);
+  data->printer_name = g_strdup (printer_name);
+  data->my_jobs = my_jobs;
+  data->which_jobs = which_jobs;
+  data->callback = callback;
+  data->user_data = user_data;
+  data->context = g_main_context_ref_thread_default ();
+
+  thread = g_thread_try_new ("cups-get-jobs",
+                             cups_get_jobs_func,
+                             data,
+                             &error);
+
+  if (!thread)
+    {
+      g_warning ("%s", error->message);
+      callback (NULL, 0, user_data);
+
+      g_error_free (error);
+      cups_get_jobs_data_free (data);
+    }
+  else
+    {
+      g_thread_unref (thread);
+    }
+}
+
+typedef struct
+{
+  GCancellable *cancellable;
+  JCPCallback   callback;
+  gpointer      user_data;
+} JCPData;
+
+static void
+job_cancel_purge_async_dbus_cb (GObject      *source_object,
+                                GAsyncResult *res,
+                                gpointer      user_data)
+{
+  GVariant *output;
+  JCPData  *data = (JCPData *) user_data;
+  GError   *error = NULL;
+
+  output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+                                          res,
+                                          &error);
+  g_object_unref (source_object);
+
+  if (output)
+    {
+      g_variant_unref (output);
+    }
+  else
+    {
+      if (!g_cancellable_is_cancelled (data->cancellable))
+        g_warning ("%s", error->message);
+      g_error_free (error);
+    }
+
+  data->callback (data->user_data);
+
+  if (data->cancellable)
+    g_object_unref (data->cancellable);
+  g_free (data);
+}
+
+void
+job_cancel_purge_async (gint          job_id,
+                        gboolean      job_purge,
+                        GCancellable *cancellable,
+                        JCPCallback   callback,
+                        gpointer      user_data)
+{
+  GDBusConnection *bus;
+  JCPData         *data;
+  GError          *error = NULL;
+
+  bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+  if (!bus)
+    {
+      g_warning ("Failed to get session bus: %s", error->message);
+      g_error_free (error);
+      callback (user_data);
+      return;
+    }
+
+  data = g_new0 (JCPData, 1);
+  if (cancellable)
+    data->cancellable = g_object_ref (cancellable);
+  data->callback = callback;
+  data->user_data = user_data;
+
+  g_dbus_connection_call (bus,
+                          MECHANISM_BUS,
+                          "/",
+                          MECHANISM_BUS,
+                          "JobCancelPurge",
+                          g_variant_new ("(ib)",
+                                         job_id,
+                                         job_purge),
+                          G_VARIANT_TYPE ("(s)"),
+                          G_DBUS_CALL_FLAGS_NONE,
+                          -1,
+                          NULL,
+                          job_cancel_purge_async_dbus_cb,
+                          data);
+}
+
+typedef struct
+{
+  GCancellable *cancellable;
+  JSHUCallback  callback;
+  gpointer      user_data;
+} JSHUData;
+
+static void
+job_set_hold_until_async_dbus_cb (GObject      *source_object,
+                                  GAsyncResult *res,
+                                  gpointer      user_data)
+{
+  GVariant *output;
+  JSHUData *data = (JSHUData *) user_data;
+  GError   *error = NULL;
+
+  output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+                                          res,
+                                          &error);
+  g_object_unref (source_object);
+
+  if (output)
+    {
+      g_variant_unref (output);
+    }
+  else
+    {
+      if (!g_cancellable_is_cancelled (data->cancellable))
+        g_warning ("%s", error->message);
+      g_error_free (error);
+    }
+
+  data->callback (data->user_data);
+
+  if (data->cancellable)
+    g_object_unref (data->cancellable);
+  g_free (data);
+}
+
+void
+job_set_hold_until_async (gint          job_id,
+                          const gchar  *job_hold_until,
+                          GCancellable *cancellable,
+                          JSHUCallback  callback,
+                          gpointer      user_data)
+{
+  GDBusConnection *bus;
+  JSHUData        *data;
+  GError          *error = NULL;
+
+  bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+  if (!bus)
+    {
+      g_warning ("Failed to get session bus: %s", error->message);
+      g_error_free (error);
+      callback (user_data);
+      return;
+    }
+
+  data = g_new0 (JSHUData, 1);
+  if (cancellable)
+    data->cancellable = g_object_ref (cancellable);
+  data->callback = callback;
+  data->user_data = user_data;
+
+  g_dbus_connection_call (bus,
+                          MECHANISM_BUS,
+                          "/",
+                          MECHANISM_BUS,
+                          "JobSetHoldUntil",
+                          g_variant_new ("(is)",
+                                         job_id,
+                                         job_hold_until),
+                          G_VARIANT_TYPE ("(s)"),
+                          G_DBUS_CALL_FLAGS_NONE,
+                          -1,
+                          NULL,
+                          job_set_hold_until_async_dbus_cb,
+                          data);
+}
diff --git a/panels/printers/pp-utils.h b/panels/printers/pp-utils.h
index 156b961..e2bc75dc 100644
--- a/panels/printers/pp-utils.h
+++ b/panels/printers/pp-utils.h
@@ -232,6 +232,32 @@ void        printer_add_option_async (const gchar   *printer_name,
                                       PAOCallback    callback,
                                       gpointer       user_data);
 
+typedef void (*CGJCallback) (cups_job_t *jobs,
+                             gint        num_of_jobs,
+                             gpointer    user_data);
+
+void        cups_get_jobs_async (const gchar *printer_name,
+                                 gboolean     my_jobs,
+                                 gint         which_jobs,
+                                 CGJCallback  callback,
+                                 gpointer     user_data);
+
+typedef void (*JCPCallback) (gpointer user_data);
+
+void job_cancel_purge_async (gint          job_id,
+                             gboolean      job_purge,
+                             GCancellable *cancellable,
+                             JCPCallback   callback,
+                             gpointer      user_data);
+
+typedef void (*JSHUCallback) (gpointer user_data);
+
+void job_set_hold_until_async (gint          job_id,
+                               const gchar  *job_hold_until,
+                               GCancellable *cancellable,
+                               JSHUCallback  callback,
+                               gpointer      user_data);
+
 G_END_DECLS
 
 #endif /* __PP_UTILS_H */
diff --git a/panels/printers/printers.ui b/panels/printers/printers.ui
index 75b1483..ebedf01 100644
--- a/panels/printers/printers.ui
+++ b/panels/printers/printers.ui
@@ -237,7 +237,7 @@
                     </child>
                     <child>
                       <object class="GtkButton" id="printer-jobs-button">
-                        <property name="label" translatable="yes" comments="Tanslators: Switch to tab containing printer's jobs">_Show</property>
+                        <property name="label" translatable="yes" comments="Tanslators: Opens a dialog containing printer's jobs">_Show</property>
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
                         <property name="receives_default">True</property>
@@ -511,158 +511,6 @@
               </packing>
             </child>
             <child>
-              <object class="GtkVBox" id="vbox2">
-                <property name="visible">True</property>
-                <property name="orientation">vertical</property>
-                <property name="spacing">10</property>
-                <child>
-                  <object class="GtkTable" id="table3">
-                    <property name="visible">True</property>
-                    <property name="n_columns">3</property>
-                    <child>
-                      <object class="GtkButton" id="back-button-1">
-                        <property name="label" translatable="yes" comments="Translators: Switch back to printer's info tab">_Back</property>
-                        <property name="use_underline">True</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="receives_default">True</property>
-                        <property name="halign">GTK_ALIGN_START</property>
-                        <property name="valign">GTK_ALIGN_CENTER</property>
-                      </object>
-                      <packing>
-                        <property name="x_options">GTK_FILL</property>
-                        <property name="y_options">GTK_FILL</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label1">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes" comments="Translators: This tab contains list of active print jobs of the selected printer">Active Print Jobs</property>
-                        <property name="halign">GTK_ALIGN_CENTER</property>
-                        <property name="valign">GTK_ALIGN_CENTER</property>
-                        <attributes>
-                          <attribute name="weight" value="bold"/>
-                        </attributes>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="y_options">GTK_FILL</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="back-spacer-label-1">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">2</property>
-                        <property name="x_options">GTK_FILL</property>
-                        <property name="y_options">GTK_FILL</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">False</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkVBox" id="vbox3">
-                    <property name="visible">True</property>
-                    <property name="orientation">vertical</property>
-                    <child>
-                      <object class="GtkScrolledWindow" id="queue-scrolledwindow">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="hscrollbar_policy">automatic</property>
-                        <property name="vscrollbar_policy">automatic</property>
-                        <property name="shadow_type">in</property>
-                        <child>
-                          <object class="GtkTreeView" id="job-treeview">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                          </object>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkToolbar" id="queue-toolbar">
-                        <property name="visible">True</property>
-                        <property name="icon_size">1</property>
-                        <property name="icon_size_set">True</property>
-                        <style>
-                          <class name="inline-toolbar"/>
-                        </style>
-                        <child>
-                          <object class="GtkToolButton" id="job-release-button">
-                            <property name="visible">True</property>
-                            <property name="label">resume-toolbutton</property>
-                            <property name="use_underline">True</property>
-                            <property name="icon_name">media-playback-start-symbolic</property>
-                            <property name="label" translatable="yes">Resume Printing</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="homogeneous">True</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkToolButton" id="job-hold-button">
-                            <property name="visible">True</property>
-                            <property name="label">pause-toolbutton</property>
-                            <property name="use_underline">True</property>
-                            <property name="icon_name">media-playback-pause-symbolic</property>
-                            <property name="label" translatable="yes">Pause Printing</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="homogeneous">True</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkToolButton" id="job-cancel-button">
-                            <property name="visible">True</property>
-                            <property name="label">stop-toolbutton</property>
-                            <property name="use_underline">True</property>
-                            <property name="icon_name">media-playback-stop-symbolic</property>
-                            <property name="label" translatable="yes">Cancel Print Job</property>
-                          </object>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="homogeneous">True</property>
-                          </packing>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child type="tab">
-              <object class="GtkLabel" id="label4">
-                <property name="visible">True</property>
-                <property name="label">Jobs</property>
-              </object>
-              <packing>
-                <property name="position">1</property>
-                <property name="tab_fill">False</property>
-              </packing>
-            </child>
-            <child>
               <object class="GtkVBox" id="vbox5">
                 <property name="visible">True</property>
                 <property name="orientation">vertical</property>



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