[gnome-control-center/wip/feborges/new-printers-panel: 127/127] printers: redesign the Printer Jobs Dialog
- From: Felipe Borges <felipeborges src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center/wip/feborges/new-printers-panel: 127/127] printers: redesign the Printer Jobs Dialog
- Date: Fri, 15 Jan 2016 10:40:48 +0000 (UTC)
commit 5d7bec85bfdd714b5fde5eb42f8699e5e4e6eccb
Author: Felipe Borges <feborges redhat com>
Date: Tue Sep 8 16:55:38 2015 +0200
printers: redesign the Printer Jobs Dialog
Update the Printer Jobs Dialog to match the current designs at
https://wiki.gnome.org/Design/SystemSettings/Printers
https://bugzilla.gnome.org/show_bug.cgi?id=755626
panels/printers/Makefile.am | 2 +
panels/printers/jobs-dialog.ui | 145 +++++-------
panels/printers/pp-job.c | 261 +++++++++++++++++++++
panels/printers/pp-job.h | 47 ++++
panels/printers/pp-jobs-dialog.c | 468 +++++++++++++-------------------------
panels/printers/pp-utils.c | 162 -------------
panels/printers/pp-utils.h | 16 --
7 files changed, 521 insertions(+), 580 deletions(-)
---
diff --git a/panels/printers/Makefile.am b/panels/printers/Makefile.am
index c386486..7fb2c17 100644
--- a/panels/printers/Makefile.am
+++ b/panels/printers/Makefile.am
@@ -37,6 +37,8 @@ libprinters_la_SOURCES = \
pp-ppd-selection-dialog.h \
pp-options-dialog.c \
pp-options-dialog.h \
+ pp-job.c \
+ pp-job.h \
pp-jobs-dialog.c \
pp-jobs-dialog.h \
pp-authentication-dialog.c \
diff --git a/panels/printers/jobs-dialog.ui b/panels/printers/jobs-dialog.ui
index 6ac05a3..881ecc7 100644
--- a/panels/printers/jobs-dialog.ui
+++ b/panels/printers/jobs-dialog.ui
@@ -3,143 +3,110 @@
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkDialog" id="jobs-dialog">
- <property name="width_request">500</property>
- <property name="height_request">350</property>
+ <property name="width_request">600</property>
+ <property name="height_request">500</property>
<property name="can_focus">False</property>
- <property name="border_width">5</property>
- <property name="title" translatable="yes" comments="Translators: This dialog contains list of active
print jobs of the selected printer">Active Jobs</property>
+ <property name="border_width">0</property>
<property name="resizable">False</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="GtkBox" id="main-vbox">
+ <property name="use-header-bar">1</property>
+ <child internal-child="headerbar">
+ <object class="GtkHeaderBar" id="dialog-header-bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">10</property>
- <child internal-child="action_area">
- <object class="GtkButtonBox" id="dialog-action-area1">
+ <property name="show_close_button">True</property>
+ <child>
+ <object class="GtkButton" id="jobs-clear-all-button">
+ <property name="label" translatable="yes" comments="Translators: this action removes (purges)
all the listed jobs from the list.">Clear All</property>
<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="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="destructive-action"/>
+ </style>
</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>
+ </object>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="border_width">0</property>
<child>
- <object class="GtkBox" id="box2">
+ <object class="GtkStack" id="stack">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="orientation">vertical</property>
<child>
- <object class="GtkScrolledWindow" id="queue-scrolledwindow">
+ <object class="GtkScrolledWindow" id="scrolledwindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="shadow_type">in</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="shadow_type">none</property>
<child>
- <object class="GtkTreeView" id="job-treeview">
+ <object class="GtkListBox" id="jobs-listbox">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection" id="treeview-selection"/>
+ <property name="can-focus">True</property>
+ <property name="halign">fill</property>
+ <property name="valign">fill</property>
+ <property name="selection-mode">none</property>
+ <child>
+ <placeholder/>
</child>
</object>
</child>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
+ <property name="name">list-jobs-page</property>
</packing>
</child>
<child>
- <object class="GtkToolbar" id="queue-toolbar">
+ <object class="GtkBox" id="no-jobs-dialog">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="icon_size">1</property>
+ <property name="spacing">10</property>
+ <property name="orientation">vertical</property>
+ <property name="valign">center</property>
<child>
- <object class="GtkToolButton" id="job-release-button">
+ <object class="GtkImage" id="no-printer-image">
<property name="visible">True</property>
- <property name="sensitive">False</property>
<property name="can_focus">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>
+ <property name="valign">start</property>
+ <property name="pixel_size">64</property>
+ <property name="icon_name">printer-symbolic</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
</object>
<packing>
<property name="expand">False</property>
- <property name="homogeneous">True</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkToolButton" id="job-hold-button">
+ <object class="GtkLabel" id="no-printer-label">
<property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can_focus">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>
+ <property name="label" translatable="yes" comments="Translators: this label describes
the dialog empty state, with no jobs listed.">No Active Printer Jobs</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
</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="sensitive">False</property>
- <property name="can_focus">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>
+ <property name="position">1</property>
</packing>
</child>
- <style>
- <class name="inline-toolbar"/>
- </style>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
+ <property name="name">no-jobs-page</property>
</packing>
</child>
</object>
- <packing>
- <property name="expand">False</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>
</interface>
diff --git a/panels/printers/pp-job.c b/panels/printers/pp-job.c
new file mode 100644
index 0000000..8b7084a
--- /dev/null
+++ b/panels/printers/pp-job.c
@@ -0,0 +1,261 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2015 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Felipe Borges <feborges redhat com>
+ */
+
+#include "pp-job.h"
+
+typedef struct
+{
+ GObject parent;
+
+ gint id;
+ gchar *title;
+ gint state;
+} PpJobPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (PpJob, pp_job, G_TYPE_OBJECT)
+
+enum
+{
+ PROP_0,
+ PROP_ID,
+ PROP_TITLE,
+ PROP_STATE,
+ LAST_PROPERTY
+};
+
+static GParamSpec *properties[LAST_PROPERTY];
+
+static void
+pp_job_cancel_purge_async_dbus_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GVariant *output;
+ GError *error = NULL;
+
+ output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
+ res,
+ &error);
+ g_object_unref (source_object);
+
+ if (output != NULL)
+ {
+ g_variant_unref (output);
+ }
+ else
+ {
+ g_error_free (error);
+ }
+}
+
+void
+pp_job_cancel_purge_async (PpJob *job,
+ gboolean job_purge)
+{
+ GDBusConnection *bus;
+ GError *error = NULL;
+ gint *job_id;
+
+ g_object_get (job, "id", &job_id, 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);
+ return;
+ }
+
+ 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,
+ pp_job_cancel_purge_async_dbus_cb,
+ NULL);
+}
+
+static void
+pp_job_set_hold_until_async_dbus_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GVariant *output;
+ 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
+ {
+ g_error_free (error);
+ }
+}
+
+void
+pp_job_set_hold_until_async (PpJob *job,
+ const gchar *job_hold_until)
+{
+ GDBusConnection *bus;
+ GError *error = NULL;
+ gint *job_id;
+
+ g_object_get (job, "id", &job_id, 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);
+ return;
+ }
+
+ 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,
+ pp_job_set_hold_until_async_dbus_cb,
+ NULL);
+}
+
+static void
+pp_job_init (PpJob *obj)
+{
+}
+
+static void
+pp_job_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PpJobPrivate *priv;
+
+ priv = pp_job_get_instance_private (PP_JOB (object));
+
+ switch (property_id)
+ {
+ case PROP_ID:
+ g_value_set_int (value, priv->id);
+ break;
+ case PROP_TITLE:
+ g_value_set_string (value, priv->title);
+ break;
+ case PROP_STATE:
+ g_value_set_int (value, priv->state);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+pp_job_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ PpJobPrivate *priv;
+
+ priv = pp_job_get_instance_private (PP_JOB (object));
+
+ switch (property_id)
+ {
+ case PROP_ID:
+ priv->id = g_value_get_int (value);
+ break;
+ case PROP_TITLE:
+ g_free (priv->title);
+ priv->title = g_value_dup_string (value);
+ break;
+ case PROP_STATE:
+ priv->state = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+pp_job_finalize (GObject *object)
+{
+ PpJobPrivate *priv;
+
+ priv = pp_job_get_instance_private (PP_JOB (object));
+
+ g_free (priv->title);
+
+ G_OBJECT_CLASS (pp_job_parent_class)->finalize (object);
+}
+
+static void
+pp_job_class_init (PpJobClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->get_property = pp_job_get_property;
+ object_class->set_property = pp_job_set_property;
+ object_class->finalize = pp_job_finalize;
+
+ properties[PROP_ID] = g_param_spec_int ("id",
+ "Id",
+ "Job id",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE);
+ properties[PROP_TITLE] = g_param_spec_string ("title",
+ "Title",
+ "Title of this print job",
+ NULL,
+ G_PARAM_READWRITE);
+ properties[PROP_STATE] = g_param_spec_int ("state",
+ "State",
+ "State of this print job (Paused, Completed, Cancelled,...)",
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (object_class, LAST_PROPERTY, properties);
+}
diff --git a/panels/printers/pp-job.h b/panels/printers/pp-job.h
new file mode 100644
index 0000000..35e16e9
--- /dev/null
+++ b/panels/printers/pp-job.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2015 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Felipe Borges <feborges redhat com>
+ */
+
+#ifndef __PP_JOB_H__
+#define __PP_JOB_H__
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+
+#include "pp-utils.h"
+
+G_BEGIN_DECLS
+
+#define PP_TYPE_JOB (pp_job_get_type ())
+G_DECLARE_FINAL_TYPE (PpJob, pp_job, PP, JOB, GObject)
+
+struct _PpJob
+{
+ GObject parent_instance;
+};
+
+void pp_job_set_hold_until_async (PpJob *job,
+ const gchar *job_hold_until);
+
+void pp_job_cancel_purge_async (PpJob *job,
+ gboolean job_purge);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/printers/pp-jobs-dialog.c b/panels/printers/pp-jobs-dialog.c
index 2d8682e..1a1f31b 100644
--- a/panels/printers/pp-jobs-dialog.c
+++ b/panels/printers/pp-jobs-dialog.c
@@ -31,8 +31,11 @@
#include <cups/cups.h>
+#include "shell/list-box-helper.h"
#include "pp-jobs-dialog.h"
#include "pp-utils.h"
+#include "pp-job.h"
+#include "pp-cups.h"
#define EMPTY_TEXT "\xe2\x80\x94"
@@ -46,326 +49,166 @@ struct _PpJobsDialog {
GtkWidget *parent;
GtkWidget *dialog;
+ GListStore *store;
+ GtkListBox *listbox;
UserResponseCallback user_callback;
gpointer user_data;
gchar *printer_name;
- cups_job_t *jobs;
- gint num_jobs;
- gint current_job_id;
-
gint ref_count;
};
-enum
+static void
+job_stop_cb (GtkButton *button,
+ PpJob *job)
{
- JOB_ID_COLUMN,
- JOB_TITLE_COLUMN,
- JOB_STATE_COLUMN,
- JOB_CREATION_TIME_COLUMN,
- JOB_N_COLUMNS
-};
+ pp_job_cancel_purge_async (job, FALSE);
+}
static void
-update_jobs_list_cb (cups_job_t *jobs,
- gint num_of_jobs,
- gpointer user_data)
+job_pause_cb (GtkButton *button,
+ PpJob *job)
{
- 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 + 1900,
- ts->tm_mon + 1,
- 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);
- }
+ gint job_state;
- gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
+ g_object_get (job, "state", &job_state, NULL);
- if (select_iter_set &&
- (selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview))))
- {
- gtk_tree_selection_select_iter (selection, &select_iter);
- }
+ pp_job_set_hold_until_async (job, job_state == IPP_JOB_HELD ? "no-hold" : "indefinite");
- g_object_unref (store);
- dialog->ref_count--;
+ gtk_button_set_image (button,
+ gtk_image_new_from_icon_name (job_state == IPP_JOB_HELD ?
+ "media-playback-pause-symbolic" :
"media-playback-start-symbolic",
+ GTK_ICON_SIZE_SMALL_TOOLBAR));
}
-static void
-update_jobs_list (PpJobsDialog *dialog)
+static GtkWidget *
+create_listbox_row (gpointer item,
+ gpointer user_data)
{
- if (dialog->printer_name)
+ PpJob *job = (PpJob *)item;
+ GtkWidget *box;
+ GtkWidget *widget;
+ gchar *title;
+ gchar *state_string;
+ gint job_state;
+
+ g_object_get (job, "title", &title, "state", &job_state, NULL);
+
+ switch (job_state)
{
- dialog->ref_count++;
- cups_get_jobs_async (dialog->printer_name,
- TRUE,
- CUPS_WHICHJOBS_ACTIVE,
- update_jobs_list_cb,
- dialog);
+ case IPP_JOB_PENDING:
+ /* Translators: Job's state (job is waiting to be printed) */
+ state_string = g_strdup (C_("print job", "Pending"));
+ break;
+ case IPP_JOB_HELD:
+ /* Translators: Job's state (job is held for printing) */
+ state_string = g_strdup (C_("print job", "Paused"));
+ break;
+ case IPP_JOB_PROCESSING:
+ /* Translators: Job's state (job is currently printing) */
+ state_string = g_strdup (C_("print job", "Processing"));
+ break;
+ case IPP_JOB_STOPPED:
+ /* Translators: Job's state (job has been stopped) */
+ state_string = g_strdup (C_("print job", "Stopped"));
+ break;
+ case IPP_JOB_CANCELED:
+ /* Translators: Job's state (job has been canceled) */
+ state_string = g_strdup (C_("print job", "Canceled"));
+ break;
+ case IPP_JOB_ABORTED:
+ /* Translators: Job's state (job has aborted due to error) */
+ state_string = g_strdup (C_("print job", "Aborted"));
+ break;
+ case IPP_JOB_COMPLETED:
+ /* Translators: Job's state (job has completed successfully) */
+ state_string = g_strdup (C_("print job", "Completed"));
+ break;
}
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ g_object_set (box, "margin", 6, NULL);
+ gtk_container_set_border_width (GTK_CONTAINER (box), 2);
+
+ widget = gtk_label_new (title);
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 10);
+
+ widget = gtk_label_new (state_string);
+ gtk_widget_set_halign (widget, GTK_ALIGN_END);
+ gtk_widget_set_margin_end (widget, 64);
+ gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 10);
+
+ widget = gtk_button_new_from_icon_name (job_state == IPP_JOB_HELD ? "media-playback-start-symbolic" :
"media-playback-pause-symbolic",
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ g_signal_connect (widget, "clicked", G_CALLBACK (job_pause_cb), item);
+ gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 4);
+
+ widget = gtk_button_new_from_icon_name ("edit-delete-symbolic",
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ g_signal_connect (widget, "clicked", G_CALLBACK (job_stop_cb), item);
+ gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 4);
+
+ gtk_widget_show_all (box);
+
+ return box;
}
static void
-job_selection_changed_cb (GtkTreeSelection *selection,
- gpointer user_data)
+update_jobs_list_cb (cups_job_t *jobs,
+ gint num_of_jobs,
+ 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))
+ PpJobsDialog *dialog = user_data;
+ GtkWidget *clear_all_button;
+ GtkStack *stack;
+ guint i;
+
+ g_list_store_remove_all (dialog->store);
+
+ stack = GTK_STACK (gtk_builder_get_object (GTK_BUILDER (dialog->builder), "stack"));
+ clear_all_button = GTK_WIDGET (gtk_builder_get_object (GTK_BUILDER (dialog->builder),
"jobs-clear-all-button"));
+
+ if (num_of_jobs > 0)
{
- gtk_tree_model_get (model, &iter,
- JOB_ID_COLUMN, &id,
- -1);
+ gtk_widget_set_sensitive (clear_all_button, TRUE);
+ gtk_stack_set_visible_child_name (stack, "list-jobs-page");
}
else
{
- id = -1;
+ gtk_widget_set_sensitive (clear_all_button, FALSE);
+ gtk_stack_set_visible_child_name (stack, "no-jobs-page");
}
- dialog->current_job_id = id;
-
- if (dialog->current_job_id >= 0 &&
- dialog->jobs != NULL)
+ for (i = 0; i < num_of_jobs; i++)
{
- 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;
- }
- }
+ PpJob *job;
+
+ job = g_object_new (pp_job_get_type (),
+ "id", jobs[i].id,
+ "title", jobs[i].title,
+ "state", jobs[i].state,
+ NULL);
+ g_list_store_append (dialog->store, job);
}
- 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)
-{
+ dialog->ref_count--;
}
static void
-job_process_cb (GtkButton *button,
- gpointer user_data)
+update_jobs_list (PpJobsDialog *dialog)
{
- PpJobsDialog *dialog = (PpJobsDialog *) user_data;
- GtkWidget *widget;
-
- if (dialog->current_job_id >= 0)
+ if (dialog->printer_name != NULL)
{
- 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);
+ dialog->ref_count++;
+ cups_get_jobs_async (dialog->printer_name,
+ TRUE,
+ CUPS_WHICHJOBS_ACTIVE,
+ update_jobs_list_cb,
+ dialog);
+ }
}
static void
@@ -382,15 +225,32 @@ jobs_dialog_response_cb (GtkDialog *dialog,
jobs_dialog->user_data);
}
+static void
+on_clear_all_button_clicked (GtkButton *button,
+ gpointer user_data)
+{
+ PpJobsDialog *dialog = user_data;
+ guint num_items;
+ guint i;
+
+ num_items = g_list_model_get_n_items (G_LIST_MODEL (dialog->store));
+
+ for (i = 0; i < num_items; i++)
+ {
+ PpJob *job = PP_JOB (g_list_model_get_item (G_LIST_MODEL (dialog->store), i));
+
+ pp_job_cancel_purge_async (job, FALSE);
+ }
+}
+
PpJobsDialog *
pp_jobs_dialog_new (GtkWindow *parent,
UserResponseCallback user_callback,
gpointer user_data,
gchar *printer_name)
{
- GtkStyleContext *context;
PpJobsDialog *dialog;
- GtkWidget *widget;
+ GtkButton *clear_all_button;
GError *error = NULL;
gchar *objects[] = { "jobs-dialog", NULL };
guint builder_result;
@@ -416,43 +276,28 @@ pp_jobs_dialog_new (GtkWindow *parent,
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, "job-cancel-button");
- g_signal_connect (widget, "clicked", G_CALLBACK (job_process_cb), dialog);
+ clear_all_button = GTK_BUTTON (gtk_builder_get_object (dialog->builder, "jobs-clear-all-button"));
+ g_signal_connect (clear_all_button, "clicked", G_CALLBACK (on_clear_all_button_clicked), 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);
-
-
- /* Set junctions */
- widget = (GtkWidget*)
- gtk_builder_get_object (dialog->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 (dialog->builder, "queue-toolbar");
- context = gtk_widget_get_style_context (widget);
- gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
-
-
- title = g_strdup_printf (_("%s Active Jobs"), printer_name);
+ /* Translators: This is the printer name for which we are showing the active jobs */
+ title = g_strdup_printf (C_("Printer jobs dialog title", "%s - Active Jobs"), printer_name);
gtk_window_set_title (GTK_WINDOW (dialog->dialog), title);
g_free (title);
- populate_jobs_list (dialog);
+ dialog->listbox = GTK_LIST_BOX (gtk_builder_get_object (dialog->builder, "jobs-listbox"));
+ gtk_list_box_set_header_func (dialog->listbox,
+ cc_list_box_update_header_func, NULL, NULL);
+ dialog->store = g_list_store_new (pp_job_get_type ());
+ gtk_list_box_bind_model (dialog->listbox, G_LIST_MODEL (dialog->store),
+ create_listbox_row, NULL, NULL);
+
+ update_jobs_list (dialog);
gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), GTK_WINDOW (parent));
gtk_window_present (GTK_WINDOW (dialog->dialog));
@@ -480,9 +325,6 @@ pp_jobs_dialog_free_idle (gpointer user_data)
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);
diff --git a/panels/printers/pp-utils.c b/panels/printers/pp-utils.c
index 899bcf3..151d337 100644
--- a/panels/printers/pp-utils.c
+++ b/panels/printers/pp-utils.c
@@ -3824,168 +3824,6 @@ cups_get_jobs_async (const gchar *printer_name,
}
}
-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);
-}
-
gchar *
guess_device_hostname (PpPrintDevice *device)
{
diff --git a/panels/printers/pp-utils.h b/panels/printers/pp-utils.h
index 9b39b6d..9783823 100644
--- a/panels/printers/pp-utils.h
+++ b/panels/printers/pp-utils.h
@@ -259,22 +259,6 @@ void cups_get_jobs_async (const gchar *printer_name,
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);
-
void pp_devices_list_free (PpDevicesList *result);
const gchar *get_page_size_from_locale (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]