~ubuntu-branches/ubuntu/trusty/unity-control-center/trusty

« back to all changes in this revision

Viewing changes to panels/printers/pp-options-dialog.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-01-08 16:29:18 UTC
  • Revision ID: package-import@ubuntu.com-20140108162918-g29dd08tr913y2qh
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright 2012  Red Hat, Inc,
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 *
 
19
 * Author: Marek Kasik <mkasik@redhat.com>
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <unistd.h>
 
25
#include <stdlib.h>
 
26
#include <sys/types.h>
 
27
#include <sys/wait.h>
 
28
 
 
29
#include <glib.h>
 
30
#include <glib/gi18n.h>
 
31
#include <glib/gstdio.h>
 
32
#include <gtk/gtk.h>
 
33
 
 
34
#include <cups/cups.h>
 
35
#include <cups/ppd.h>
 
36
 
 
37
#include "pp-options-dialog.h"
 
38
#include "pp-ppd-option-widget.h"
 
39
#include "pp-ipp-option-widget.h"
 
40
#include "pp-utils.h"
 
41
 
 
42
struct _PpOptionsDialog {
 
43
  GtkBuilder *builder;
 
44
  GtkWidget  *parent;
 
45
 
 
46
  GtkWidget  *dialog;
 
47
 
 
48
  UserResponseCallback user_callback;
 
49
  gpointer             user_data;
 
50
 
 
51
  gchar       *printer_name;
 
52
 
 
53
  gchar       *ppd_filename;
 
54
  gboolean     ppd_filename_set;
 
55
 
 
56
  cups_dest_t *destination;
 
57
  gboolean     destination_set;
 
58
 
 
59
  GHashTable  *ipp_attributes;
 
60
  gboolean     ipp_attributes_set;
 
61
 
 
62
  gboolean     populating_dialog;
 
63
 
 
64
  GtkResponseType response;
 
65
 
 
66
  gboolean sensitive;
 
67
};
 
68
 
 
69
static void pp_options_dialog_hide (PpOptionsDialog *dialog);
 
70
 
 
71
enum
 
72
{
 
73
  CATEGORY_IDS_COLUMN = 0,
 
74
  CATEGORY_NAMES_COLUMN
 
75
};
 
76
 
 
77
/* These lists come from Gtk+ */
 
78
static const struct {
 
79
  const char *keyword;
 
80
  const char *translation;
 
81
} ppd_option_translations[] = {
 
82
  { "Duplex", N_("Two Sided") },
 
83
  { "MediaType", N_("Paper Type") },
 
84
  { "InputSlot", N_("Paper Source") },
 
85
  { "OutputBin", N_("Output Tray") },
 
86
  { "Resolution", N_("Resolution") },
 
87
  { "PreFilter", N_("GhostScript pre-filtering") },
 
88
};
 
89
 
 
90
/* keep sorted when changing */
 
91
static const char *page_setup_option_whitelist[] = {
 
92
  "InputSlot",
 
93
  "MediaType",
 
94
  "OutputBin",
 
95
  "PageSize",
 
96
};
 
97
 
 
98
/* keep sorted when changing */
 
99
static const char *color_option_whitelist[] = {
 
100
  "BRColorEnhancement",
 
101
  "BRColorMatching",
 
102
  "BRColorMatching",
 
103
  "BRColorMode",
 
104
  "BRGammaValue",
 
105
  "BRImprovedGray",
 
106
  "BlackSubstitution",
 
107
  "ColorModel",
 
108
  "HPCMYKInks",
 
109
  "HPCSGraphics",
 
110
  "HPCSImages",
 
111
  "HPCSText",
 
112
  "HPColorSmart",
 
113
  "RPSBlackMode",
 
114
  "RPSBlackOverPrint",
 
115
  "Rcmyksimulation",
 
116
};
 
117
 
 
118
/* keep sorted when changing */
 
119
static const char *color_group_whitelist[] = {
 
120
  "Color",
 
121
  "Color1",
 
122
  "Color2",
 
123
  "ColorBalance",
 
124
  "ColorPage",
 
125
  "ColorSettings1",
 
126
  "ColorSettings2",
 
127
  "ColorSettings3",
 
128
  "ColorSettings4",
 
129
  "EPColorSettings",
 
130
  "FPColorWise1",
 
131
  "FPColorWise2",
 
132
  "FPColorWise3",
 
133
  "FPColorWise4",
 
134
  "FPColorWise5",
 
135
  "HPCMYKInksPanel",
 
136
  "HPColorOptions",
 
137
  "HPColorOptionsPanel",
 
138
  "HPColorQualityOptionsPanel",
 
139
  "ManualColor",
 
140
};
 
141
 
 
142
/* keep sorted when changing */
 
