Logo Search packages:      
Sourcecode: eggcups version File versions  Download package

ec-job-list.c

/* -*- 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;
}

Generated by  Doxygen 1.6.0   Back to index