/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2004 Red Hat, Inc. * Written by Matthias Clasen <mclasen@redhat.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include <gtk/gtk.h> #include "ec-job-list.h" #include "ec-job-model.h" #include "ec-tray-icon.h" #include "rb-debug.h" #include <libgnome/gnome-i18n.h> #include <glib/gi18n.h> #include <libgnomeui/libgnomeui.h> G_DEFINE_TYPE(ECJobList, ec_job_list, GNOME_TYPE_APP) static void ec_job_list_dispose (GObject *object); static void ec_job_list_finalize (GObject *object); static GObject * ec_job_list_constructor (GType type, guint n_props, GObjectConstructParam *construct_props); static void ec_job_list_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void ec_job_list_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static GtkWidget * create_jobs_menubar (GtkAccelGroup *accel_group, GtkTooltips *tooltips, ECJobList *job_list); static void tree_selection_changed_cb (GtkTreeSelection *selection, ECJobList *job_list); static gboolean list_button_press_event_cb (GtkWidget *widget, GdkEvent *event, ECJobList *job_list); static gint sort_by_status (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); static void set_cell_name (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data); static gint sort_by_name (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); static void set_cell_printer (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data); static gint sort_by_printer (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); static gint sort_by_size (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); static void set_cell_size (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data); static void set_cell_time (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data); static gint sort_by_time (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); static void set_cell_status (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data); static gboolean jobs_delete_event_cb (GtkWidget *widget, GdkEvent *event, ECJobList *job_list); static void set_menu_sensitivities (ECJobList *job_list); enum { PROP_NONE, PROP_MODEL }; 00108 struct ECJobListPrivate { gboolean disposed; GtkWidget *statusbar; GtkWidget *tree_view; GtkWidget *cancel; GtkWidget *pause; GtkWidget *resume; GtkWidget *clear; ECJobModel *job_model; GtkTreeModel *model; }; 00123 typedef struct { GnomeCupsJob *job; gchar *printer; gint local_jobid; } JobData; static void ec_job_list_class_init (ECJobListClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = ec_job_list_dispose; object_class->finalize = ec_job_list_finalize; object_class->constructor = ec_job_list_constructor; object_class->set_property = ec_job_list_set_property; object_class->get_property = ec_job_list_get_property; g_object_class_install_property (object_class, PROP_MODEL, g_param_spec_object ("model", "ECJobModel", "Model to use", EC_TYPE_JOB_MODEL, G_PARAM_CONSTRUCT | G_PARAM_WRITABLE)); } void ec_job_list_init (ECJobList *list) { list->priv = g_new0 (struct ECJobListPrivate, 1); } static void ec_job_list_dispose (GObject *object) { ECJobList *list = EC_JOB_LIST (object); if (list->priv->disposed) return; list->priv->disposed = TRUE; } static void ec_job_list_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ECJobList *list; list = EC_JOB_LIST (object); switch (prop_id) { case PROP_MODEL: list->priv->job_model = EC_JOB_MODEL (g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void ec_job_list_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ECJobList *list; list = EC_JOB_LIST (object); switch (prop_id) { case PROP_MODEL: g_value_set_object (value, list->priv->job_model); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static GObject * ec_job_list_constructor (GType type, guint n_props, GObjectConstructParam *construct_props) { GObject *obj; ECJobList *list; ECJobListClass *klass; GObjectClass *parent_class; GtkWidget *menubar, *scrolledwin; GtkAccelGroup *accel_group; GtkTooltips *tooltips; GtkTreeViewColumn *col; GtkCellRenderer *rend; GtkTreeSelection *selection; AtkObject *accessible; klass = EC_JOB_LIST_CLASS (g_type_class_peek (EC_TYPE_JOB_LIST)); parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); obj = parent_class->constructor (type, n_props, construct_props); list = EC_JOB_LIST (obj); gnome_app_construct (GNOME_APP (list), "eggcups", "Print Notifier"); list->priv->model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list->priv->job_model)); accel_group = gtk_accel_group_new (); gtk_window_add_accel_group (GTK_WINDOW (list), accel_group); tooltips = gtk_tooltips_new (); menubar = create_jobs_menubar (accel_group, tooltips, list); gnome_app_set_menus (GNOME_APP (list), GTK_MENU_BAR (menubar)); /* List view - Job Name, Owner, Number, Size, Submitted Date/Time. */ scrolledwin = gtk_scrolled_window_new (NULL, NULL); gtk_widget_show (scrolledwin); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwin), GTK_SHADOW_IN); gnome_app_set_contents (GNOME_APP (list), scrolledwin); list->priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list->priv->model)); g_object_unref (G_OBJECT (list->priv->model)); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list->priv->tree_view)); gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection), GTK_SELECTION_MULTIPLE); g_signal_connect (selection, "changed", G_CALLBACK (tree_selection_changed_cb), list); g_signal_connect (list->priv->tree_view, "button_press_event", G_CALLBACK (list_button_press_event_cb), list); accessible = gtk_widget_get_accessible (GTK_WIDGET (list->priv->tree_view)); if (GTK_IS_ACCESSIBLE (accessible)) { atk_object_set_name (accessible, _("Document List")); atk_object_set_description (accessible, _("Lists the user's documents submitted for printing")); } gtk_widget_show (list->priv->tree_view); gtk_container_add (GTK_CONTAINER (scrolledwin), list->priv->tree_view); gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (list->priv->model), sort_by_status, NULL, NULL); rend = gtk_cell_renderer_text_new (); col = gtk_tree_view_column_new_with_attributes (_("Document"), rend, NULL); gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_name, NULL, NULL); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list->priv->model), 0, sort_by_name, NULL, NULL); gtk_tree_view_column_set_sort_column_id (col, 0); gtk_tree_view_append_column (GTK_TREE_VIEW (list->priv->tree_view), col); rend = gtk_cell_renderer_text_new (); col = gtk_tree_view_column_new_with_attributes (_("Printer"), rend, NULL); gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_printer, NULL, NULL); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list->priv->model), 1, sort_by_printer, NULL, NULL); gtk_tree_view_column_set_sort_column_id (col, 1); gtk_tree_view_append_column (GTK_TREE_VIEW (list->priv->tree_view), col); rend = gtk_cell_renderer_text_new (); col = gtk_tree_view_column_new_with_attributes (_("Size"), rend, NULL); gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_size, NULL, NULL); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list->priv->model), 2, sort_by_size, NULL, NULL); gtk_tree_view_column_set_sort_column_id (col, 2); gtk_tree_view_append_column (GTK_TREE_VIEW (list->priv->tree_view), col); rend = gtk_cell_renderer_text_new (); col = gtk_tree_view_column_new_with_attributes (_("Time Submitted"), rend, NULL); gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_time, NULL, NULL); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list->priv->model), 3, sort_by_time, NULL, NULL); gtk_tree_view_column_set_sort_column_id (col, 3); gtk_tree_view_append_column (GTK_TREE_VIEW (list->priv->tree_view), col); #if 0 /* Cups doesn't seem to support this */ rend = gtk_cell_renderer_text_new (); col = gtk_tree_view_column_new_with_attributes (_("Position"), rend, NULL); gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_position, NULL, NULL); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list->priv->model), 4, sort_by_position, NULL, NULL); gtk_tree_view_column_set_sort_column_id (col, 4); gtk_tree_view_append_column (GTK_TREE_VIEW (list->priv->tree_view), col); #endif rend = gtk_cell_renderer_text_new (); col = gtk_tree_view_column_new_with_attributes (_("Status"), rend, NULL); gtk_tree_view_column_set_cell_data_func (col, rend, set_cell_status, NULL, NULL); gtk_tree_view_column_set_resizable (col, TRUE); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list->priv->model), 5, sort_by_status, NULL, NULL); gtk_tree_view_column_set_sort_column_id (col, 5); gtk_tree_view_append_column (GTK_TREE_VIEW (list->priv->tree_view), col); list->priv->statusbar = gtk_statusbar_new (); gnome_app_set_statusbar (GNOME_APP (list), list->priv->statusbar); gtk_window_set_default_size (GTK_WINDOW (list), 500, 300); g_signal_connect (list, "delete-event", G_CALLBACK (jobs_delete_event_cb), list); gtk_window_set_title (GTK_WINDOW (list), _("Document print status")); set_menu_sensitivities (list); set_menu_sensitivities (list); gtk_widget_show (GTK_WIDGET (list)); return obj; } static void ec_job_list_finalize (GObject *object) { ECJobList *list = EC_JOB_LIST (object); g_return_if_fail (list->priv != NULL); rb_debug ("finalizing"); g_free (list->priv); G_OBJECT_CLASS (ec_job_list_parent_class)->finalize (object); } ECJobList * ec_job_list_new (ECJobModel *model) { return EC_JOB_LIST (g_object_new (EC_TYPE_JOB_LIST, "model", model, NULL)); } static void selection_foreach_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GSList **list = data; JobData *job_data; job_data = g_new0 (JobData, 1); gtk_tree_model_get (model, iter, EC_JOB_MODEL_COLUMN_LOCAL_JOBID, &job_data->local_jobid, EC_JOB_MODEL_COLUMN_PRINTER, &job_data->printer, EC_JOB_MODEL_COLUMN_JOB, &job_data->job, -1); *list = g_slist_prepend (*list, job_data); } static GSList * get_selected_jobs (ECJobList *job_list) { GtkTreeSelection *selection; GSList *ret = NULL; selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (job_list->priv->tree_view)); gtk_tree_selection_selected_foreach (selection, selection_foreach_cb, &ret); return ret; } static void free_job_data (gpointer data, gpointer user_data) { JobData *job_data = data; g_free (job_data->printer); g_free (job_data); } static void free_selected_jobs (GSList *selected) { g_slist_foreach (selected, free_job_data, NULL); g_slist_free (selected); } static void set_menu_sensitivities (ECJobList *job_list) { GSList *selected = get_selected_jobs (job_list); gtk_widget_set_sensitive (job_list->priv->cancel, (selected != NULL)); gtk_widget_set_sensitive (job_list->priv->pause, (selected != NULL)); gtk_widget_set_sensitive (job_list->priv->resume, (selected != NULL)); free_selected_jobs (selected); } static void cancel_cb (GtkWidget *widget, ECJobList *job_list) { GSList *selected, *j; GtkWidget *dialog; gint length, resp; GnomeCupsQueue *queue; GError *error; selected = get_selected_jobs (job_list); length = g_slist_length (selected); if (length == 1 && ((JobData *)selected->data)->job) { JobData *job_data = selected->data; dialog = gtk_message_dialog_new (GTK_WINDOW (job_list), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("Cancel printing of \"%s\" " "on printer \"%s\"?"), job_data->job->name, job_data->printer); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", _("If you select \"Cancel printing\", " "the selected job will be cancelled.")); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("Keep printing"), GTK_RESPONSE_NO, _("Cancel printing"), GTK_RESPONSE_YES, NULL); } else { const char *primary_format; primary_format = ngettext ("Cancel printing of %d document?", "Cancel printing of %d documents?", length); dialog = gtk_message_dialog_new (GTK_WINDOW (job_list), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, primary_format, length); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", _("If you select \"Cancel printing\", " "the selected jobs will be cancelled.")); gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("Keep printing"), GTK_RESPONSE_NO, _("Cancel printing"), GTK_RESPONSE_YES, NULL); } resp = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (resp != GTK_RESPONSE_YES) { free_selected_jobs (selected); return; } for (j = selected; j; j = j->next) { JobData *job_data = j->data; if (!job_data->job) continue; /* avoid pointless error dialogs */ if (job_data->job->state == IPP_JOB_CANCELLED || job_data->job->state == IPP_JOB_ABORTED || job_data->job->state == IPP_JOB_COMPLETED || ec_job_model_job_get_pending_state (job_list->priv->job_model, job_data->local_jobid)) continue; queue = gnome_cups_queue_get (job_data->printer); error = NULL; gnome_cups_queue_cancel_job (queue, job_data->local_jobid, &error); if (error) { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (job_list), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Error cancelling \"%s\" on printer \"%s\".", job_data->job->name, job_data->printer); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); gtk_dialog_run (GTK_DIALOG (dialog)); g_clear_error (&error); } else ec_job_model_job_set_pending_state (job_list->priv->job_model, job_data->local_jobid, IPP_JOB_CANCELLED); } free_selected_jobs (selected); } static void pause_cb (GtkWidget *widget, ECJobList *job_list) { GSList *selected, *j; GnomeCupsQueue *queue; GError *error; selected = get_selected_jobs (job_list); for (j = selected; j; j = j->next) { JobData *job_data = j->data; if (!job_data->job) continue; queue = gnome_cups_queue_get (job_data->printer); error = NULL; gnome_cups_queue_pause_job (queue, job_data->job->id, &error); if (error) { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (job_list), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Error pausing \"%s\" on printer \"%s\".", job_data->job->name, job_data->printer); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); gtk_dialog_run (GTK_DIALOG (dialog)); g_clear_error (&error); } else ec_job_model_job_set_pending_state (job_list->priv->job_model, job_data->local_jobid, IPP_JOB_HELD); } free_selected_jobs (selected); } static void resume_cb (GtkWidget *widget, ECJobList *job_list) { GSList *selected, *j; GnomeCupsQueue *queue; GError *error; selected = get_selected_jobs (job_list); for (j = selected; j; j = j->next) { JobData *job_data = j->data; if (!job_data->job) continue; /* avoid pointless error dialogs */ if (job_data->job->state == IPP_JOB_CANCELLED || job_data->job->state == IPP_JOB_ABORTED || job_data->job->state == IPP_JOB_COMPLETED || ec_job_model_job_get_pending_state (job_list->priv->job_model, job_data->local_jobid)) continue; queue = gnome_cups_queue_get (job_data->printer); error = NULL; gnome_cups_queue_resume_job (queue, job_data->job->id, &error); if (error) { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (job_list), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Error resuming \"%s\" on printer \"%s\".", job_data->job->name, job_data->printer); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); gtk_dialog_run (GTK_DIALOG (dialog)); g_clear_error (&error); } } free_selected_jobs (selected); } static void clear_cb (GtkWidget *widget, ECJobList *job_list) { ec_job_model_remove_old_completed (job_list->priv->job_model, 0); } static void about_cb (GtkWidget *widget, gpointer data) { ec_tray_icon_show_about_window (); } static void show_popup_menu (GdkEvent *event, ECJobList *job_list) { static GtkWidget *menu = NULL; GtkWidget *menuitem; GSList *selection; int length; if (!menu) { menu = gtk_menu_new (); menuitem = gtk_menu_item_new_with_mnemonic (_("_Cancel Documents")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", G_CALLBACK (cancel_cb), job_list); menuitem = gtk_menu_item_new_with_mnemonic (_("_Pause Documents")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", G_CALLBACK (pause_cb), job_list); menuitem = gtk_menu_item_new_with_mnemonic (_("_Resume Documents")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", G_CALLBACK (resume_cb), job_list); } selection = get_selected_jobs (job_list); length = g_slist_length (selection); free_selected_jobs (selection); if (length > 0) gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event ? event->button.button : 3, event ? event->button.time : GDK_CURRENT_TIME); } static gboolean list_button_press_event_cb (GtkWidget *widget, GdkEvent *event, ECJobList *job_list) { if (event->type == GDK_BUTTON_PRESS && event->button.button == 3) { show_popup_menu (event, job_list); return TRUE; } return FALSE; } static void tree_selection_changed_cb (GtkTreeSelection *selection, ECJobList *job_list) { set_menu_sensitivities (job_list); } static void jobs_close_cb (GtkWidget *widget, ECJobList *job_list) { gtk_widget_hide (GTK_WIDGET (job_list)); } static gboolean jobs_delete_event_cb (GtkWidget *widget, GdkEvent *event, ECJobList *job_list) { gtk_widget_hide (GTK_WIDGET (job_list)); return TRUE; } static GtkWidget * create_jobs_menubar (GtkAccelGroup *accel_group, GtkTooltips *tooltips, ECJobList *job_list) { GtkWidget *menubar, *menuitem, *menu; menubar = gtk_menu_bar_new (); gtk_widget_show (menubar); /* File menu. */ menuitem = gtk_menu_item_new_with_mnemonic (_("_File")); gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem); gtk_widget_show (menuitem); menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLOSE, accel_group); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_tooltips_set_tip (tooltips, menuitem, _("Close the window"), NULL); gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", G_CALLBACK (jobs_close_cb), job_list); /* Edit menu. */ menuitem = gtk_menu_item_new_with_mnemonic (_("_Edit")); gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem); gtk_widget_show (menuitem); menu = gtk_menu_new (); gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); menuitem = gtk_menu_item_new_with_mnemonic (_("_Cancel Documents")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_tooltips_set_tip (tooltips, menuitem, _("Cancel printing of the selected documents"), NULL); gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", G_CALLBACK (cancel_cb), job_list); job_list->priv->cancel = menuitem; menuitem = gtk_menu_item_new_with_mnemonic (_("_Pause Documents")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_tooltips_set_tip (tooltips, menuitem, _("Pause printing of the selected documents"), NULL); gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", G_CALLBACK (pause_cb), job_list); job_list->priv->pause = menuitem; menuitem = gtk_menu_item_new_with_mnemonic (_("_Resume Documents")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_tooltips_set_tip (tooltips, menuitem, _("Resume printing of the selected documents"), NULL); gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", G_CALLBACK (resume_cb), job_list); job_list->priv->resume = menuitem; menuitem = gtk_menu_item_new_with_mnemonic (_("C_lear Completed Documents")); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem); gtk_tooltips_set_tip (tooltips, menuitem, _("Remove completed documents from the list"), NULL); gtk_widget_show (menuitem); g_signal_connect (menuitem, "activate", G_CALLBACK (clear_cb), job_list); job_list->priv->clear = menuitem; /* We don't have help yet. */ #if 0 /* Help menu. */ menuitem = gtk_menu_item_new_with_mnemonic (_("_Help")); gtk_menu_shell_append (GTK_MENU_SHELL (menubar), menuitem); gtk_widget_show (menuitem); #endif menu = gtk_menu_new (); #if 0 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), menu); #endif { GnomeUIInfo uiinfo [] = { GNOMEUIINFO_HELP ((gchar *) "eggcups"), GNOMEUIINFO_MENU_ABOUT_ITEM (about_cb, NULL), GNOMEUIINFO_END }; gnome_app_fill_menu (GTK_MENU_SHELL (menu), uiinfo, accel_group, TRUE, 0); } return menubar; } static void set_cell_printer (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { gchar *printer; gtk_tree_model_get (tree_model, iter, EC_JOB_MODEL_COLUMN_PRINTER, &printer, -1); g_object_set (cell, "text", printer ? printer : _("Unknown"), NULL); g_free (printer); } static gint sort_by_printer (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { gchar *printer_a, *printer_b; gint res; gtk_tree_model_get (model, a, EC_JOB_MODEL_COLUMN_PRINTER, &printer_a, -1); gtk_tree_model_get (model, b, EC_JOB_MODEL_COLUMN_PRINTER, &printer_b, -1); res = strcmp (printer_a ? printer_a : _("Unknown"), printer_b ? printer_b : _("Unknown")); g_free (printer_a); g_free (printer_b); return res; } static void set_cell_name (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { GnomeCupsJob *job; gtk_tree_model_get (tree_model, iter, EC_JOB_MODEL_COLUMN_JOB, &job, -1); g_object_set (cell, "text", job ? job->name : _("Unknown"), NULL); } static gint sort_by_name (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { GnomeCupsJob *job_a, *job_b; gtk_tree_model_get (model, a, EC_JOB_MODEL_COLUMN_JOB, &job_a, -1); gtk_tree_model_get (model, b, EC_JOB_MODEL_COLUMN_JOB, &job_b, -1); return strcmp (job_a ? job_a->name : _("Unknown"), job_b ? job_b->name : _("Unknown")); } static void set_cell_size (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { GnomeCupsJob *job; gchar *size; gint pages; gtk_tree_model_get (tree_model, iter, EC_JOB_MODEL_COLUMN_JOB, &job, -1); if (job) { pages = MAX (job->pages, job->pages_complete); if (pages > 0) size = g_strdup_printf (ngettext ("%d page", "%d pages", pages), pages); else /* Translators: This is the size of print jobs in kibibytes, and * expands to "42k" for 42 kibibytes. Do not translate the "job size|" prefix. * Remove it instead. */ size = g_strdup_printf (Q_("job size|%ldk"), job->size / 1024); } else size = g_strdup ("?"); g_object_set (cell, "text", size, NULL); g_free (size); } static gint sort_by_size (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { GnomeCupsJob *job_a, *job_b; gint size_a, size_b; gtk_tree_model_get (model, a, EC_JOB_MODEL_COLUMN_JOB, &job_a, -1); gtk_tree_model_get (model, b, EC_JOB_MODEL_COLUMN_JOB, &job_b, -1); size_a = job_a ? job_a->size : 0; size_b = job_b ? job_b->size : 0; if (size_a < size_b) return -1; if (size_a > size_b) return 1; return 0; } static void set_cell_time (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { long delta; long days, hours, minutes; gchar *result; const char *minutefmt; const char *hourfmt; const char *dayfmt; gtk_tree_model_get (tree_model, iter, EC_JOB_MODEL_COLUMN_LOCAL_SUBMISSION_TIME_RELATIVE, &delta, -1); if (delta < 0) { g_object_set (cell, "text", _("Unknown"), NULL); return; } /* Code stolen from Rhythmbox */ days = delta / (60 * 24); hours = (delta / 60) - (days * 24); minutes = delta - ((days * 24 * 60) + (hours * 60)); minutefmt = ngettext ("%ld minute", "%ld minutes", minutes); hourfmt = ngettext ("%ld hour", "%ld hours", hours); dayfmt = ngettext ("%ld day", "%ld days", days); if (days >= 1) { char *fmt; /* Translators: the format is "X days, X hours and X minutes ago" */ fmt = g_strdup_printf (_("%s, %s ago"), dayfmt, hourfmt); result = g_strdup_printf (fmt, days, hours, minutes); g_free (fmt); } else if (hours >= 1) { char *fmt; /* Translators: the format is "X hours and X minutes ago" */ fmt = g_strdup_printf (_("%s and %s ago"), hourfmt, minutefmt); result = g_strdup_printf (fmt, hours, minutes); g_free (fmt); } else if (minutes >= 1) { char *fmt; /* Translators: the format is "X minutes ago" */ fmt = g_strdup_printf (_("%s ago"), minutefmt); result = g_strdup_printf (fmt, minutes); g_free (fmt); } else { result = g_strdup (_("Less than one minute ago")); } g_object_set (cell, "text", result, NULL); g_free (result); } static gint sort_by_time (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { GTimeVal *time_a, *time_b; gtk_tree_model_get (model, a, EC_JOB_MODEL_COLUMN_LOCAL_SUBMISSION_TIME, &time_a, -1); gtk_tree_model_get (model, b, EC_JOB_MODEL_COLUMN_LOCAL_SUBMISSION_TIME, &time_b, -1); if (time_a->tv_sec < time_b->tv_sec) return -1; if (time_a->tv_sec > time_b->tv_sec) return 1; if (time_a->tv_usec < time_b->tv_usec) return -1; if (time_a->tv_usec > time_b->tv_usec) return 1; return 0; } #if 0 static void set_cell_position (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { GnomeCupsJob *job; gchar *position; gtk_tree_model_get (tree_model, iter, EC_JOB_MODEL_COLUMN_JOB, &job, -1); position = job ? g_strdup_printf ("%d", job->position + 1) : _("Unknown"); g_object_set (cell, "text", position, NULL); g_free (position); } static gint sort_by_position (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { GnomeCupsJob *job_a, *job_b; gint pos_a, pos_b; gtk_tree_model_get (model, a, EC_JOB_MODEL_COLUMN_JOB, &job_a, -1); gtk_tree_model_get (model, b, EC_JOB_MODEL_COLUMN_JOB, &job_b, -1); pos_a = job_a ? job_a->position : 0; pos_b = job_b ? job_b->position : 0; if (pos_a < pos_b) return -1; if (pos_a > pos_b) return 1; return 0; } #endif static void set_cell_status (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { ECJobState state; GnomeCupsJob *job; gchar *text = NULL; gtk_tree_model_get (tree_model, iter, EC_JOB_MODEL_COLUMN_STATE, &state, EC_JOB_MODEL_COLUMN_JOB, &job, -1); switch (state) { case EC_JOB_STATE_LOCAL: case EC_JOB_STATE_REMOTE: case EC_JOB_STATE_FINAL: text = g_strdup (job ? job->state_str : _("Unknown")); break; case EC_JOB_STATE_LOCAL_UNKNOWN: case EC_JOB_STATE_REMOTE_UNKNOWN: text = g_strdup_printf ("%s (?)", job ? job->state_str : _("Unknown")); break; case EC_JOB_STATE_SUBMITTED: if (job && job->state == IPP_JOB_HELD) text = g_strdup (job->state_str); else text = g_strdup (_("Sending")); break; case EC_JOB_STATE_SUBMITTED_UNKNOWN: if (job && job->state == IPP_JOB_HELD) text = g_strdup_printf ("%s (?)", job->state_str); else text = g_strdup (_("Sending (?)")); break; case EC_JOB_STATE_FINAL_TIMEOUT: text = g_strdup (_("Unknown")); break; } g_object_set (cell, "text", text, NULL); g_free (text); } static gint sort_by_status (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) { ECJobState state_a, state_b; GnomeCupsJob *job_a, *job_b; gtk_tree_model_get (model, a, EC_JOB_MODEL_COLUMN_STATE, &state_a, EC_JOB_MODEL_COLUMN_JOB, &job_a, -1); gtk_tree_model_get (model, b, EC_JOB_MODEL_COLUMN_STATE, &state_b, EC_JOB_MODEL_COLUMN_JOB, &job_b, -1); state_a = state_a * 10 + (job_a ? job_a->state : 0); state_b = state_b * 10 + (job_b ? job_b->state : 0); if (state_a < state_b) return -1; if (state_a > state_b) return 1; return 0; }