143
static const char *image_quality_option_whitelist[] = {
 
144
  "BRDocument",
 
145
  "BRHalfTonePattern",
 
146
  "BRNormalPrt",
 
147
  "BRPrintQuality",
 
148
  "BitsPerPixel",
 
149
  "Darkness",
 
150
  "Dithering",
 
151
  "EconoMode",
 
152
  "Economode",
 
153
  "HPEconoMode",
 
154
  "HPEdgeControl",
 
155
  "HPGraphicsHalftone",
 
156
  "HPHalftone",
 
157
  "HPImagingOptions",
 
158
  "HPLJDensity",
 
159
  "HPPhotoHalftone",
 
160
  "HPPrintQualityOptions",
 
161
  "HPResolutionOptions",
 
162
  "OutputMode",
 
163
  "REt",
 
164
  "RPSBitsPerPixel",
 
165
  "RPSDitherType",
 
166
  "Resolution",
 
167
  "ScreenLock",
 
168
  "Smoothing",
 
169
  "TonerSaveMode",
 
170
  "UCRGCRForImage",
 
171
};
 
172
 
 
173
/* keep sorted when changing */
 
174
static const char *image_quality_group_whitelist[] = {
 
175
  "EPQualitySettings",
 
176
  "FPImageQuality1",
 
177
  "FPImageQuality2",
 
178
  "FPImageQuality3",
 
179
  "ImageQualityPage",
 
180
  "Quality",
 
181
};
 
182
 
 
183
/* keep sorted when changing */
 
184
static const char * finishing_option_whitelist[] = {
 
185
  "BindColor",
 
186
  "BindEdge",
 
187
  "BindType",
 
188
  "BindWhen",
 
189
  "Booklet",
 
190
  "FoldType",
 
191
  "FoldWhen",
 
192
  "HPStaplerOptions",
 
193
  "Jog",
 
194
  "Slipsheet",
 
195
  "Sorter",
 
196
  "StapleLocation",
 
197
  "StapleOrientation",
 
198
  "StapleWhen",
 
199
  "StapleX",
 
200
  "StapleY",
 
201
};
 
202
 
 
203
/* keep sorted when changing */
 
204
static const char *job_group_whitelist[] = {
 
205
  "JobHandling",
 
206
  "JobLog",
 
207
};
 
208
 
 
209
/* keep sorted when changing */
 
210
static const char *finishing_group_whitelist[] = {
 
211
  "Booklet",
 
212
  "BookletCover",
 
213
  "BookletModeOptions",
 
214
  "FPFinishing1",
 
215
  "FPFinishing2",
 
216
  "FPFinishing3",
 
217
  "FPFinishing4",
 
218
  "Finishing",
 
219
  "FinishingOptions",
 
220
  "FinishingPage",
 
221
  "HPBookletPanel",
 
222
  "HPFinishing",
 
223
  "HPFinishingOptions",
 
224
  "HPFinishingPanel",
 
225
};
 
226
 
 
227
/* keep sorted when changing */
 
228
static const char *installable_options_group_whitelist[] = {
 
229
  "InstallableOptions",
 
230
};
 
231
 
 
232
/* keep sorted when changing */
 
233
static const char *page_setup_group_whitelist[] = {
 
234
  "HPMarginAndLayout",
 
235
  "OutputControl",
 
236
  "PaperHandling",
 
237
  "Paper",
 
238
  "Source",
 
239
};
 
240
 
 
241
/* keep sorted when changing */
 
242
static const char *ppd_option_blacklist[] = {
 
243
  "Collate",
 
244
  "Copies",
 
245
  "Duplex",
 
246
  "HPManualDuplexOrientation",
 
247
  "HPManualDuplexSwitch",
 
248
  "OutputOrder",
 
249
  "PageRegion"
 
250
};
 
251
 
 
252
static int
 
253
strptr_cmp (const void *a,
 
254
            const void *b)
 
255
{
 
256
  char **aa = (char **)a;
 
257
  char **bb = (char **)b;
 
258
  return strcmp (*aa, *bb);
 
259
}
 
260
 
 
261
static gboolean
 
262
string_in_table (gchar       *str,
 
263
                 const gchar *table[],
 
264
                 gint         table_len)
 
265
{
 
266
  return bsearch (&str, table, table_len, sizeof (char *), (void *)strptr_cmp) != NULL;
 
267
}
 
268
 
 
269
#define STRING_IN_TABLE(_str, _table) (string_in_table (_str, _table, G_N_ELEMENTS (_table)))
 
270
 
 
271
static gchar *
 
272
ppd_option_name_translate (ppd_option_t *option)
 
273
{
 
274
  gint i;
 
275
 
 
276
  for (i = 0; i < G_N_ELEMENTS (ppd_option_translations); i++)
 
277
    {
 
278
      if (g_strcmp0 (ppd_option_translations[i].keyword, option->keyword) == 0)
 
279
        return g_strdup (_(ppd_option_translations[i].translation));
 
280
    }
 
281
 
 
282
  return g_strdup (option->text);
 
283
}
 
284
 
 
285
static gint
 
286
grid_get_height (GtkWidget *grid)
 
