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
This commit is contained in:
Felipe Borges 2015-09-08 16:55:38 +02:00 committed by Felipe Borges
parent 8ec6506a04
commit 8baaa81a39
7 changed files with 513 additions and 583 deletions

View file

@ -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 \

View file

@ -3,144 +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="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>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<property name="show_close_button">True</property>
<child>
<object class="GtkBox" id="box2">
<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">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>
</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="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>
<property name="position">1</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>
</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>

251
panels/printers/pp-job.c Normal file
View file

@ -0,0 +1,251 @@
/* -*- 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;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
NULL);
g_object_unref (source_object);
if (output != NULL)
{
g_variant_unref (output);
}
}
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;
output = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
res,
NULL);
g_object_unref (source_object);
if (output)
{
g_variant_unref (output);
}
}
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);
}

47
panels/printers/pp-job.h Normal file
View file

@ -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

View file

@ -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,162 +49,158 @@ 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
job_pause_cb (GtkButton *button,
PpJob *job)
{
gint job_state;
g_object_get (job, "state", &job_state, NULL);
pp_job_set_hold_until_async (job, job_state == IPP_JOB_HELD ? "no-hold" : "indefinite");
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 GtkWidget *
create_listbox_row (gpointer item,
gpointer user_data)
{
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)
{
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
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;
PpJobsDialog *dialog = user_data;
GtkWidget *clear_all_button;
GtkStack *stack;
guint i;
treeview = (GtkTreeView*)
gtk_builder_get_object (dialog->builder, "job-treeview");
g_list_store_remove_all (dialog->store);
if (dialog->num_jobs > 0)
cupsFreeJobs (dialog->num_jobs, dialog->jobs);
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"));
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)
if (num_of_jobs > 0)
{
for (i = 0; i < dialog->num_jobs; i++)
{
select_index = i;
if (dialog->jobs[i].id >= dialog->current_job_id)
break;
}
gtk_widget_set_sensitive (clear_all_button, TRUE);
gtk_stack_set_visible_child_name (stack, "list-jobs-page");
}
else
{
gtk_widget_set_sensitive (clear_all_button, FALSE);
gtk_stack_set_visible_child_name (stack, "no-jobs-page");
}
for (i = 0; i < dialog->num_jobs; i++)
for (i = 0; i < num_of_jobs; i++)
{
GDesktopClockFormat value;
GDateTime *time;
struct tm *ts;
gchar *time_string;
gchar *state = NULL;
PpJob *job;
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);
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);
}
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)
if (dialog->printer_name != NULL)
{
dialog->ref_count++;
cups_get_jobs_async (dialog->printer_name,
@ -212,162 +211,6 @@ update_jobs_list (PpJobsDialog *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,
@ -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);

View file

@ -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)
{

View file

@ -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);