287
{
 
288
  GList *children;
 
289
  GList *child;
 
290
  gint   height = 0;
 
291
  gint   top_attach = 0;
 
292
  gint   max = 0;
 
293
 
 
294
  children = gtk_container_get_children (GTK_CONTAINER (grid));
 
295
  for (child = children; child; child = g_list_next (child))
 
296
    {
 
297
      gtk_container_child_get (GTK_CONTAINER (grid), child->data,
 
298
                               "top-attach", &top_attach,
 
299
                               "height", &height,
 
300
                               NULL);
 
301
 
 
302
      if (height + top_attach > max)
 
303
        max = height + top_attach;
 
304
    }
 
305
 
 
306
  g_list_free (children);
 
307
 
 
308
  return max;
 
309
}
 
310
 
 
311
static gboolean
 
312
grid_is_empty (GtkWidget *grid)
 
313
{
 
314
  GList *children;
 
315
 
 
316
  children = gtk_container_get_children (GTK_CONTAINER (grid));
 
317
  if (children)
 
318
    {
 
319
      g_list_free (children);
 
320
      return FALSE;
 
321
    }
 
322
  else
 
323
    {
 
324
      return TRUE;
 
325
    }
 
326
}
 
327
 
 
328
static GtkWidget *
 
329
ipp_option_add (IPPAttribute *attr_supported,
 
330
                IPPAttribute *attr_default,
 
331
                const gchar  *option_name,
 
332
                const gchar  *option_display_name,
 
333
                const gchar  *printer_name,
 
334
                GtkWidget    *grid,
 
335
                gboolean      sensitive)
 
336
{
 
337
  GtkStyleContext *context;
 
338
  GtkWidget       *widget;
 
339
  GtkWidget       *label;
 
340
  gint             position;
 
341
 
 
342
  widget = (GtkWidget *) pp_ipp_option_widget_new (attr_supported,
 
343
                                                   attr_default,
 
344
                                                   option_name,
 
345
                                                   printer_name);
 
346
  if (widget)
 
347
    {
 
348
      gtk_widget_set_sensitive (widget, sensitive);
 
349
      position = grid_get_height (grid);
 
350
 
 
351
      label = gtk_label_new (option_display_name);
 
352
      context = gtk_widget_get_style_context (label);
 
353
      gtk_style_context_add_class (context, "dim-label");
 
354
      gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
 
355
      gtk_widget_set_margin_left (label, 10);
 
356
      gtk_grid_attach (GTK_GRID (grid), label, 0, position, 1, 1);
 
357
 
 
358
      gtk_widget_set_margin_left (widget, 20);
 
359
      gtk_grid_attach (GTK_GRID (grid), widget, 1, position, 1, 1);
 
360
    }
 
361
 
 
362
  return widget;
 
363
}
 
364
 
 
365
static GtkWidget *
 
366
ppd_option_add (ppd_option_t  option,
 
367
                const gchar  *printer_name,
 
368
                GtkWidget    *grid,
 
369
                gboolean      sensitive)
 
370
{
 
371
  GtkStyleContext *context;
 
372
  GtkWidget       *widget;
 
373
  GtkWidget       *label;
 
374
  gint             position;
 
375
 
 
376
  widget = (GtkWidget *) pp_ppd_option_widget_new (&option, printer_name);
 
377
  if (widget)
 
378
    {
 
379
      gtk_widget_set_sensitive (widget, sensitive);
 
380
      position = grid_get_height (grid);
 
381
 
 
382
      label = gtk_label_new (ppd_option_name_translate (&option));
 
383
      context = gtk_widget_get_style_context (label);
 
384
      gtk_style_context_add_class (context, "dim-label");
 
385
      gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
 
386
      gtk_widget_set_margin_left (label, 10);
 
387
      gtk_grid_attach (GTK_GRID (grid), label, 0, position, 1, 1);
 
388
 
 
389
      gtk_widget_set_margin_left (widget, 20);
 
390
      gtk_grid_attach (GTK_GRID (grid), widget, 1, position, 1, 1);
 
391
    }
 
392
 
 
393
  return widget;
 
394
}
 
395
 
 
396
static GtkWidget *
 
397
tab_grid_new ()
 
398
{
 
399
  GtkWidget *grid;
 
400
 
 
401
  grid = gtk_grid_new ();
 
402
  gtk_container_set_border_width (GTK_CONTAINER (grid), 20);
 
403
  gtk_grid_set_row_spacing (GTK_GRID (grid), 15);
 
404
 
 
405
  return grid;
 
406
}
 
407
 
 
408
static void
 
409
tab_add (const gchar *tab_name,
 
410
         GtkWidget   *options_notebook,
 
411
         GtkTreeView *treeview,
 
412
         GtkWidget   *grid)
 
413
{
 
414
  GtkListStore *store;
 
415
  GtkTreeIter   iter;
 
416
  GtkWidget    *scrolled_window;
 
417
  gboolean      unref_store = FALSE;
 
418
  gint          id;
 
419
 
 
420
  if (!grid_is_empty (grid))
 
421
    {
 
422
      scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 
423
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
 
424
                                      GTK_POLICY_NEVER,
 
425
                                      GTK_POLICY_AUTOMATIC);
 
426
      gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
 
427
                                             grid);
 
428
 
 
429
      id = gtk_notebook_append_page (GTK_NOTEBOOK (options_notebook),
 
430
                                     scrolled_window,
 
431
                                     NULL);
 
432
 
 
433
      if (id >= 0)
 
434
        {
 
435
          store = GTK_LIST_STORE (gtk_tree_view_get_model (treeview));
 
436
          if (!store)
 
437
            {
 
438
              store = gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING);
 
439
              unref_store = TRUE;
 
440
            }
 
441
 
 
442
          gtk_list_store_append (store, &iter);
 
443
          gtk_list_store_set (store, &iter,
 
444
                              CATEGORY_IDS_COLUMN, id,
 
445
                              CATEGORY_NAMES_COLUMN, tab_name,
 
446
                              -1);
 
447
 
 
448
          if (unref_store)
 
449
            {
 
450
              gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
 
451
              g_object_unref (store);
 
452
            }
 
453
        }
 
454
    }
 
455
  else
 
456
    {
 
457
      g_object_ref_sink (grid);
 
458
      g_object_unref (grid);
 
459
    }
 
460
}
 
461
 
 
462
static void
 
463
category_selection_changed_cb (GtkTreeSelection *selection,
 
464
                               gpointer          user_data)
 
465
{
 
466
  PpOptionsDialog *dialog = (PpOptionsDialog *) user_data;
 
467
  GtkTreeModel    *model;
 
468
  GtkTreeIter      iter;
 
469
  GtkWidget       *options_notebook;
 
470
  gint             id = -1;
 
471
 
 
472
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
 
473
    {
 
474
      gtk_tree_model_get (model, &iter,
 
475
                          CATEGORY_IDS_COLUMN, &id,
 
476
                          -1);
 
477
    }
 
478
 
 
479
  if (id >= 0)
 
480
    {
 
481
      options_notebook = (GtkWidget*)
 
482
        gtk_builder_get_object (dialog->builder, "options-notebook");
 
483
 
 
484
      gtk_notebook_set_current_page (GTK_NOTEBOOK (options_notebook), id);
 
485
    }
 
486
}
 
487
 
 
488
static void
 
489
populate_options_real (PpOptionsDialog *dialog)
 
490
{
 
491
  GtkTreeSelection *selection;
 
492
  GtkTreeModel     *model;
 
493
  GtkTreeView      *treeview;
 
494
  GtkTreeIter       iter;
 
495
  ppd_file_t       *ppd_file;
 
496
  GtkWidget        *notebook;
 
497
  GtkWidget        *grid;
 
498
  GtkWidget        *general_tab_grid = tab_grid_new ();
 
499
  GtkWidget        *page_setup_tab_grid = tab_grid_new ();
 
500
  GtkWidget        *installable_options_tab_grid = tab_grid_new ();
 
501
  GtkWidget        *job_tab_grid = tab_grid_new ();
 
502
  GtkWidget        *image_quality_tab_grid = tab_grid_new ();
 
503
  GtkWidget        *color_tab_grid = tab_grid_new ();
 
504
  GtkWidget        *finishing_tab_grid = tab_grid_new ();
 
505
  GtkWidget        *advanced_tab_grid = tab_grid_new ();
 
506
  GtkWidget        *widget;
 
507
  gint              i, j;
 
508
 
 
509
  widget = (GtkWidget*)
 
510
    gtk_builder_get_object (dialog->builder, "options-spinner");
 
511
  gtk_widget_hide (widget);
 
512
  gtk_spinner_stop (GTK_SPINNER (widget));
 
513
 
 
514
  widget = (GtkWidget*)
 
515
    gtk_builder_get_object (dialog->builder, "progress-label");
 
516
  gtk_widget_hide (widget);
 
517
 
 
518
  treeview = (GtkTreeView *)
 
519
    gtk_builder_get_object (dialog->builder, "options-categories-treeview");
 
520
 
 
521
  notebook = (GtkWidget *)
 
522
    gtk_builder_get_object (dialog->builder, "options-notebook");
 
523
 
 
524
  if (dialog->ipp_attributes)
 
525
    {
 
526
      /* Add number-up option to Page Setup tab */
 
527
      ipp_option_add (g_hash_table_lookup (dialog->ipp_attributes,
 
528
                                           "number-up-supported"),
 
529
                      g_hash_table_lookup (dialog->ipp_attributes,
 
530
                                           "number-up-default"),
 
531
                      "number-up",
 
532
                      /* Translators: This option sets number of pages printed on one sheet */
 
533
                      _("Pages per side"),
 
534
                      dialog->printer_name,
 
535
                      page_setup_tab_grid,
 
536
                      dialog->sensitive);
 
537
 
 
538
      /* Add sides option to Page Setup tab */
 
539
      ipp_option_add (g_hash_table_lookup (dialog->ipp_attributes,
 
540
                                           "sides-supported"),
 
541
                      g_hash_table_lookup (dialog->ipp_attributes,
 
542
                                           "sides-default"),
 
543
                      "sides",
 
544
                      /* Translators: This option sets whether to print on both sides of paper */
 
545
                      _("Two-sided"),
 
546
                      dialog->printer_name,
 
547
                      page_setup_tab_grid,
 
548
                      dialog->sensitive);
 
549
 
 
550
      /* Add orientation-requested option to Page Setup tab */
 
551
      ipp_option_add (g_hash_table_lookup (dialog->ipp_attributes,
 
552
                                           "orientation-requested-supported"),
 
553
                      g_hash_table_lookup (dialog->ipp_attributes,
 
554
                                           "orientation-requested-default"),
 
555
                      "orientation-requested",
 
556
                      /* Translators: This option sets orientation of print (portrait, landscape...) */
 
557
                      _("Orientation"),
 
558
                      dialog->printer_name,
 
559
                      page_setup_tab_grid,
 
560
                      dialog->sensitive);
 
561
    }
 
562
 
 
563
  if (dialog->destination && dialog->ppd_filename)
 
564
    {
 
565
      ppd_file = ppdOpenFile (dialog->ppd_filename);
 
566
      ppdLocalize (ppd_file);
 
567
 
 
568
      if (ppd_file)
 
569
        {
 
570
          ppdMarkDefaults (ppd_file);
 
571
          cupsMarkOptions (ppd_file,
 
572
                           dialog->destination->num_options,
 
573
                           dialog->destination->options);
 
574
 
 
575
          for (i = 0; i < ppd_file->num_groups; i++)
 
576
            {
 
577
              for (j = 0; j < ppd_file->groups[i].num_options; j++)
 
578
                {
 
579
                  grid = NULL;
 
580
 
 
581
                  if (STRING_IN_TABLE (ppd_file->groups[i].name,
 
582
                                       color_group_whitelist))
 
583
                    grid = color_tab_grid;
 
584
                  else if (STRING_IN_TABLE (ppd_file->groups[i].name,
 
585
                                            image_quality_group_whitelist))
 
586
                    grid = image_quality_tab_grid;
 
587
                  else if (STRING_IN_TABLE (ppd_file->groups[i].name,
 
588
                                            job_group_whitelist))
 
589
                    grid = job_tab_grid;
 
590
                  else if (STRING_IN_TABLE (ppd_file->groups[i].name,
 
591
                                            finishing_group_whitelist))
 
592
                    grid = finishing_tab_grid;
 
593
                  else if (STRING_IN_TABLE (ppd_file->groups[i].name,
 
594
                                            installable_options_group_whitelist))
 
595
                    grid = installable_options_tab_grid;
 
596
                  else if (STRING_IN_TABLE (ppd_file->groups[i].name,
 
597
                                            page_setup_group_whitelist))
 
598
                    grid = page_setup_tab_grid;
 
599
 
 
600
                  if (!STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
 
601
                                        ppd_option_blacklist))
 
602
                    {
 
603
                      if (!grid && STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
 
604
                                                    color_option_whitelist))
 
605
                        grid = color_tab_grid;
 
606
                      else if (!grid && STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
 
607
                                                         image_quality_option_whitelist))
 
608
                        grid = image_quality_tab_grid;
 
609
                      else if (!grid && STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
 
610
                                                         finishing_option_whitelist))
 
611
                        grid = finishing_tab_grid;
 
612
                      else if (!grid && STRING_IN_TABLE (ppd_file->groups[i].options[j].keyword,
 
613
                                                         page_setup_option_whitelist))
 
614
                        grid = page_setup_tab_grid;
 
615
 
 
616
                      if (!grid)
 
617
                        grid = advanced_tab_grid;
 
618
 
 
619
                      ppd_option_add (ppd_file->groups[i].options[j],
 
620
                                      dialog->printer_name,
 
621
                                      grid,
 
622
                                      dialog->sensitive);
 
623
                    }
 
624
                }
 
625
            }
 
626
 
 
627
          ppdClose (ppd_file);
 
628
        }
 
629
    }
 
630
 
 
631
  dialog->ppd_filename_set = FALSE;
 
632
  if (dialog->ppd_filename)
 
633
    {
 
634
      g_unlink (dialog->ppd_filename);
 
635
      g_free (dialog->ppd_filename);
 
636
      dialog->ppd_filename = NULL;
 
637
    }
 
638
 
 
639
  dialog->destination_set = FALSE;
 
640
  if (dialog->destination)
 
641
    {
 
642
      cupsFreeDests (1, dialog->destination);
 
643
      dialog->destination = NULL;
 
644
    }
 
645
 
 
646
  dialog->ipp_attributes_set = FALSE;
 
647
  if (dialog->ipp_attributes)
 
648
    {
 
649
      g_hash_table_unref (dialog->ipp_attributes);
 
650
      dialog->ipp_attributes = NULL;
 
651
    }
 
652
 
 
653
  /* Translators: "General" tab contains general printer options */
 
654
  tab_add (C_("Printer Option Group", "General"), notebook, treeview, general_tab_grid);
 
655
 
 
656
  /* Translators: "Page Setup" tab contains settings related to pages (page size, paper source, etc.) */
 
657
  tab_add (C_("Printer Option Group", "Page Setup"), notebook, treeview, page_setup_tab_grid);
 
658
 
 
659
  /* Translators: "Installable Options" tab contains settings of presence of installed options (amount of RAM, duplex unit, etc.) */
 
660
  tab_add (C_("Printer Option Group", "Installable Options"), notebook, treeview, installable_options_tab_grid);
 
661
 
 
662
  /* Translators: "Job" tab contains settings for jobs */
 
663
  tab_add (C_("Printer Option Group", "Job"), notebook, treeview, job_tab_grid);
 
664
 
 
665
  /* Translators: "Image Quality" tab contains settings for quality of output print (e.g. resolution) */
 
666
  tab_add (C_("Printer Option Group", "Image Quality"), notebook, treeview, image_quality_tab_grid);
 
667
 
 
668
  /* Translators: "Color" tab contains color settings (e.g. color printing) */
 
669
  tab_add (C_("Printer Option Group", "Color"), notebook, treeview, color_tab_grid);
 
670
 
 
671
  /* Translators: "Finishing" tab contains finishing settings (e.g. booklet printing) */
 
672
  tab_add (C_("Printer Option Group", "Finishing"), notebook, treeview, finishing_tab_grid);
 
673
 
 
674
  /* Translators: "Advanced" tab contains all others settings */
 
675
  tab_add (C_("Printer Option Group", "Advanced"), notebook, treeview, advanced_tab_grid);
 
676
 
 
677
  gtk_widget_show_all (GTK_WIDGET (notebook));
 
678
 
 
679
  /* Select the first option group */
 
680
  if ((selection = gtk_tree_view_get_selection (treeview)) != NULL)
 
681
    {
 
682
      g_signal_connect (selection,
 
683
                        "changed",
 
684
                        G_CALLBACK (category_selection_changed_cb), dialog);
 
685
 
 
686
      if ((model = gtk_tree_view_get_model (treeview)) != NULL &&
 
687
          gtk_tree_model_get_iter_first (model, &iter))
 
688
        gtk_tree_selection_select_iter (selection, &iter);
 
689
    }
 
690
 
 
691
  dialog->populating_dialog = FALSE;
 
692
  if (dialog->response != GTK_RESPONSE_NONE)
 
693
    {
 
694
      dialog->user_callback (GTK_DIALOG (dialog->dialog), dialog->response, dialog->user_data);
 
695
    }
 
696
}
 
697
 
 
698
static void
 
699
printer_get_ppd_cb (const gchar *ppd_filename,
 
700
                    gpointer     user_data)
 
701
{
 
702
  PpOptionsDialog *dialog = (PpOptionsDialog *) user_data;
 
703
 
 
704
  if (dialog->ppd_filename)
 
705
    {
 
706
      g_unlink (dialog->ppd_filename);
 
707
      g_free (dialog->ppd_filename);
 
708
    }
 
709
 
 
710
  dialog->ppd_filename = g_strdup (ppd_filename);
 
711
  dialog->ppd_filename_set = TRUE;
 
712
 
 
713
  if (dialog->destination_set &&
 
714
      dialog->ipp_attributes_set)
 
715
    {
 
716
      populate_options_real (dialog);
 
717
    }
 
718
}
 
719
 
 
720
static void
 
721
get_named_dest_cb (cups_dest_t *dest,
 
722
                   gpointer     user_data)
 
723
{
 
724
  PpOptionsDialog *dialog = (PpOptionsDialog *) user_data;
 
725
 
 
726
  if (dialog->destination)
 
727
    cupsFreeDests (1, dialog->destination);
 
728
 
 
729
  dialog->destination = dest;
 
730
  dialog->destination_set = TRUE;
 
731
 
 
732
  if (dialog->ppd_filename_set &&
 
733
      dialog->ipp_attributes_set)
 
734
    {
 
735
      populate_options_real (dialog);
 
736
    }
 
737
}
 
738
 
 
739
static void
 
740
get_ipp_attributes_cb (GHashTable *table,
 
741
                       gpointer    user_data)
 
742
{
 
743
  PpOptionsDialog *dialog = (PpOptionsDialog *) user_data;
 
744
 
 
745
  if (dialog->ipp_attributes)
 
746
    g_hash_table_unref (dialog->ipp_attributes);
 
747
 
 
748
  dialog->ipp_attributes = table;
 
749
  dialog->ipp_attributes_set = TRUE;
 
750
 
 
751
  if (dialog->ppd_filename_set &&
 
752
      dialog->destination_set)
 
753
    {
 
754
      populate_options_real (dialog);
 
755
    }
 
756
}
 
757
 
 
758
static void
 
759
populate_options (PpOptionsDialog *dialog)
 
760
{
 
761
  GtkTreeViewColumn  *column;
 
762
  GtkCellRenderer    *renderer;
 
763
  GtkTreeView        *treeview;
 
764
  GtkWidget          *widget;
 
765
  /*
 
766
   * Options which we need to obtain through an IPP request
 
767
   * to be able to fill the options dialog.
 
768
   * *-supported - possible values of the option
 
769
   * *-default - actual value of the option
 
770
   */
 
771
  const gchar        *attributes[] =
 
772
    { "number-up-supported",
 
773
      "number-up-default",
 
774
      "sides-supported",
 
775
      "sides-default",
 
776
      "orientation-requested-supported",
 
777
      "orientation-requested-default",
 
778
      NULL};
 
779
 
 
780
  treeview = (GtkTreeView *)
 
781
    gtk_builder_get_object (dialog->builder, "options-categories-treeview");
 
782
 
 
783
  renderer = gtk_cell_renderer_text_new ();
 
784
 
 
785
  column = gtk_tree_view_column_new_with_attributes ("Categories", renderer,
 
786
                                                     "text", CATEGORY_NAMES_COLUMN, NULL);
 
787
  gtk_tree_view_column_set_expand (column, TRUE);
 
788
  gtk_tree_view_append_column (treeview, column);
 
789
 
 
790
  widget = (GtkWidget*)
 
791
    gtk_builder_get_object (dialog->builder, "options-spinner");
 
792
  gtk_widget_show (widget);
 
793
  gtk_spinner_start (GTK_SPINNER (widget));
 
794
 
 
795
  widget = (GtkWidget*)
 
796
    gtk_builder_get_object (dialog->builder, "progress-label");
 
797
  gtk_widget_show (widget);
 
798
 
 
799
  printer_get_ppd_async (dialog->printer_name,
 
800
                         NULL,
 
801
                         0,
 
802
                         printer_get_ppd_cb,
 
803
                         dialog);
 
804
 
 
805
  get_named_dest_async (dialog->printer_name,
 
806
                        get_named_dest_cb,
 
807
                        dialog);
 
808
 
 
809
  get_ipp_attributes_async (dialog->printer_name,
 
810
                            (gchar **) attributes,
 
811
                            get_ipp_attributes_cb,
 
812
                            dialog);
 
813
}
 
814
 
 
815
/*
 
816
 * Modify padding of the content area of the GtkDialog
 
817
 * so it is aligned with the action area.
 
818
 */
 
819
static void
 
820
update_alignment_padding (GtkWidget     *widget,
 
821
                          GtkAllocation *allocation,
 
822
                          gpointer       user_data)
 
823
{
 
824
  PpOptionsDialog *dialog = (PpOptionsDialog*) user_data;
 
825
  GtkAllocation    allocation1, allocation2;
 
826
  GtkWidget       *action_area;
 
827
  GtkWidget       *content_area;
 
828
  gint             offset_left, offset_right;
 
829
  guint            padding_left, padding_right,
 
830
                   padding_top, padding_bottom;
 
831
 
 
832
  action_area = (GtkWidget*)
 
833
    gtk_builder_get_object (dialog->builder, "dialog-action-area1");
 
834
  gtk_widget_get_allocation (action_area, &allocation2);
 
835
 
 
836
  content_area = (GtkWidget*)
 
837
    gtk_builder_get_object (dialog->builder, "content-alignment");
 
838
  gtk_widget_get_allocation (content_area, &allocation1);
 
839
 
 
840
  offset_left = allocation2.x - allocation1.x;
 
841
  offset_right = (allocation1.x + allocation1.width) -
 
842
                 (allocation2.x + allocation2.width);
 
843
 
 
844
  gtk_alignment_get_padding  (GTK_ALIGNMENT (content_area),
 
845
                              &padding_top, &padding_bottom,
 
846
                              &padding_left, &padding_right);
 
847
  if (allocation1.x >= 0 && allocation2.x >= 0)
 
848
    {
 
849
      if (offset_left > 0 && offset_left != padding_left)
 
850
        gtk_alignment_set_padding (GTK_ALIGNMENT (content_area),
 
851
                                   padding_top, padding_bottom,
 
852
                                   offset_left, padding_right);
 
853
 
 
854
      gtk_alignment_get_padding  (GTK_ALIGNMENT (content_area),
 
855
                                  &padding_top, &padding_bottom,
 
856
                                  &padding_left, &padding_right);
 
857
      if (offset_right > 0 && offset_right != padding_right)
 
858
        gtk_alignment_set_padding (GTK_ALIGNMENT (content_area),
 
859
                                   padding_top, padding_bottom,
 
860
                                   padding_left, offset_right);
 
861
    }
 
862
}
 
863
 
 
864
static void
 
865
options_dialog_response_cb (GtkDialog *_dialog,
 
866
                            gint       response_id,
 
867
                            gpointer   user_data)
 
868
{
 
869
  PpOptionsDialog *dialog = (PpOptionsDialog*) user_data;
 
870
 
 
871
  pp_options_dialog_hide (dialog);
 
872
  dialog->response = response_id;
 
873
 
 
874
  if (!dialog->populating_dialog)
 
875
    dialog->user_callback (GTK_DIALOG (dialog->dialog), response_id, dialog->user_data);
 
876
}
 
877
 
 
878
PpOptionsDialog *
 
879
pp_options_dialog_new (GtkWindow            *parent,
 
880
                       UserResponseCallback  user_callback,
 
881
                       gpointer              user_data,
 
882
                       gchar                *printer_name,
 
883
                       gboolean              sensitive)
 
884
{
 
885
  PpOptionsDialog *dialog;
 
886
  GtkWidget       *widget;
 
887
  GError          *error = NULL;
 
888
  gchar           *objects[] = { "options-dialog", NULL };
 
889
  guint            builder_result;
 
890
  gchar           *title;
 
891
 
 
892
  dialog = g_new0 (PpOptionsDialog, 1);
 
893
 
 
894
  dialog->builder = gtk_builder_new ();
 
895
  dialog->parent = GTK_WIDGET (parent);
 
896
 
 
897
  builder_result = gtk_builder_add_objects_from_file (dialog->builder,
 
898
                                                      DATADIR"/options-dialog.ui",
 
899
                                                      objects, &error);
 
900
 
 
901
  if (builder_result == 0)
 
902
    {
 
903
      g_warning ("Could not load ui: %s", error->message);
 
904
      g_error_free (error);
 
905
      return NULL;
 
906
    }
 
907
 
 
908
  dialog->dialog = (GtkWidget *) gtk_builder_get_object (dialog->builder, "options-dialog");
 
909
  gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), GTK_WINDOW (parent));
 
910
 
 
911
  dialog->user_callback = user_callback;
 
912
  dialog->user_data = user_data;
 
913
 
 
914
  dialog->printer_name = g_strdup (printer_name);
 
915
 
 
916
  dialog->ppd_filename = NULL;
 
917
  dialog->ppd_filename_set = FALSE;
 
918
 
 
919
  dialog->destination = NULL;
 
920
  dialog->destination_set = FALSE;
 
921
 
 
922
  dialog->ipp_attributes = NULL;
 
923
  dialog->ipp_attributes_set = FALSE;
 
924
 
 
925
  dialog->response = GTK_RESPONSE_NONE;
 
926
 
 
927
  dialog->sensitive = sensitive;
 
928
 
 
929
  /* connect signals */
 
930
  g_signal_connect (dialog->dialog, "response", G_CALLBACK (options_dialog_response_cb), dialog);
 
931
  g_signal_connect (dialog->dialog, "size-allocate", G_CALLBACK (update_alignment_padding), dialog);
 
932
 
 
933
  widget = (GtkWidget*)
 
934
    gtk_builder_get_object (dialog->builder, "options-title");
 
935
  /* Translators: Options of given printer (e.g. "MyPrinter Options") */
 
936
  title = g_strdup_printf (_("%s Options"), printer_name);
 
937
  gtk_label_set_label (GTK_LABEL (widget), title);
 
938
  g_free (title);
 
939
 
 
940
  gtk_widget_show_all (GTK_WIDGET (dialog->dialog));
 
941
 
 
942
  dialog->populating_dialog = TRUE;
 
943
  populate_options (dialog);
 
944
 
 
945
  return dialog;
 
946
}
 
947
 
 
948
void
 
949
pp_options_dialog_free (PpOptionsDialog *dialog)
 
950
{
 
951
  gtk_widget_destroy (GTK_WIDGET (dialog->dialog));
 
952
  dialog->dialog = NULL;
 
953
 
 
954
  g_object_unref (dialog->builder);
 
955
  dialog->builder = NULL;
 
956
 
 
957
  g_free (dialog->printer_name);
 
958
  dialog->printer_name = NULL;
 
959
 
 
960
  if (dialog->ppd_filename)
 
961
    {
 
962
      g_unlink (dialog->ppd_filename);
 
963
      g_free (dialog->ppd_filename);
 
964
      dialog->ppd_filename = NULL;
 
965
    }
 
966
 
 
967
  if (dialog->destination)
 
968
    {
 
969
      cupsFreeDests (1, dialog->destination);
 
970
      dialog->destination = NULL;
 
971
    }
 
972
 
 
973
  if (dialog->ipp_attributes)
 
974
    {
 
975
      g_hash_table_unref (dialog->ipp_attributes);
 
976
      dialog->ipp_attributes = NULL;
 
977
    }
 
978
 
 
979
  g_free (dialog);
 
980
}
 
981
 
 
982
static void
 
983
pp_options_dialog_hide (PpOptionsDialog *dialog)
 
984
{
 
985
  gtk_widget_hide (GTK_WIDGET (dialog->dialog));
 
986
}