]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintunixdialog.c
Add translator hints here too
[~andy/gtk] / gtk / gtkprintunixdialog.c
1 /* GtkPrintUnixDialog
2  * Copyright (C) 2006 John (J5) Palmieri  <johnp@redhat.com>
3  * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
4  * Copyright © 2006, 2007 Christian Persch
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <math.h>
28
29 #include "gtkintl.h"
30 #include "gtkprivate.h"
31
32 #include "gtkspinbutton.h"
33 #include "gtkcellrendererpixbuf.h"
34 #include "gtkcellrenderertext.h"
35 #include "gtkstock.h"
36 #include "gtkiconfactory.h"
37 #include "gtkimage.h"
38 #include "gtktreeselection.h"
39 #include "gtknotebook.h"
40 #include "gtkscrolledwindow.h"
41 #include "gtkcombobox.h"
42 #include "gtktogglebutton.h"
43 #include "gtkradiobutton.h"
44 #include "gtkdrawingarea.h"
45 #include "gtkvbox.h"
46 #include "gtktable.h"
47 #include "gtkframe.h"
48 #include "gtkalignment.h"
49 #include "gtklabel.h"
50 #include "gtkeventbox.h"
51 #include "gtkbuildable.h"
52
53 #include "gtkprintbackend.h"
54 #include "gtkprinter-private.h"
55 #include "gtkprintunixdialog.h"
56 #include "gtkprinteroptionwidget.h"
57 #include "gtkalias.h"
58
59 #include "gtkmessagedialog.h"
60 #include "gtkbutton.h"
61
62 #define EXAMPLE_PAGE_AREA_SIZE 140
63
64 #define GTK_PRINT_UNIX_DIALOG_GET_PRIVATE(o)  \
65    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINT_UNIX_DIALOG, GtkPrintUnixDialogPrivate))
66
67 static void     gtk_print_unix_dialog_destroy      (GtkPrintUnixDialog *dialog);
68 static void     gtk_print_unix_dialog_finalize     (GObject            *object);
69 static void     gtk_print_unix_dialog_set_property (GObject            *object,
70                                                     guint               prop_id,
71                                                     const GValue       *value,
72                                                     GParamSpec         *pspec);
73 static void     gtk_print_unix_dialog_get_property (GObject            *object,
74                                                     guint               prop_id,
75                                                     GValue             *value,
76                                                     GParamSpec         *pspec);
77 static void     gtk_print_unix_dialog_style_set    (GtkWidget          *widget,
78                                                     GtkStyle           *previous_style);
79 static void     populate_dialog                    (GtkPrintUnixDialog *dialog);
80 static void     unschedule_idle_mark_conflicts     (GtkPrintUnixDialog *dialog);
81 static void     selected_printer_changed           (GtkTreeSelection   *selection,
82                                                     GtkPrintUnixDialog *dialog);
83 static void     clear_per_printer_ui               (GtkPrintUnixDialog *dialog);
84 static void     printer_added_cb                   (GtkPrintBackend    *backend,
85                                                     GtkPrinter         *printer,
86                                                     GtkPrintUnixDialog *dialog);
87 static void     printer_removed_cb                 (GtkPrintBackend    *backend,
88                                                     GtkPrinter         *printer,
89                                                     GtkPrintUnixDialog *dialog);
90 static void     printer_status_cb                  (GtkPrintBackend    *backend,
91                                                     GtkPrinter         *printer,
92                                                     GtkPrintUnixDialog *dialog);
93 static void     update_collate_icon                (GtkToggleButton    *toggle_button,
94                                                     GtkPrintUnixDialog *dialog);
95 static gboolean dialog_get_collate                 (GtkPrintUnixDialog *dialog);
96 static gboolean dialog_get_reverse                 (GtkPrintUnixDialog *dialog);
97 static gint     dialog_get_n_copies                (GtkPrintUnixDialog *dialog);
98
99 static void     set_cell_sensitivity_func          (GtkTreeViewColumn *tree_column,
100                                                     GtkCellRenderer   *cell,
101                                                     GtkTreeModel      *model,
102                                                     GtkTreeIter       *iter,
103                                                     gpointer           data);
104
105 /* GtkBuildable */
106 static void gtk_print_unix_dialog_buildable_init                    (GtkBuildableIface *iface);
107 static GObject *gtk_print_unix_dialog_buildable_get_internal_child  (GtkBuildable *buildable,
108                                                                      GtkBuilder   *builder,
109                                                                      const gchar  *childname);
110
111 enum {
112   PROP_0,
113   PROP_PAGE_SETUP,
114   PROP_CURRENT_PAGE,
115   PROP_PRINT_SETTINGS,
116   PROP_SELECTED_PRINTER
117 };
118
119 enum {
120   PRINTER_LIST_COL_ICON,
121   PRINTER_LIST_COL_NAME,
122   PRINTER_LIST_COL_STATE,
123   PRINTER_LIST_COL_JOBS,
124   PRINTER_LIST_COL_LOCATION,
125   PRINTER_LIST_COL_PRINTER_OBJ,
126   PRINTER_LIST_N_COLS
127 };
128
129 struct GtkPrintUnixDialogPrivate
130 {
131   GtkWidget *notebook;
132
133   GtkWidget *printer_treeview;
134
135   GtkPrintCapabilities manual_capabilities;
136   GtkPrintCapabilities printer_capabilities;
137   
138   GtkTreeModel *printer_list;
139   GtkTreeModelFilter *printer_list_filter;
140
141   GtkPageSetup *page_setup;
142   gboolean page_setup_set;
143
144   GtkWidget *all_pages_radio;
145   GtkWidget *current_page_radio;
146   GtkWidget *page_range_radio;
147   GtkWidget *page_range_entry;
148   
149   GtkWidget *copies_spin;
150   GtkWidget *collate_check;
151   GtkWidget *reverse_check;
152   GtkWidget *collate_image;
153   GtkWidget *page_layout_preview;
154   GtkWidget *scale_spin;
155   GtkWidget *page_set_combo;
156   GtkWidget *print_now_radio;
157   GtkWidget *print_at_radio;
158   GtkWidget *print_at_entry;
159   GtkWidget *print_hold_radio;
160   GtkWidget *preview_button;
161   gboolean updating_print_at;
162   GtkPrinterOptionWidget *pages_per_sheet;
163   GtkPrinterOptionWidget *duplex;
164   GtkPrinterOptionWidget *paper_type;
165   GtkPrinterOptionWidget *paper_source;
166   GtkPrinterOptionWidget *output_tray;
167   GtkPrinterOptionWidget *job_prio;
168   GtkPrinterOptionWidget *billing_info;
169   GtkPrinterOptionWidget *cover_before;
170   GtkPrinterOptionWidget *cover_after;
171   GtkPrinterOptionWidget *number_up_layout;
172
173   GtkWidget *conflicts_widget;
174
175   GtkWidget *job_page;
176   GtkWidget *finishing_table;
177   GtkWidget *finishing_page;
178   GtkWidget *image_quality_table;
179   GtkWidget *image_quality_page;
180   GtkWidget *color_table;
181   GtkWidget *color_page;
182
183   GtkWidget *advanced_vbox;
184   GtkWidget *advanced_page;
185
186   GtkWidget *extension_point;
187
188   /* These are set initially on selected printer (either default printer, 
189    * printer taken from set settings, or user-selected), but when any setting 
190    * is changed by the user it is cleared.
191    */
192   GtkPrintSettings *initial_settings;
193
194   GtkPrinterOption *number_up_layout_n_option;
195   GtkPrinterOption *number_up_layout_2_option;
196   
197   /* This is the initial printer set by set_settings. We look for it in the
198    * added printers. We clear this whenever the user manually changes
199    * to another printer, when the user changes a setting or when we find
200    * this printer.
201    */
202   char *waiting_for_printer;
203   gboolean internal_printer_change;
204   
205   GList *print_backends;
206   
207   GtkPrinter *current_printer;
208   GtkPrinter *request_details_printer;
209   guint request_details_tag;
210   GtkPrinterOptionSet *options;
211   gulong options_changed_handler;
212   gulong mark_conflicts_id;
213
214   gchar *format_for_printer;
215   
216   gint current_page;
217 };
218
219 G_DEFINE_TYPE_WITH_CODE (GtkPrintUnixDialog, gtk_print_unix_dialog, GTK_TYPE_DIALOG,
220                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
221                                                 gtk_print_unix_dialog_buildable_init))
222
223 static GtkBuildableIface *parent_buildable_iface;
224
225 static gboolean
226 is_default_printer (GtkPrintUnixDialog *dialog,
227                     GtkPrinter         *printer)
228 {
229   GtkPrintUnixDialogPrivate *priv = dialog->priv;
230
231   if (priv->format_for_printer)
232     return strcmp (priv->format_for_printer,
233                    gtk_printer_get_name (printer)) == 0;
234  else
235    return gtk_printer_is_default (printer);
236 }
237
238 static void
239 gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
240 {
241   GObjectClass *object_class;
242   GtkWidgetClass *widget_class;
243
244   object_class = (GObjectClass *) class;
245   widget_class = (GtkWidgetClass *) class;
246
247   object_class->finalize = gtk_print_unix_dialog_finalize;
248   object_class->set_property = gtk_print_unix_dialog_set_property;
249   object_class->get_property = gtk_print_unix_dialog_get_property;
250
251   widget_class->style_set = gtk_print_unix_dialog_style_set;
252
253   g_object_class_install_property (object_class,
254                                    PROP_PAGE_SETUP,
255                                    g_param_spec_object ("page-setup",
256                                                         P_("Page Setup"),
257                                                         P_("The GtkPageSetup to use"),
258                                                         GTK_TYPE_PAGE_SETUP,
259                                                         GTK_PARAM_READWRITE));
260
261   g_object_class_install_property (object_class,
262                                    PROP_CURRENT_PAGE,
263                                    g_param_spec_int ("current-page",
264                                                      P_("Current Page"),
265                                                      P_("The current page in the document"),
266                                                      -1,
267                                                      G_MAXINT,
268                                                      -1,
269                                                      GTK_PARAM_READWRITE));
270
271   g_object_class_install_property (object_class,
272                                    PROP_PRINT_SETTINGS,
273                                    g_param_spec_object ("print-settings",
274                                                         P_("Print Settings"),
275                                                         P_("The GtkPrintSettings used for initializing the dialog"),
276                                                         GTK_TYPE_PRINT_SETTINGS,
277                                                         GTK_PARAM_READWRITE));
278
279   g_object_class_install_property (object_class,
280                                    PROP_SELECTED_PRINTER,
281                                    g_param_spec_object ("selected-printer",
282                                                         P_("Selected Printer"),
283                                                         P_("The GtkPrinter which is selected"),
284                                                         GTK_TYPE_PRINTER,
285                                                         GTK_PARAM_READABLE));
286   
287   
288   g_type_class_add_private (class, sizeof (GtkPrintUnixDialogPrivate));  
289 }
290
291 /* Returns a toplevel GtkWindow, or NULL if none */
292 static GtkWindow *
293 get_toplevel (GtkWidget *widget)
294 {
295   GtkWidget *toplevel = NULL;
296
297   toplevel = gtk_widget_get_toplevel (widget);
298   if (!GTK_WIDGET_TOPLEVEL (toplevel))
299     return NULL;
300   else
301     return GTK_WINDOW (toplevel);
302 }
303
304 static void
305 add_custom_button_to_dialog (GtkDialog   *dialog,
306                              const gchar *mnemonic_label,
307                              const gchar *stock_id,
308                              gint         response_id)
309 {
310   GtkWidget *button = NULL;
311
312   button = gtk_button_new_with_mnemonic (mnemonic_label);
313   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
314   gtk_button_set_image (GTK_BUTTON (button),
315                         gtk_image_new_from_stock (stock_id,
316                                                   GTK_ICON_SIZE_BUTTON));
317   gtk_widget_show (button);
318
319   gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, response_id);
320 }
321
322 /* This function handles error messages before printing.
323  */
324 static gboolean
325 error_dialogs (GtkPrintUnixDialog *print_dialog,
326                gint                print_dialog_response_id,
327                gpointer            data)
328 {
329   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
330   GtkPrinterOption          *option = NULL;
331   GtkPrinter                *printer = NULL;
332   GtkWindow                 *toplevel = NULL;
333   GtkWidget                 *dialog = NULL;
334   gchar                     *filename = NULL;
335   gchar                     *basename = NULL;
336   gchar                     *dirname = NULL;
337   int                        response;
338
339   if (print_dialog != NULL && print_dialog_response_id == GTK_RESPONSE_OK)
340     {
341       printer = gtk_print_unix_dialog_get_selected_printer (print_dialog);
342
343       /* Shows overwrite confirmation dialog in the case of printing to file which
344        * already exists. */
345       if (printer != NULL && gtk_printer_is_virtual (printer))
346         {
347           option = gtk_printer_option_set_lookup (priv->options,
348                                                   "gtk-main-page-custom-input");
349
350           if (option != NULL &&
351               option->type == GTK_PRINTER_OPTION_TYPE_FILESAVE)
352             {
353               filename = g_filename_from_uri (option->value, NULL, NULL);
354
355               if (filename != NULL &&
356                   g_file_test (filename, G_FILE_TEST_EXISTS))
357                 {
358                   toplevel = get_toplevel (GTK_WIDGET (print_dialog));
359
360                   basename = g_path_get_basename (filename);
361                   dirname = g_path_get_dirname (filename);
362
363                   dialog = gtk_message_dialog_new (toplevel,
364                                                    GTK_DIALOG_MODAL |
365                                                    GTK_DIALOG_DESTROY_WITH_PARENT,
366                                                    GTK_MESSAGE_QUESTION,
367                                                    GTK_BUTTONS_NONE,
368                                                    _("A file named \"%s\" already exists.  Do you want to replace it?"),
369                                                    basename);
370
371                   gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
372                                                             _("The file already exists in \"%s\".  Replacing it will "
373                                                             "overwrite its contents."),
374                                                             dirname);
375
376                   gtk_dialog_add_button (GTK_DIALOG (dialog),
377                                          GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
378                   add_custom_button_to_dialog (GTK_DIALOG (dialog),
379                                                _("_Replace"),
380                                                GTK_STOCK_PRINT,
381                                                GTK_RESPONSE_ACCEPT);
382                   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
383                                                            GTK_RESPONSE_ACCEPT,
384                                                            GTK_RESPONSE_CANCEL,
385                                                            -1);
386                   gtk_dialog_set_default_response (GTK_DIALOG (dialog),
387                                                    GTK_RESPONSE_ACCEPT);
388
389                   if (toplevel->group)
390                     gtk_window_group_add_window (toplevel->group,
391                                                  GTK_WINDOW (dialog));
392
393                   response = gtk_dialog_run (GTK_DIALOG (dialog));
394
395                   gtk_widget_destroy (dialog);
396
397                   if (response != GTK_RESPONSE_ACCEPT)
398                     {
399                       g_signal_stop_emission_by_name (print_dialog, "response");
400                       return TRUE;
401                     }
402
403                   g_free (dirname);
404                   g_free (basename);
405                 }
406
407               g_free (filename);
408             }
409         }
410     }
411   return FALSE;
412 }
413
414 static void
415 gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
416 {
417   GtkPrintUnixDialogPrivate *priv = dialog->priv;
418
419   priv = dialog->priv = GTK_PRINT_UNIX_DIALOG_GET_PRIVATE (dialog); 
420   priv->print_backends = NULL;
421   priv->current_page = -1;
422   priv->number_up_layout_n_option = NULL;
423   priv->number_up_layout_2_option = NULL;
424
425   priv->page_setup = gtk_page_setup_new ();
426   priv->page_setup_set = FALSE;
427
428   g_signal_connect (dialog, 
429                     "destroy", 
430                     (GCallback) gtk_print_unix_dialog_destroy, 
431                     NULL);
432
433   g_signal_connect (dialog,
434                     "response",
435                     (GCallback) error_dialogs,
436                     NULL);
437
438   priv->preview_button = gtk_button_new_from_stock (GTK_STOCK_PRINT_PREVIEW);
439   gtk_widget_show (priv->preview_button);
440    
441   gtk_dialog_add_action_widget (GTK_DIALOG (dialog), 
442                                 priv->preview_button, 
443                                 GTK_RESPONSE_APPLY);
444   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
445                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
446                           GTK_STOCK_PRINT, GTK_RESPONSE_OK,
447                           NULL);
448   gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
449                                            GTK_RESPONSE_APPLY,
450                                            GTK_RESPONSE_OK,
451                                            GTK_RESPONSE_CANCEL,
452                                            -1);
453
454   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
455   gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
456
457   populate_dialog (dialog);  
458 }
459
460 static void
461 gtk_print_unix_dialog_destroy (GtkPrintUnixDialog *dialog)
462 {
463   /* Make sure we don't destroy custom widgets owned by the backends */
464   clear_per_printer_ui (dialog);  
465 }
466
467 static void
468 disconnect_printer_details_request (GtkPrintUnixDialog *dialog)
469 {
470   GtkPrintUnixDialogPrivate *priv = dialog->priv;
471
472   if (priv->request_details_tag)
473     {
474       g_signal_handler_disconnect (priv->request_details_printer,
475                                    priv->request_details_tag);
476       priv->request_details_tag = 0;
477       g_object_unref (priv->request_details_printer);
478       priv->request_details_printer = NULL;
479     }
480 }
481
482 static void
483 gtk_print_unix_dialog_finalize (GObject *object)
484 {
485   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
486   GtkPrintUnixDialogPrivate *priv = dialog->priv;
487   GtkPrintBackend *backend;
488   GList *node;
489
490   unschedule_idle_mark_conflicts (dialog);
491   disconnect_printer_details_request (dialog);
492
493   if (priv->current_printer)
494     {
495       g_object_unref (priv->current_printer);
496       priv->current_printer = NULL;
497     }
498
499   if (priv->printer_list)
500     {
501       g_object_unref (priv->printer_list);
502       priv->printer_list = NULL;
503     }
504  
505   if (priv->printer_list_filter)
506     {
507       g_object_unref (priv->printer_list_filter);
508       priv->printer_list_filter = NULL;
509     }
510
511  
512   if (priv->options)
513     {
514       g_object_unref (priv->options);
515       priv->options = NULL;
516     }
517  
518   if (priv->number_up_layout_2_option)
519     {
520       priv->number_up_layout_2_option->choices[0] = NULL;
521       priv->number_up_layout_2_option->choices[1] = NULL;
522       g_free (priv->number_up_layout_2_option->choices_display[0]);
523       g_free (priv->number_up_layout_2_option->choices_display[1]);
524       priv->number_up_layout_2_option->choices_display[0] = NULL;
525       priv->number_up_layout_2_option->choices_display[1] = NULL;
526       g_object_unref (priv->number_up_layout_2_option);
527       priv->number_up_layout_2_option = NULL;
528     }
529
530   if (priv->number_up_layout_n_option)
531     {
532       g_object_unref (priv->number_up_layout_n_option);
533       priv->number_up_layout_n_option = NULL;
534     }
535
536  if (priv->page_setup)
537     {
538       g_object_unref (priv->page_setup);
539       priv->page_setup = NULL;
540     }
541
542   if (priv->initial_settings)
543     {
544       g_object_unref (priv->initial_settings);
545       priv->initial_settings = NULL;
546     }
547
548   g_free (priv->waiting_for_printer);
549   priv->waiting_for_printer = NULL;
550   
551   g_free (priv->format_for_printer);
552   priv->format_for_printer = NULL;
553
554   for (node = priv->print_backends; node != NULL; node = node->next)
555     {
556       backend = GTK_PRINT_BACKEND (node->data);
557
558       g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog);
559       g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog);
560       g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog);
561
562       gtk_print_backend_destroy (backend);
563       g_object_unref (backend);
564     }
565   
566   g_list_free (priv->print_backends);
567   priv->print_backends = NULL;
568   
569   G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize (object);
570 }
571
572 static void
573 printer_removed_cb (GtkPrintBackend    *backend, 
574                     GtkPrinter         *printer, 
575                     GtkPrintUnixDialog *dialog)
576 {
577   GtkPrintUnixDialogPrivate *priv = dialog->priv;
578   GtkTreeIter *iter;
579
580   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
581   gtk_list_store_remove (GTK_LIST_STORE (priv->printer_list), iter);
582 }
583
584 static void
585 gtk_print_unix_dialog_buildable_init (GtkBuildableIface *iface)
586 {
587   parent_buildable_iface = g_type_interface_peek_parent (iface);
588
589   iface->get_internal_child = gtk_print_unix_dialog_buildable_get_internal_child;
590 }
591
592 static GObject *
593 gtk_print_unix_dialog_buildable_get_internal_child (GtkBuildable *buildable,
594                                                     GtkBuilder   *builder,
595                                                     const gchar  *childname)
596 {
597   if (strcmp (childname, "notebook") == 0)
598     return G_OBJECT (GTK_PRINT_UNIX_DIALOG (buildable)->priv->notebook);
599
600   return parent_buildable_iface->get_internal_child (buildable, builder, childname);
601 }
602
603 /* This function controls "sensitive" property of GtkCellRenderer based on pause
604  * state of printers. */
605 void set_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
606                                 GtkCellRenderer   *cell,
607                                 GtkTreeModel      *tree_model,
608                                 GtkTreeIter       *iter,
609                                 gpointer           data)
610 {
611   GtkPrinter *printer;
612   
613   gtk_tree_model_get (tree_model, iter, PRINTER_LIST_COL_PRINTER_OBJ, &printer, -1);
614
615   if (printer != NULL && !gtk_printer_is_accepting_jobs (printer))
616     g_object_set (cell,
617                   "sensitive", FALSE,
618                   NULL);
619   else
620     g_object_set (cell,
621                   "sensitive", TRUE,
622                   NULL);
623 }
624
625 static void
626 printer_status_cb (GtkPrintBackend    *backend, 
627                    GtkPrinter         *printer, 
628                    GtkPrintUnixDialog *dialog)
629 {
630   GtkPrintUnixDialogPrivate *priv = dialog->priv;
631   GtkTreeIter *iter;
632   GtkTreeSelection *selection;
633
634   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
635
636   gtk_list_store_set (GTK_LIST_STORE (priv->printer_list), iter,
637                       PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
638                       PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
639                       PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
640                       PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
641                       -1);
642
643   /* When the pause state change then we need to update sensitive property
644    * of GTK_RESPONSE_OK button inside of selected_printer_changed function. */
645   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
646   selected_printer_changed (selection, dialog);
647 }
648
649 static void
650 printer_added_cb (GtkPrintBackend    *backend, 
651                   GtkPrinter         *printer, 
652                   GtkPrintUnixDialog *dialog)
653 {
654   GtkPrintUnixDialogPrivate *priv = dialog->priv;
655   GtkTreeIter iter, filter_iter;
656   GtkTreeSelection *selection;
657   GtkTreePath *path;
658
659   gtk_list_store_append (GTK_LIST_STORE (priv->printer_list), &iter);
660   
661   g_object_set_data_full (G_OBJECT (printer), 
662                          "gtk-print-tree-iter", 
663                           gtk_tree_iter_copy (&iter),
664                           (GDestroyNotify) gtk_tree_iter_free);
665
666   gtk_list_store_set (GTK_LIST_STORE (priv->printer_list), &iter,
667                       PRINTER_LIST_COL_ICON, gtk_printer_get_icon_name (printer),
668                       PRINTER_LIST_COL_NAME, gtk_printer_get_name (printer),
669                       PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
670                       PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
671                       PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
672                       PRINTER_LIST_COL_PRINTER_OBJ, printer,
673                       -1);
674
675   gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
676                                                     &filter_iter, &iter);
677   path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->printer_list_filter), &filter_iter);
678
679   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
680   
681   if (priv->waiting_for_printer != NULL &&
682       strcmp (gtk_printer_get_name (printer),
683               priv->waiting_for_printer) == 0)
684     {
685       priv->internal_printer_change = TRUE;
686       gtk_tree_selection_select_iter (selection, &filter_iter);
687       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->printer_treeview),
688                                     path, NULL, TRUE, 0.5, 0.0);
689       priv->internal_printer_change = FALSE;
690       g_free (priv->waiting_for_printer);
691       priv->waiting_for_printer = NULL;
692     }
693   else if (is_default_printer (dialog, printer) &&
694            gtk_tree_selection_count_selected_rows (selection) == 0)
695     {
696       priv->internal_printer_change = TRUE;
697       gtk_tree_selection_select_iter (selection, &filter_iter);
698       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->printer_treeview),
699                                     path, NULL, TRUE, 0.5, 0.0);
700       priv->internal_printer_change = FALSE;
701     }
702
703   gtk_tree_path_free (path);
704 }
705
706 static void
707 printer_list_initialize (GtkPrintUnixDialog *dialog,
708                          GtkPrintBackend    *print_backend)
709 {
710   GList *list;
711   GList *node;
712
713   g_return_if_fail (print_backend != NULL);
714
715   g_signal_connect_object (print_backend, 
716                            "printer-added", 
717                            (GCallback) printer_added_cb, 
718                            G_OBJECT (dialog), 0);
719
720   g_signal_connect_object (print_backend, 
721                            "printer-removed", 
722                            (GCallback) printer_removed_cb, 
723                            G_OBJECT (dialog), 0);
724
725   g_signal_connect_object (print_backend, 
726                            "printer-status-changed", 
727                            (GCallback) printer_status_cb, 
728                            G_OBJECT (dialog), 0);
729
730   list = gtk_print_backend_get_printer_list (print_backend);
731
732   node = list;
733   while (node != NULL)
734     {
735       printer_added_cb (print_backend, node->data, dialog);
736       node = node->next;
737     }
738
739   g_list_free (list);
740 }
741
742 static void
743 load_print_backends (GtkPrintUnixDialog *dialog)
744 {
745   GtkPrintUnixDialogPrivate *priv = dialog->priv;
746   GList *node;
747
748   if (g_module_supported ())
749     priv->print_backends = gtk_print_backend_load_modules ();
750
751   for (node = priv->print_backends; node != NULL; node = node->next)
752     printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
753 }
754
755 static void
756 gtk_print_unix_dialog_set_property (GObject      *object,
757                                     guint         prop_id,
758                                     const GValue *value,
759                                     GParamSpec   *pspec)
760
761 {
762   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
763
764   switch (prop_id)
765     {
766     case PROP_PAGE_SETUP:
767       gtk_print_unix_dialog_set_page_setup (dialog, g_value_get_object (value));
768       break;
769     case PROP_CURRENT_PAGE:
770       gtk_print_unix_dialog_set_current_page (dialog, g_value_get_int (value));
771       break;
772     case PROP_PRINT_SETTINGS:
773       gtk_print_unix_dialog_set_settings (dialog, g_value_get_object (value));
774       break;
775     default:
776       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
777       break;
778     }
779 }
780
781 static void
782 gtk_print_unix_dialog_get_property (GObject    *object,
783                                     guint       prop_id,
784                                     GValue     *value,
785                                     GParamSpec *pspec)
786 {
787   GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
788   GtkPrintUnixDialogPrivate *priv = dialog->priv;
789
790   switch (prop_id)
791     {
792     case PROP_PAGE_SETUP:
793       g_value_set_object (value, priv->page_setup);
794       break;
795     case PROP_CURRENT_PAGE:
796       g_value_set_int (value, priv->current_page);
797       break;
798     case PROP_PRINT_SETTINGS:
799       g_value_take_object (value, gtk_print_unix_dialog_get_settings (dialog));
800       break;
801     case PROP_SELECTED_PRINTER:
802       g_value_set_object (value, priv->current_printer);
803       break;
804     default:
805       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
806       break;
807     }
808 }
809
810 static gboolean
811 is_printer_active (GtkTreeModel       *model,
812                    GtkTreeIter        *iter,
813                    GtkPrintUnixDialog *dialog)
814 {
815   gboolean result;
816   GtkPrinter *printer;
817   GtkPrintUnixDialogPrivate *priv = dialog->priv;
818
819   gtk_tree_model_get (model,
820                       iter,
821                       PRINTER_LIST_COL_PRINTER_OBJ,
822                       &printer,
823                       -1);
824   
825   if (printer == NULL)
826     return FALSE;
827
828   result = gtk_printer_is_active (printer);
829   
830   if (result && 
831       priv->manual_capabilities & (GTK_PRINT_CAPABILITY_GENERATE_PDF |
832                                    GTK_PRINT_CAPABILITY_GENERATE_PS))
833     {
834        /* Check that the printer can handle at least one of the data 
835         * formats that the application supports.
836         */
837        result = ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PDF) &&
838                  gtk_printer_accepts_pdf (printer)) ||
839                 ((priv->manual_capabilities & GTK_PRINT_CAPABILITY_GENERATE_PS) &&
840                  gtk_printer_accepts_ps (printer));
841     }
842   
843   g_object_unref (printer);
844   
845   return result;
846 }
847
848 static gint
849 default_printer_list_sort_func (GtkTreeModel *model,
850                                 GtkTreeIter  *a,
851                                 GtkTreeIter  *b,
852                                 gpointer      user_data)
853 {
854   gchar *a_name;
855   gchar *b_name;
856   GtkPrinter *a_printer;
857   GtkPrinter *b_printer;
858   gint result;
859
860   gtk_tree_model_get (model, a, 
861                       PRINTER_LIST_COL_NAME, &a_name, 
862                       PRINTER_LIST_COL_PRINTER_OBJ, &a_printer,
863                       -1);
864   gtk_tree_model_get (model, b, 
865                       PRINTER_LIST_COL_NAME, &b_name,
866                       PRINTER_LIST_COL_PRINTER_OBJ, &b_printer,
867                       -1);
868
869   if (a_printer == NULL && b_printer == NULL)
870     result = 0;
871   else if (a_printer == NULL)
872    result = G_MAXINT;
873   else if (b_printer == NULL)
874    result = G_MININT;
875   else if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
876     result = 0;
877   else if (gtk_printer_is_virtual (a_printer) && !gtk_printer_is_virtual (b_printer))
878     result = G_MININT;
879   else if (!gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
880     result = G_MAXINT;
881   else if (a_name == NULL && b_name == NULL)
882     result = 0;
883   else if (a_name == NULL && b_name != NULL)
884     result = 1;
885   else if (a_name != NULL && b_name == NULL)
886     result = -1;
887   else
888     result = g_ascii_strcasecmp (a_name, b_name);
889
890   g_free (a_name);
891   g_free (b_name);
892   g_object_unref (a_printer);
893   g_object_unref (b_printer);
894
895   return result;
896 }
897
898
899 static void
900 create_printer_list_model (GtkPrintUnixDialog *dialog)
901 {
902   GtkPrintUnixDialogPrivate *priv = dialog->priv;
903   GtkListStore *model;
904   GtkTreeSortable *sort;
905
906   model = gtk_list_store_new (PRINTER_LIST_N_COLS,
907                               G_TYPE_STRING,
908                               G_TYPE_STRING, 
909                               G_TYPE_STRING, 
910                               G_TYPE_INT, 
911                               G_TYPE_STRING,
912                               G_TYPE_OBJECT);
913
914   priv->printer_list = (GtkTreeModel *)model;
915   priv->printer_list_filter = (GtkTreeModelFilter *) gtk_tree_model_filter_new ((GtkTreeModel *)model,
916                                                                                         NULL);
917
918   gtk_tree_model_filter_set_visible_func (priv->printer_list_filter,
919                                           (GtkTreeModelFilterVisibleFunc) is_printer_active,
920                                           dialog,
921                                           NULL);
922
923   sort = GTK_TREE_SORTABLE (model);
924   gtk_tree_sortable_set_default_sort_func (sort,
925                                            default_printer_list_sort_func,
926                                            NULL,
927                                            NULL);
928  
929   gtk_tree_sortable_set_sort_column_id (sort,
930                                         GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
931                                         GTK_SORT_ASCENDING);
932
933 }
934
935
936 static GtkWidget *
937 wrap_in_frame (const gchar *label, 
938                GtkWidget   *child)
939 {
940   GtkWidget *frame, *alignment, *label_widget;
941   gchar *bold_text;
942
943   label_widget = gtk_label_new (NULL);
944   gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
945   gtk_widget_show (label_widget);
946   
947   bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
948   gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
949   g_free (bold_text);
950   
951   frame = gtk_vbox_new (FALSE, 6);
952   gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
953   
954   alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
955   gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
956                              0, 0, 12, 0);
957   gtk_box_pack_start (GTK_BOX (frame), alignment, FALSE, FALSE, 0);
958
959   gtk_container_add (GTK_CONTAINER (alignment), child);
960
961   gtk_widget_show (frame);
962   gtk_widget_show (alignment);
963   
964   return frame;
965 }
966
967 static gboolean
968 setup_option (GtkPrintUnixDialog     *dialog,
969               const gchar            *option_name,
970               GtkPrinterOptionWidget *widget)
971 {
972   GtkPrintUnixDialogPrivate *priv = dialog->priv;
973   GtkPrinterOption *option;
974
975   option = gtk_printer_option_set_lookup (priv->options, option_name);
976   gtk_printer_option_widget_set_source (widget, option);
977
978   return option != NULL;
979 }
980
981 static void
982 add_option_to_extension_point (GtkPrinterOption *option,
983                                gpointer          data)
984 {
985   GtkWidget *extension_point = data;
986   GtkWidget *widget;
987
988   widget = gtk_printer_option_widget_new (option);
989   gtk_widget_show (widget);
990    
991   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
992     {
993       GtkWidget *label, *hbox;
994       
995       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
996       gtk_widget_show (label);
997       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
998       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
999       
1000       hbox = gtk_hbox_new (FALSE, 12);
1001       gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1002       gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
1003       gtk_widget_show (hbox);
1004       
1005       gtk_box_pack_start (GTK_BOX (extension_point), hbox, FALSE, FALSE, 0);
1006     }
1007   else
1008     gtk_box_pack_start (GTK_BOX (extension_point), widget, FALSE, FALSE, 0);
1009 }
1010
1011 static void
1012 add_option_to_table (GtkPrinterOption *option,
1013                      gpointer          user_data)
1014 {
1015   GtkTable *table;
1016   GtkWidget *label, *widget;
1017   gint row;
1018
1019   table = GTK_TABLE (user_data);
1020   
1021   if (g_str_has_prefix (option->name, "gtk-"))
1022     return;
1023   
1024   widget = gtk_printer_option_widget_new (option);
1025   gtk_widget_show (widget);
1026
1027   row = table->nrows;
1028   gtk_table_resize (table, table->nrows + 1, 2);
1029   
1030   if (gtk_printer_option_widget_has_external_label (GTK_PRINTER_OPTION_WIDGET (widget)))
1031     {
1032       label = gtk_printer_option_widget_get_external_label (GTK_PRINTER_OPTION_WIDGET (widget));
1033       gtk_widget_show (label);
1034
1035       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1036       gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
1037
1038       gtk_table_attach (table, label,
1039                         0, 1, row - 1 , row,  GTK_FILL, 0, 0, 0);
1040       
1041       gtk_table_attach (table, widget,
1042                         1, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
1043     }
1044   else
1045     gtk_table_attach (table, widget,
1046                       0, 2, row - 1, row,  GTK_FILL, 0, 0, 0);
1047 }
1048
1049
1050 static void
1051 setup_page_table (GtkPrinterOptionSet *options,
1052                   const gchar         *group,
1053                   GtkWidget           *table,
1054                   GtkWidget           *page)
1055 {
1056   gtk_printer_option_set_foreach_in_group (options, group,
1057                                            add_option_to_table,
1058                                            table);
1059   if (GTK_TABLE (table)->nrows == 1)
1060     gtk_widget_hide (page);
1061   else
1062     gtk_widget_show (page);
1063 }
1064
1065 static void
1066 update_print_at_option (GtkPrintUnixDialog *dialog)
1067 {
1068   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1069   GtkPrinterOption *option;
1070   
1071   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
1072
1073   if (option == NULL)
1074     return;
1075   
1076   if (priv->updating_print_at)
1077     return;
1078   
1079   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_at_radio)))
1080     gtk_printer_option_set (option, "at");
1081   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio)))
1082     gtk_printer_option_set (option, "on-hold");
1083   else
1084     gtk_printer_option_set (option, "now");
1085   
1086   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
1087   if (option != NULL)
1088     {
1089       const char *text = gtk_entry_get_text (GTK_ENTRY (priv->print_at_entry));
1090       gtk_printer_option_set (option,text);
1091     }
1092 }
1093
1094
1095 static gboolean
1096 setup_print_at (GtkPrintUnixDialog *dialog)
1097 {
1098   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1099   GtkPrinterOption *option;
1100   
1101   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time");
1102  
1103   if (option == NULL)
1104     {
1105       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
1106                                     TRUE);
1107       gtk_widget_set_sensitive (priv->print_at_radio, FALSE);
1108       gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
1109       gtk_widget_set_sensitive (priv->print_hold_radio, FALSE);
1110       gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry), "");
1111       return FALSE;
1112     }
1113
1114   priv->updating_print_at = TRUE;
1115   
1116   if (gtk_printer_option_has_choice (option, "at"))
1117     {
1118       gtk_widget_set_sensitive (priv->print_at_radio, TRUE);
1119       gtk_widget_set_sensitive (priv->print_at_entry, TRUE);
1120     }
1121   else
1122     {
1123       gtk_widget_set_sensitive (priv->print_at_radio, FALSE);
1124       gtk_widget_set_sensitive (priv->print_at_entry, FALSE);
1125     }
1126   
1127   gtk_widget_set_sensitive (priv->print_hold_radio,
1128                             gtk_printer_option_has_choice (option, "on-hold"));
1129
1130   update_print_at_option (dialog);
1131
1132   if (strcmp (option->value, "at") == 0)
1133     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_at_radio),
1134                                   TRUE);
1135   else if (strcmp (option->value, "on-hold") == 0)
1136     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_hold_radio),
1137                                   TRUE);
1138   else
1139     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->print_now_radio),
1140                                   TRUE);
1141
1142   option = gtk_printer_option_set_lookup (priv->options, "gtk-print-time-text");
1143   if (option != NULL)
1144     gtk_entry_set_text (GTK_ENTRY (priv->print_at_entry),
1145                         option->value);
1146   
1147
1148   priv->updating_print_at = FALSE;
1149
1150   return TRUE;
1151 }
1152              
1153 static void
1154 update_dialog_from_settings (GtkPrintUnixDialog *dialog)
1155 {
1156   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1157   GList *groups, *l;
1158   gchar *group;
1159   GtkWidget *table, *frame;
1160   gboolean has_advanced, has_job;
1161  
1162   if (priv->current_printer == NULL)
1163     {
1164        clear_per_printer_ui (dialog);
1165        gtk_widget_hide (priv->job_page);
1166        gtk_widget_hide (priv->advanced_page);
1167        gtk_widget_hide (priv->image_quality_page);
1168        gtk_widget_hide (priv->finishing_page);
1169        gtk_widget_hide (priv->color_page);
1170        gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1171
1172        return;
1173     }
1174  
1175   setup_option (dialog, "gtk-n-up", priv->pages_per_sheet);
1176   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
1177   setup_option (dialog, "gtk-duplex", priv->duplex);
1178   setup_option (dialog, "gtk-paper-type", priv->paper_type);
1179   setup_option (dialog, "gtk-paper-source", priv->paper_source);
1180   setup_option (dialog, "gtk-output-tray", priv->output_tray);
1181
1182   has_job = FALSE;
1183   has_job |= setup_option (dialog, "gtk-job-prio", priv->job_prio);
1184   has_job |= setup_option (dialog, "gtk-billing-info", priv->billing_info);
1185   has_job |= setup_option (dialog, "gtk-cover-before", priv->cover_before);
1186   has_job |= setup_option (dialog, "gtk-cover-after", priv->cover_after);
1187   has_job |= setup_print_at (dialog);
1188   
1189   if (has_job)
1190     gtk_widget_show (priv->job_page);
1191   else
1192     gtk_widget_hide (priv->job_page);
1193
1194   
1195   setup_page_table (priv->options,
1196                     "ImageQualityPage",
1197                     priv->image_quality_table,
1198                     priv->image_quality_page);
1199   
1200   setup_page_table (priv->options,
1201                     "FinishingPage",
1202                     priv->finishing_table,
1203                     priv->finishing_page);
1204
1205   setup_page_table (priv->options,
1206                     "ColorPage",
1207                     priv->color_table,
1208                     priv->color_page);
1209
1210   gtk_printer_option_set_foreach_in_group (priv->options,
1211                                            "GtkPrintDialogExtension",
1212                                            add_option_to_extension_point,
1213                                            priv->extension_point);
1214
1215   /* Put the rest of the groups in the advanced page */
1216   groups = gtk_printer_option_set_get_groups (priv->options);
1217
1218   has_advanced = FALSE;
1219   for (l = groups; l != NULL; l = l->next)
1220     {
1221       group = l->data;
1222
1223       if (group == NULL)
1224         continue;
1225       
1226       if (strcmp (group, "ImageQualityPage") == 0 ||
1227           strcmp (group, "ColorPage") == 0 ||
1228           strcmp (group, "FinishingPage") == 0 ||
1229           strcmp (group, "GtkPrintDialogExtension") == 0)
1230         continue;
1231
1232       table = gtk_table_new (1, 2, FALSE);
1233       gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1234       gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1235       
1236       gtk_printer_option_set_foreach_in_group (priv->options,
1237                                                group,
1238                                                add_option_to_table,
1239                                                table);
1240       if (GTK_TABLE (table)->nrows == 1)
1241         gtk_widget_destroy (table);
1242       else
1243         {
1244           has_advanced = TRUE;
1245           frame = wrap_in_frame (group, table);
1246           gtk_widget_show (table);
1247           gtk_widget_show (frame);
1248           
1249           gtk_box_pack_start (GTK_BOX (priv->advanced_vbox),
1250                               frame, FALSE, FALSE, 0);
1251         }
1252     }
1253
1254   if (has_advanced)
1255     gtk_widget_show (priv->advanced_page);
1256   else
1257     gtk_widget_hide (priv->advanced_page);
1258
1259   
1260   g_list_foreach (groups, (GFunc) g_free, NULL);
1261   g_list_free (groups);
1262 }
1263
1264 static void
1265 update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
1266 {
1267   GtkPrintCapabilities caps;
1268   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1269   gboolean can_collate;
1270   const gchar *copies;
1271
1272   copies = gtk_entry_get_text (GTK_ENTRY (priv->copies_spin));
1273   can_collate = (*copies != '\0' && atoi (copies) > 1);
1274
1275   caps = priv->manual_capabilities | priv->printer_capabilities;
1276
1277   gtk_widget_set_sensitive (priv->page_set_combo,
1278                             caps & GTK_PRINT_CAPABILITY_PAGE_SET);
1279   gtk_widget_set_sensitive (priv->copies_spin,
1280                             caps & GTK_PRINT_CAPABILITY_COPIES);
1281   gtk_widget_set_sensitive (priv->collate_check,
1282                             can_collate && 
1283                             (caps & GTK_PRINT_CAPABILITY_COLLATE));
1284   gtk_widget_set_sensitive (priv->reverse_check,
1285                             caps & GTK_PRINT_CAPABILITY_REVERSE);
1286   gtk_widget_set_sensitive (priv->scale_spin,
1287                             caps & GTK_PRINT_CAPABILITY_SCALE);
1288   gtk_widget_set_sensitive (GTK_WIDGET (priv->pages_per_sheet),
1289                             caps & GTK_PRINT_CAPABILITY_NUMBER_UP);
1290
1291   if (caps & GTK_PRINT_CAPABILITY_PREVIEW)
1292     gtk_widget_show (priv->preview_button);
1293   else
1294     gtk_widget_hide (priv->preview_button);
1295
1296   update_collate_icon (NULL, dialog);
1297
1298   gtk_tree_model_filter_refilter (priv->printer_list_filter);
1299 }
1300
1301 static void
1302 mark_conflicts (GtkPrintUnixDialog *dialog)
1303 {
1304   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1305   GtkPrinter *printer;
1306   gboolean have_conflict;
1307
1308   have_conflict = FALSE;
1309
1310   printer = priv->current_printer;
1311
1312   if (printer)
1313     {
1314
1315       g_signal_handler_block (priv->options,
1316                               priv->options_changed_handler);
1317       
1318       gtk_printer_option_set_clear_conflicts (priv->options);
1319       
1320       have_conflict = _gtk_printer_mark_conflicts (printer,
1321                                                    priv->options);
1322       
1323       g_signal_handler_unblock (priv->options,
1324                                 priv->options_changed_handler);
1325     }
1326
1327   if (have_conflict)
1328     gtk_widget_show (priv->conflicts_widget);
1329   else
1330     gtk_widget_hide (priv->conflicts_widget);
1331 }
1332
1333 static gboolean
1334 mark_conflicts_callback (gpointer data)
1335 {
1336   GtkPrintUnixDialog *dialog = data;
1337   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1338
1339   priv->mark_conflicts_id = 0;
1340
1341   mark_conflicts (dialog);
1342
1343   return FALSE;
1344 }
1345
1346 static void
1347 unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1348 {
1349   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1350
1351   if (priv->mark_conflicts_id != 0)
1352     {
1353       g_source_remove (priv->mark_conflicts_id);
1354       priv->mark_conflicts_id = 0;
1355     }
1356 }
1357
1358 static void
1359 schedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog)
1360 {
1361   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1362
1363   if (priv->mark_conflicts_id != 0)
1364     return;
1365
1366   priv->mark_conflicts_id = gdk_threads_add_idle (mark_conflicts_callback,
1367                                         dialog);
1368 }
1369
1370 static void
1371 options_changed_cb (GtkPrintUnixDialog *dialog)
1372 {
1373   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1374
1375   schedule_idle_mark_conflicts (dialog);
1376
1377   if (priv->initial_settings)
1378     {
1379       g_object_unref (priv->initial_settings);
1380       priv->initial_settings = NULL;
1381     }
1382
1383   g_free (priv->waiting_for_printer);
1384   priv->waiting_for_printer = NULL;
1385 }
1386
1387 static void
1388 remove_custom_widget (GtkWidget    *widget,
1389                       GtkContainer *container)
1390 {
1391   gtk_container_remove (container, widget);
1392 }
1393
1394 static void
1395 extension_point_clear_children (GtkContainer *container)
1396 {
1397   gtk_container_foreach (container,
1398                          (GtkCallback)remove_custom_widget,
1399                          container);
1400 }
1401
1402 static void
1403 clear_per_printer_ui (GtkPrintUnixDialog *dialog)
1404 {
1405   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1406
1407   gtk_container_foreach (GTK_CONTAINER (priv->finishing_table),
1408                          (GtkCallback)gtk_widget_destroy,
1409                          NULL);
1410   gtk_table_resize (GTK_TABLE (priv->finishing_table), 1, 2);
1411   gtk_container_foreach (GTK_CONTAINER (priv->image_quality_table),
1412                          (GtkCallback)gtk_widget_destroy,
1413                          NULL);
1414   gtk_table_resize (GTK_TABLE (priv->image_quality_table), 1, 2);
1415   gtk_container_foreach (GTK_CONTAINER (priv->color_table),
1416                          (GtkCallback)gtk_widget_destroy,
1417                          NULL);
1418   gtk_table_resize (GTK_TABLE (priv->color_table), 1, 2);
1419   gtk_container_foreach (GTK_CONTAINER (priv->advanced_vbox),
1420                          (GtkCallback)gtk_widget_destroy,
1421                          NULL);
1422   extension_point_clear_children (GTK_CONTAINER (priv->extension_point));
1423 }
1424
1425 static void
1426 printer_details_acquired (GtkPrinter         *printer,
1427                           gboolean            success,
1428                           GtkPrintUnixDialog *dialog)
1429 {
1430   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1431
1432   disconnect_printer_details_request (dialog);
1433   
1434   if (success)
1435     {
1436       GtkTreeSelection *selection;
1437       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
1438       
1439       selected_printer_changed (selection, dialog);
1440     }
1441 }
1442
1443 static void
1444 selected_printer_changed (GtkTreeSelection   *selection,
1445                           GtkPrintUnixDialog *dialog)
1446 {
1447   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1448   GtkPrinter *printer;
1449   GtkTreeIter iter, filter_iter;
1450
1451   /* Whenever the user selects a printer we stop looking for
1452      the printer specified in the initial settings */
1453   if (priv->waiting_for_printer &&
1454       !priv->internal_printer_change)
1455     {
1456       g_free (priv->waiting_for_printer);
1457       priv->waiting_for_printer = NULL;
1458     }
1459
1460   disconnect_printer_details_request (dialog);
1461
1462   printer = NULL;
1463   if (gtk_tree_selection_get_selected (selection, NULL, &filter_iter))
1464     {
1465       gtk_tree_model_filter_convert_iter_to_child_iter (priv->printer_list_filter,
1466                                                         &iter,
1467                                                         &filter_iter);
1468
1469       gtk_tree_model_get (priv->printer_list, &iter,
1470                           PRINTER_LIST_COL_PRINTER_OBJ, &printer,
1471                           -1);
1472     }
1473
1474   /* sets GTK_RESPONSE_OK button sensitive/insensitive depending on whether the printer 
1475    * accepts/rejects jobs */
1476   if (printer != NULL)
1477     {
1478       if (!gtk_printer_is_accepting_jobs (printer))
1479         {
1480           gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1481         }
1482       else
1483         {
1484           if (priv->current_printer == printer && gtk_printer_has_details (printer))
1485             gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1486         }
1487     }
1488   
1489   if (printer != NULL && !gtk_printer_has_details (printer))
1490     {
1491       gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
1492       priv->request_details_tag =
1493         g_signal_connect (printer, "details-acquired",
1494                           G_CALLBACK (printer_details_acquired), dialog);
1495       /* take the reference */
1496       priv->request_details_printer = printer;
1497       gtk_printer_request_details (printer);
1498       return;
1499     }
1500   
1501   if (printer == priv->current_printer)
1502     {
1503       if (printer)
1504         g_object_unref (printer);
1505       return;
1506     }
1507
1508   if (priv->options)
1509     {
1510       g_object_unref (priv->options);
1511       priv->options = NULL;  
1512
1513       clear_per_printer_ui (dialog);
1514     }
1515
1516   if (priv->current_printer)
1517     {
1518       g_object_unref (priv->current_printer);
1519     }
1520
1521   priv->printer_capabilities = 0;
1522   
1523   if (gtk_printer_is_accepting_jobs (printer))
1524     gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
1525   priv->current_printer = printer;
1526
1527   if (printer != NULL)
1528     {
1529       if (!priv->page_setup_set)
1530         {
1531           /* if no explicit page setup has been set, use the printer default */   
1532           GtkPageSetup *page_setup;
1533
1534           page_setup = gtk_printer_get_default_page_size (printer);
1535
1536           if (!page_setup)
1537             page_setup = gtk_page_setup_new ();
1538
1539           g_object_unref (priv->page_setup);
1540           priv->page_setup = page_setup;
1541         }
1542
1543       priv->printer_capabilities = gtk_printer_get_capabilities (printer);
1544       priv->options = _gtk_printer_get_options (printer, 
1545                                                 priv->initial_settings,
1546                                                 priv->page_setup,
1547                                                 priv->manual_capabilities);
1548   
1549       priv->options_changed_handler = 
1550         g_signal_connect_swapped (priv->options, "changed", G_CALLBACK (options_changed_cb), dialog);
1551     }
1552
1553   update_dialog_from_settings (dialog);
1554   update_dialog_from_capabilities (dialog);
1555 }
1556
1557 static void
1558 update_collate_icon (GtkToggleButton    *toggle_button,
1559                      GtkPrintUnixDialog *dialog)
1560 {
1561   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1562
1563   gtk_widget_queue_draw (priv->collate_image);
1564 }
1565
1566 static void
1567 paint_page (GtkWidget *widget,
1568             cairo_t   *cr, 
1569             gfloat     scale,
1570             gint       x_offset, 
1571             gint       y_offset,
1572             gchar     *text,
1573             gint       text_x)
1574 {
1575   gint x, y, width, height;
1576   gint text_y, linewidth;
1577
1578   x = x_offset * scale;
1579   y = y_offset * scale;
1580   width = 20 * scale;
1581   height = 26 * scale;
1582
1583   linewidth = 2;
1584   text_y = 21;
1585
1586   gdk_cairo_set_source_color (cr, &widget->style->base[GTK_STATE_NORMAL]);
1587   cairo_rectangle (cr, x, y, width, height);
1588   cairo_fill (cr);
1589
1590   gdk_cairo_set_source_color (cr, &widget->style->text[GTK_STATE_NORMAL]);
1591   cairo_set_line_width (cr, linewidth);
1592   cairo_rectangle (cr, x + linewidth/2.0, y + linewidth/2.0, width - linewidth, height - linewidth);
1593   cairo_stroke (cr);
1594
1595   cairo_select_font_face (cr, "Sans", 
1596                           CAIRO_FONT_SLANT_NORMAL,
1597                           CAIRO_FONT_WEIGHT_NORMAL);
1598   cairo_set_font_size (cr, (gint)(9 * scale));
1599   cairo_move_to (cr, x + (gint)(text_x * scale), y + (gint)(text_y * scale));
1600   cairo_show_text (cr, text);
1601 }
1602
1603
1604 static gboolean
1605 draw_collate_cb (GtkWidget          *widget,
1606                  GdkEventExpose     *event,
1607                  GtkPrintUnixDialog *dialog)
1608 {
1609   GtkSettings *settings;
1610   cairo_t *cr;
1611   gint size;
1612   gfloat scale;
1613   gboolean collate, reverse, rtl;
1614   gint copies;
1615   gint text_x;
1616
1617   collate = dialog_get_collate (dialog);
1618   reverse = dialog_get_reverse (dialog);
1619   copies = dialog_get_n_copies (dialog);
1620
1621   rtl = (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL);
1622
1623   settings = gtk_widget_get_settings (widget);
1624   gtk_icon_size_lookup_for_settings (settings,
1625                                      GTK_ICON_SIZE_DIALOG,
1626                                      &size,
1627                                      NULL);
1628   scale = size / 48.0;
1629   text_x = rtl ? 4 : 11;
1630
1631   cr = gdk_cairo_create (widget->window);
1632
1633   cairo_translate (cr, widget->allocation.x, widget->allocation.y);
1634
1635   if (copies == 1)
1636     {
1637       paint_page (widget, cr, scale, rtl ? 40: 15, 5, reverse ? "1" : "2", text_x);
1638       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
1639     }
1640   else
1641     {
1642       paint_page (widget, cr, scale, rtl ? 40: 15, 5, collate == reverse ? "1" : "2", text_x);
1643       paint_page (widget, cr, scale, rtl ? 50: 5, 15, reverse ? "2" : "1", text_x);
1644
1645       paint_page (widget, cr, scale, rtl ? 5 : 50, 5, reverse ? "1" : "2", text_x);
1646       paint_page (widget, cr, scale, rtl ? 15 : 40, 15, collate == reverse ? "2" : "1", text_x);
1647     }
1648
1649   cairo_destroy (cr);
1650
1651   return TRUE;
1652 }
1653
1654 static void
1655 gtk_print_unix_dialog_style_set (GtkWidget *widget,
1656                                  GtkStyle  *previous_style)
1657 {
1658   GTK_WIDGET_CLASS (gtk_print_unix_dialog_parent_class)->style_set (widget, previous_style);
1659
1660   if (gtk_widget_has_screen (widget))
1661     {
1662       GtkPrintUnixDialog *dialog = (GtkPrintUnixDialog *)widget;
1663       GtkPrintUnixDialogPrivate *priv = dialog->priv;
1664       GtkSettings *settings;
1665       gint size;
1666       gfloat scale;
1667       
1668       settings = gtk_widget_get_settings (widget);
1669       gtk_icon_size_lookup_for_settings (settings,
1670                                          GTK_ICON_SIZE_DIALOG,
1671                                          &size,
1672                                          NULL);
1673       scale = size / 48.0;
1674       
1675       gtk_widget_set_size_request (priv->collate_image, 
1676                                    (50 + 20) * scale,
1677                                    (15 + 26) * scale);
1678     }
1679 }
1680
1681 static void
1682 update_range_sensitivity (GtkWidget *button,
1683                           GtkWidget *range)
1684 {
1685   gboolean active;
1686
1687   active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
1688
1689   gtk_widget_set_sensitive (range, active);
1690 }
1691
1692 static void
1693 create_main_page (GtkPrintUnixDialog *dialog)
1694 {
1695   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1696   GtkWidget *main_vbox, *label, *vbox, *hbox;
1697   GtkWidget *scrolled, *treeview, *frame, *table;
1698   GtkWidget *entry, *spinbutton;
1699   GtkWidget *radio, *check, *image;
1700   GtkCellRenderer *renderer;
1701   GtkTreeViewColumn *column;
1702   GtkTreeSelection *selection;
1703   GtkWidget *custom_input;
1704
1705   main_vbox = gtk_vbox_new (FALSE, 18);
1706   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
1707   gtk_widget_show (main_vbox);
1708
1709   vbox = gtk_vbox_new (FALSE, 6);
1710   gtk_box_pack_start (GTK_BOX (main_vbox), vbox, TRUE, TRUE, 0);
1711   gtk_widget_show (vbox);
1712
1713   scrolled = gtk_scrolled_window_new (NULL, NULL);
1714   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1715                                   GTK_POLICY_AUTOMATIC,
1716                                   GTK_POLICY_AUTOMATIC);
1717   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1718                                        GTK_SHADOW_IN);
1719   gtk_widget_show (scrolled);
1720   gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1721
1722   treeview = gtk_tree_view_new_with_model ((GtkTreeModel *) priv->printer_list_filter);
1723   priv->printer_treeview = treeview;
1724   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), TRUE);
1725   gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview), PRINTER_LIST_COL_NAME);
1726   gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
1727   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1728   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1729   g_signal_connect (selection, "changed", G_CALLBACK (selected_printer_changed), dialog);
1730  
1731   renderer = gtk_cell_renderer_pixbuf_new ();
1732   column = gtk_tree_view_column_new_with_attributes ("",
1733                                                      renderer,
1734                                                      "icon-name",
1735                                                      PRINTER_LIST_COL_ICON,
1736                                                      NULL);
1737   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1738   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1739
1740   renderer = gtk_cell_renderer_text_new ();
1741   column = gtk_tree_view_column_new_with_attributes (_("Printer"),
1742                                                      renderer,
1743                                                      "text",
1744                                                      PRINTER_LIST_COL_NAME,
1745                                                      NULL);
1746   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1747   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1748   
1749   renderer = gtk_cell_renderer_text_new ();
1750   /* Translators: this is the header for the location column in the print dialog */
1751   column = gtk_tree_view_column_new_with_attributes (_("Location"),
1752                                                      renderer,
1753                                                      "text",
1754                                                      PRINTER_LIST_COL_LOCATION,
1755                                                      NULL);
1756   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1757   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1758
1759   renderer = gtk_cell_renderer_text_new ();
1760   g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
1761   /* Translators: this is the header for the printer status column in the print dialog */
1762   column = gtk_tree_view_column_new_with_attributes (_("Status"),
1763                                                      renderer,
1764                                                      "text",
1765                                                      PRINTER_LIST_COL_STATE,
1766                                                      NULL);
1767   gtk_tree_view_column_set_cell_data_func (column, renderer, set_cell_sensitivity_func, NULL, NULL);
1768   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1769   
1770   gtk_widget_show (treeview);
1771   gtk_container_add (GTK_CONTAINER (scrolled), treeview);
1772
1773   custom_input = gtk_hbox_new (FALSE, 18);
1774   gtk_widget_show (custom_input);
1775   gtk_box_pack_start (GTK_BOX (vbox), custom_input, FALSE, FALSE, 0);
1776   priv->extension_point = custom_input;
1777
1778   hbox = gtk_hbox_new (FALSE, 18);
1779   gtk_widget_show (hbox);
1780   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
1781
1782   table = gtk_table_new (3, 2, FALSE);
1783   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1784   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1785   frame = wrap_in_frame (_("Range"), table);
1786   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1787   gtk_widget_show (table);
1788
1789   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_All Pages"));
1790   priv->all_pages_radio = radio;
1791   gtk_widget_show (radio);
1792   gtk_table_attach (GTK_TABLE (table), radio,
1793                     0, 2, 0, 1,  GTK_FILL, 0,
1794                     0, 0);
1795   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
1796                                               _("C_urrent Page"));
1797   if (priv->current_page == -1)
1798     gtk_widget_set_sensitive (radio, FALSE);    
1799   priv->current_page_radio = radio;
1800   gtk_widget_show (radio);
1801   gtk_table_attach (GTK_TABLE (table), radio,
1802                     0, 2, 1, 2,  GTK_FILL, 0,
1803                     0, 0);
1804  
1805   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)), _("Pag_es:"));
1806   gtk_widget_set_tooltip_text (radio, _("Specify one or more page ranges,\n e.g. 1-3,7,11"));
1807  
1808   priv->page_range_radio = radio;
1809   gtk_widget_show (radio);
1810   gtk_table_attach (GTK_TABLE (table), radio,
1811                     0, 1, 2, 3,  GTK_FILL, 0,
1812                     0, 0);
1813   entry = gtk_entry_new ();
1814   priv->page_range_entry = entry;
1815   gtk_widget_show (entry);
1816   gtk_table_attach (GTK_TABLE (table), entry,
1817                     1, 2, 2, 3,  GTK_FILL, 0,
1818                     0, 0);
1819   g_signal_connect (radio, "toggled", G_CALLBACK (update_range_sensitivity), entry);
1820   update_range_sensitivity (radio, entry);
1821
1822   table = gtk_table_new (3, 2, FALSE);
1823   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
1824   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
1825   frame = wrap_in_frame (_("Copies"), table);
1826   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
1827   gtk_widget_show (table);
1828
1829   /* FIXME chpe: too much space between Copies and spinbutton, put those 2 in a hbox and make it span 2 columns */
1830   label = gtk_label_new_with_mnemonic (_("Copie_s:"));
1831   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
1832   gtk_widget_show (label);
1833   gtk_table_attach (GTK_TABLE (table), label,
1834                     0, 1, 0, 1,  GTK_FILL, 0,
1835                     0, 0);
1836   spinbutton = gtk_spin_button_new_with_range (1.0, 100.0, 1.0);
1837   priv->copies_spin = spinbutton;
1838   gtk_widget_show (spinbutton);
1839   gtk_table_attach (GTK_TABLE (table), spinbutton,
1840                     1, 2, 0, 1,  GTK_FILL, 0,
1841                     0, 0);
1842   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
1843   g_signal_connect_swapped (spinbutton, "value-changed", 
1844                             G_CALLBACK (update_dialog_from_capabilities), dialog);
1845   g_signal_connect_swapped (spinbutton, "changed", 
1846                             G_CALLBACK (update_dialog_from_capabilities), dialog);
1847   
1848   check = gtk_check_button_new_with_mnemonic (_("C_ollate"));
1849   priv->collate_check = check;
1850   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
1851   gtk_widget_show (check);
1852   gtk_table_attach (GTK_TABLE (table), check,
1853                     0, 1, 1, 2,  GTK_FILL, 0,
1854                     0, 0);
1855
1856   check = gtk_check_button_new_with_mnemonic (_("_Reverse"));
1857   g_signal_connect (check, "toggled", G_CALLBACK (update_collate_icon), dialog);
1858   priv->reverse_check = check;
1859   gtk_widget_show (check);
1860   gtk_table_attach (GTK_TABLE (table), check,
1861                     0, 1, 2, 3,  GTK_FILL, 0,
1862                     0, 0);
1863
1864   image = gtk_drawing_area_new ();
1865   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
1866
1867   priv->collate_image = image;
1868   gtk_widget_show (image);
1869   gtk_widget_set_size_request (image, 70, 90);
1870   gtk_table_attach (GTK_TABLE (table), image,
1871                     1, 2, 1, 3, GTK_FILL, 0,
1872                     0, 0);
1873   g_signal_connect (image, "expose-event",
1874                     G_CALLBACK (draw_collate_cb), dialog);
1875
1876   label = gtk_label_new (_("General"));
1877   gtk_widget_show (label);
1878   
1879   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), main_vbox, label);
1880 }
1881
1882 static gboolean
1883 is_range_separator (gchar c)
1884 {
1885   return (c == ',' || c == ';' || c == ':');
1886 }
1887
1888 static GtkPageRange *
1889 dialog_get_page_ranges (GtkPrintUnixDialog *dialog,
1890                         gint               *n_ranges_out)
1891 {
1892   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1893   gint i, n_ranges;
1894   const gchar *text, *p;
1895   gchar *next;
1896   GtkPageRange *ranges;
1897   gint start, end;
1898   
1899   text = gtk_entry_get_text (GTK_ENTRY (priv->page_range_entry));
1900
1901   if (*text == 0)
1902     {
1903       *n_ranges_out = 0;
1904       return NULL;
1905     }
1906   
1907   n_ranges = 1;
1908   p = text;
1909   while (*p)
1910     {
1911       if (is_range_separator (*p))
1912         n_ranges++;
1913       p++;
1914     }
1915
1916   ranges = g_new0 (GtkPageRange, n_ranges);
1917   
1918   i = 0;
1919   p = text;
1920   while (*p)
1921     {
1922       while (isspace (*p)) p++;
1923
1924       if (*p == '-')
1925         {
1926           /* a half-open range like -2 */
1927           start = 1;
1928         }
1929       else
1930         {
1931           start = (int)strtol (p, &next, 10);
1932           if (start < 1)
1933             start = 1;
1934           p = next;
1935         }
1936       
1937       end = start;
1938
1939       while (isspace (*p)) p++;
1940
1941       if (*p == '-')
1942         {
1943           p++;
1944           end = (int)strtol (p, &next, 10);
1945           if (next == p) /* a half-open range like 2- */
1946             end = 0;
1947           else if (end < start)
1948             end = start;
1949         }
1950
1951       ranges[i].start = start - 1;
1952       ranges[i].end = end - 1;
1953       i++;
1954
1955       /* Skip until end or separator */
1956       while (*p && !is_range_separator (*p))
1957         p++;
1958
1959       /* if not at end, skip separator */
1960       if (*p)
1961         p++;
1962     }
1963
1964   *n_ranges_out = i;
1965   
1966   return ranges;
1967 }
1968
1969 static void
1970 dialog_set_page_ranges (GtkPrintUnixDialog *dialog,
1971                         GtkPageRange       *ranges,
1972                         gint                n_ranges)
1973 {
1974   GtkPrintUnixDialogPrivate *priv = dialog->priv;
1975   gint i;
1976   GString *s = g_string_new (NULL);
1977
1978   for (i = 0; i < n_ranges; i++)
1979     {
1980       g_string_append_printf (s, "%d", ranges[i].start + 1);
1981       if (ranges[i].end > ranges[i].start)
1982         g_string_append_printf (s, "-%d", ranges[i].end + 1);
1983       else if (ranges[i].end == -1)
1984         g_string_append (s, "-");
1985       
1986       if (i != n_ranges - 1)
1987         g_string_append (s, ",");
1988     }
1989
1990   gtk_entry_set_text (GTK_ENTRY (priv->page_range_entry), s->str);
1991   
1992   g_string_free (s, TRUE);
1993 }
1994
1995
1996 static GtkPrintPages
1997 dialog_get_print_pages (GtkPrintUnixDialog *dialog)
1998 {
1999   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2000   
2001   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio)))
2002     return GTK_PRINT_PAGES_ALL;
2003   else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->current_page_radio)))
2004     return GTK_PRINT_PAGES_CURRENT;
2005   else
2006     return GTK_PRINT_PAGES_RANGES;
2007 }
2008
2009 static void
2010 dialog_set_print_pages (GtkPrintUnixDialog *dialog, 
2011                         GtkPrintPages       pages)
2012 {
2013   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2014
2015   if (pages == GTK_PRINT_PAGES_RANGES)
2016     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->page_range_radio), TRUE);
2017   else if (pages == GTK_PRINT_PAGES_CURRENT)
2018     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->current_page_radio), TRUE);
2019   else
2020     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->all_pages_radio), TRUE);
2021 }
2022
2023 static gdouble
2024 dialog_get_scale (GtkPrintUnixDialog *dialog)
2025 {
2026   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->scale_spin))
2027     return gtk_spin_button_get_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin));
2028   else
2029     return 100.0;
2030 }
2031
2032 static void
2033 dialog_set_scale (GtkPrintUnixDialog *dialog, 
2034                   gdouble             val)
2035 {
2036   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->scale_spin), val);
2037 }
2038
2039 static GtkPageSet
2040 dialog_get_page_set (GtkPrintUnixDialog *dialog)
2041 {
2042   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->page_set_combo))
2043     return (GtkPageSet)gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->page_set_combo));
2044   else
2045     return GTK_PAGE_SET_ALL;
2046 }
2047
2048 static void
2049 dialog_set_page_set (GtkPrintUnixDialog *dialog, 
2050                      GtkPageSet          val)
2051 {
2052   gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->page_set_combo),
2053                             (int)val);
2054 }
2055
2056 static gint
2057 dialog_get_n_copies (GtkPrintUnixDialog *dialog)
2058 {
2059   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->copies_spin))
2060     return gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->copies_spin));
2061   return 1;
2062 }
2063
2064 static void
2065 dialog_set_n_copies (GtkPrintUnixDialog *dialog, 
2066                      gint                n_copies)
2067 {
2068   gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->copies_spin),
2069                              n_copies);
2070 }
2071
2072 static gboolean
2073 dialog_get_collate (GtkPrintUnixDialog *dialog)
2074 {
2075   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->collate_check))
2076     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check));
2077   return FALSE;
2078 }
2079
2080 static void
2081 dialog_set_collate (GtkPrintUnixDialog *dialog, 
2082                     gboolean            collate)
2083 {
2084   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->collate_check),
2085                                 collate);
2086 }
2087
2088 static gboolean
2089 dialog_get_reverse (GtkPrintUnixDialog *dialog)
2090 {
2091   if (GTK_WIDGET_IS_SENSITIVE (dialog->priv->reverse_check))
2092     return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check));
2093   return FALSE;
2094 }
2095
2096 static void
2097 dialog_set_reverse (GtkPrintUnixDialog *dialog, 
2098                     gboolean            reverse)
2099 {
2100   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->reverse_check),
2101                                 reverse);
2102 }
2103
2104 static gint 
2105 dialog_get_pages_per_sheet (GtkPrintUnixDialog *dialog)
2106 {
2107   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2108   const gchar *val;
2109   gint num;
2110
2111   val = gtk_printer_option_widget_get_value (priv->pages_per_sheet);
2112
2113   num = 1;
2114   
2115   if (val)
2116     {
2117       num = atoi(val);
2118       if (num < 1)
2119         num = 1;
2120     }
2121   
2122   return num;
2123 }
2124
2125 static GtkNumberUpLayout
2126 dialog_get_number_up_layout (GtkPrintUnixDialog *dialog)
2127 {
2128   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2129   GtkPrintCapabilities       caps;
2130   GtkNumberUpLayout          layout;
2131   GtkTextDirection           text_direction;
2132   const gchar               *val;
2133
2134   val = gtk_printer_option_widget_get_value (priv->number_up_layout);
2135   text_direction = gtk_widget_get_default_direction ();
2136
2137   caps = priv->manual_capabilities | priv->printer_capabilities;
2138
2139   if (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
2140     {
2141       if (text_direction == GTK_TEXT_DIR_LTR)
2142         layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2143       else
2144         layout = GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM;
2145     }
2146   else
2147     layout = GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2148
2149   if (val == NULL)
2150     return layout;
2151
2152   if (strcmp (val, "lrtb") == 0)
2153     return GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM;
2154
2155   if (strcmp (val, "lrbt") == 0)
2156     return GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP;
2157
2158   if (strcmp (val, "rltb") == 0)
2159     return GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM;
2160
2161   if (strcmp (val, "rlbt") == 0)
2162     return GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP;
2163
2164   if (strcmp (val, "tblr") == 0)
2165     return GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT;
2166
2167   if (strcmp (val, "tbrl") == 0)
2168     return GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT;
2169
2170   if (strcmp (val, "btlr") == 0)
2171     return GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT;
2172
2173   if (strcmp (val, "btrl") == 0)
2174     return GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT;
2175
2176   return layout;
2177 }
2178
2179 static gboolean
2180 draw_page_cb (GtkWidget          *widget,
2181               GdkEventExpose     *event,
2182               GtkPrintUnixDialog *dialog)
2183 {
2184   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2185   cairo_t *cr;
2186   gdouble ratio;
2187   gint w, h, tmp, shadow_offset;
2188   gint pages_x, pages_y, i, x, y, layout_w, layout_h;
2189   gdouble page_width, page_height;
2190   GtkPageOrientation orientation;
2191   gboolean landscape;
2192   PangoLayout *layout;
2193   PangoFontDescription *font;
2194   gchar *text;
2195   GdkColor *color;
2196   GtkNumberUpLayout number_up_layout;
2197   gint start_x, end_x, start_y, end_y;
2198   gint dx, dy;
2199   gboolean horizontal;
2200   
2201   orientation = gtk_page_setup_get_orientation (priv->page_setup);
2202   landscape =
2203     (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE) ||
2204     (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
2205
2206   number_up_layout = dialog_get_number_up_layout (dialog);
2207   
2208   cr = gdk_cairo_create (widget->window);
2209   
2210   cairo_translate (cr, widget->allocation.x, widget->allocation.y);
2211
2212   ratio = G_SQRT2;
2213
2214   w = (EXAMPLE_PAGE_AREA_SIZE - 3) / ratio;
2215   h = w * ratio;
2216
2217   switch (dialog_get_pages_per_sheet (dialog))
2218     {
2219     default:
2220     case 1:
2221       pages_x = 1; pages_y = 1;
2222       break;
2223     case 2:
2224       landscape = !landscape;
2225       pages_x = 1; pages_y = 2;
2226       break;
2227     case 4:
2228       pages_x = 2; pages_y = 2;
2229       break;
2230     case 6:
2231       landscape = !landscape;
2232       pages_x = 2; pages_y = 3;
2233       break;
2234     case 9:
2235       pages_x = 3; pages_y = 3;
2236       break;
2237     case 16:
2238       pages_x = 4; pages_y = 4;
2239       break;
2240     }
2241
2242   if (landscape)
2243     {
2244       tmp = w;
2245       w = h;
2246       h = tmp;
2247
2248       tmp = pages_x;
2249       pages_x = pages_y;
2250       pages_y = tmp;
2251     }
2252   
2253   shadow_offset = 3;
2254   
2255   color = &widget->style->text[GTK_STATE_NORMAL];
2256   cairo_set_source_rgba (cr, color->red / 65535., color->green / 65535., color->blue / 65535, 0.5);
2257   cairo_rectangle (cr, shadow_offset + 1, shadow_offset + 1, w, h);
2258   cairo_fill (cr);
2259   
2260   gdk_cairo_set_source_color (cr, &widget->style->base[GTK_STATE_NORMAL]);
2261   cairo_rectangle (cr, 1, 1, w, h);
2262   cairo_fill (cr);
2263   cairo_set_line_width (cr, 1.0);
2264   cairo_rectangle (cr, 0.5, 0.5, w+1, h+1);
2265   
2266   gdk_cairo_set_source_color (cr, &widget->style->text[GTK_STATE_NORMAL]);
2267   cairo_stroke (cr);
2268
2269   i = 1;
2270
2271   page_width = (double)w / pages_x;
2272   page_height = (double)h / pages_y;
2273
2274   layout  = pango_cairo_create_layout (cr);
2275
2276   font = pango_font_description_new ();
2277   pango_font_description_set_family (font, "sans");
2278   pango_font_description_set_absolute_size (font, page_height * 0.4 * PANGO_SCALE);
2279   pango_layout_set_font_description (layout, font);
2280   pango_font_description_free (font);
2281
2282   pango_layout_set_width (layout, page_width * PANGO_SCALE);
2283   pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
2284   
2285   switch (number_up_layout)
2286     {
2287       default:
2288       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
2289         start_x = 0;
2290         end_x = pages_x - 1;
2291         start_y = 0;
2292         end_y = pages_y - 1;
2293         dx = 1;
2294         dy = 1;
2295         horizontal = TRUE;
2296         break;
2297       case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
2298         start_x = 0;
2299         end_x = pages_x - 1;
2300         start_y = pages_y - 1;
2301         end_y = 0;
2302         dx = 1;
2303         dy = - 1;
2304         horizontal = TRUE;
2305         break;
2306       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
2307         start_x = pages_x - 1;
2308         end_x = 0;
2309         start_y = 0;
2310         end_y = pages_y - 1;
2311         dx = - 1;
2312         dy = 1;
2313         horizontal = TRUE;
2314         break;
2315       case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
2316         start_x = pages_x - 1;
2317         end_x = 0;
2318         start_y = pages_y - 1;
2319         end_y = 0;
2320         dx = - 1;
2321         dy = - 1;
2322         horizontal = TRUE;
2323         break;
2324       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
2325         start_x = 0;
2326         end_x = pages_x - 1;
2327         start_y = 0;
2328         end_y = pages_y - 1;
2329         dx = 1;
2330         dy = 1;
2331         horizontal = FALSE;
2332         break;
2333       case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
2334         start_x = pages_x - 1;
2335         end_x = 0;
2336         start_y = 0;
2337         end_y = pages_y - 1;
2338         dx = - 1;
2339         dy = 1;
2340         horizontal = FALSE;
2341         break;
2342       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
2343         start_x = 0;
2344         end_x = pages_x - 1;
2345         start_y = pages_y - 1;
2346         end_y = 0;
2347         dx = 1;
2348         dy = - 1;
2349         horizontal = FALSE;
2350         break;
2351       case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
2352         start_x = pages_x - 1;
2353         end_x = 0;
2354         start_y = pages_y - 1;
2355         end_y = 0;
2356         dx = - 1;
2357         dy = - 1;
2358         horizontal = FALSE;
2359         break;
2360     }
2361
2362   if (horizontal)
2363     for (y = start_y; y != end_y + dy; y += dy)
2364       {
2365         for (x = start_x; x != end_x + dx; x += dx)
2366           {
2367             text = g_strdup_printf ("%d", i++);
2368             pango_layout_set_text (layout, text, -1);
2369             g_free (text);
2370             pango_layout_get_size (layout, &layout_w, &layout_h);
2371             cairo_save (cr);
2372             cairo_translate (cr,
2373                              x * page_width,
2374                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2375
2376             pango_cairo_show_layout (cr, layout);
2377             cairo_restore (cr);
2378           }
2379       }
2380   else
2381     for (x = start_x; x != end_x + dx; x += dx)
2382       {
2383         for (y = start_y; y != end_y + dy; y += dy)
2384           {
2385             text = g_strdup_printf ("%d", i++);
2386             pango_layout_set_text (layout, text, -1);
2387             g_free (text);
2388             pango_layout_get_size (layout, &layout_w, &layout_h);
2389             cairo_save (cr);
2390             cairo_translate (cr,
2391                              x * page_width,
2392                              y * page_height + (page_height - layout_h / 1024.0) / 2);
2393
2394             pango_cairo_show_layout (cr, layout);
2395             cairo_restore (cr);
2396           }
2397       }
2398   
2399   g_object_unref (layout);
2400   cairo_destroy (cr);
2401
2402   return TRUE;
2403 }
2404
2405 static void
2406 redraw_page_layout_preview (GtkPrintUnixDialog *dialog)
2407 {
2408   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2409
2410   if (priv->page_layout_preview)
2411     gtk_widget_queue_draw (priv->page_layout_preview);
2412 }
2413
2414 static void
2415 update_number_up_layout (GtkPrintUnixDialog *dialog)
2416 {
2417   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2418   GtkPrintCapabilities       caps;
2419   GtkPrinterOptionSet       *set;
2420   GtkNumberUpLayout          layout;
2421   GtkPrinterOption          *option;
2422   GtkPrinterOption          *old_option;
2423
2424   set = priv->options;
2425
2426   caps = priv->manual_capabilities | priv->printer_capabilities;
2427
2428   if (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT)
2429     {
2430       if (priv->number_up_layout_n_option == NULL)
2431         {
2432           priv->number_up_layout_n_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
2433           g_object_ref (priv->number_up_layout_n_option);
2434
2435           priv->number_up_layout_2_option = gtk_printer_option_new ("gtk-n-up-layout",
2436                                                                     _("Page Ordering"),
2437                                                                     GTK_PRINTER_OPTION_TYPE_PICKONE);
2438           gtk_printer_option_allocate_choices (priv->number_up_layout_2_option, 2);
2439
2440           priv->number_up_layout_2_option->choices[0] = priv->number_up_layout_n_option->choices[0];
2441           priv->number_up_layout_2_option->choices[1] = priv->number_up_layout_n_option->choices[2];
2442           priv->number_up_layout_2_option->choices_display[0] = g_strdup ( _("Left to right"));
2443           priv->number_up_layout_2_option->choices_display[1] = g_strdup ( _("Right to left"));
2444         }
2445
2446       layout = dialog_get_number_up_layout (dialog);
2447
2448       old_option = gtk_printer_option_set_lookup (set, "gtk-n-up-layout");
2449       if (old_option != NULL)
2450         gtk_printer_option_set_remove (set, old_option);
2451
2452       if (dialog_get_pages_per_sheet (dialog) != 1)
2453         {
2454           if (dialog_get_pages_per_sheet (dialog) == 2)
2455             {
2456               option = priv->number_up_layout_2_option;
2457
2458               if (layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM ||
2459                   layout == GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP ||
2460                   layout == GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT ||
2461                   layout == GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT)
2462                 gtk_printer_option_set (option, "lrtb");
2463               else
2464                 gtk_printer_option_set (option, "rltb");
2465             }
2466           else
2467             {
2468               option = priv->number_up_layout_n_option;
2469
2470               switch (layout)
2471                 {
2472                   case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_TOP_TO_BOTTOM:
2473                     gtk_printer_option_set (option, "lrtb");
2474                     break;
2475                   case GTK_NUMBER_UP_LAYOUT_LEFT_TO_RIGHT_BOTTOM_TO_TOP:
2476                     gtk_printer_option_set (option, "lrbt");
2477                     break;
2478                   case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_TOP_TO_BOTTOM:
2479                     gtk_printer_option_set (option, "rltb");
2480                     break;
2481                   case GTK_NUMBER_UP_LAYOUT_RIGHT_TO_LEFT_BOTTOM_TO_TOP:
2482                     gtk_printer_option_set (option, "rlbt");
2483                     break;
2484                   case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_LEFT_TO_RIGHT:
2485                     gtk_printer_option_set (option, "tblr");
2486                     break;
2487                   case GTK_NUMBER_UP_LAYOUT_TOP_TO_BOTTOM_RIGHT_TO_LEFT:
2488                     gtk_printer_option_set (option, "tbrl");
2489                     break;
2490                   case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_LEFT_TO_RIGHT:
2491                     gtk_printer_option_set (option, "btlr");
2492                     break;
2493                   case GTK_NUMBER_UP_LAYOUT_BOTTOM_TO_TOP_RIGHT_TO_LEFT:
2494                     gtk_printer_option_set (option, "btrl");
2495                     break;
2496                }
2497             }
2498
2499           gtk_printer_option_set_add (set, option);
2500         }
2501     }
2502
2503   setup_option (dialog, "gtk-n-up-layout", priv->number_up_layout);
2504
2505   if (priv->number_up_layout != NULL)
2506     gtk_widget_set_sensitive (GTK_WIDGET (priv->number_up_layout),
2507                               (caps & GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT) &&
2508                               (dialog_get_pages_per_sheet (dialog) > 1));
2509 }
2510
2511 static void
2512 create_page_setup_page (GtkPrintUnixDialog *dialog)
2513 {
2514   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2515   GtkWidget *main_vbox, *label, *hbox, *hbox2;
2516   GtkWidget *frame, *table, *widget;
2517   GtkWidget *combo, *spinbutton, *draw;
2518
2519   main_vbox = gtk_vbox_new (FALSE, 18);
2520   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2521   gtk_widget_show (main_vbox);
2522
2523   hbox = gtk_hbox_new (FALSE, 18);
2524   gtk_widget_show (hbox);
2525   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
2526
2527   table = gtk_table_new (5, 2, FALSE);
2528   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2529   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2530   frame = wrap_in_frame (_("Layout"), table);
2531   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
2532   gtk_widget_show (table);
2533
2534   label = gtk_label_new_with_mnemonic (_("T_wo-sided:"));
2535   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2536   gtk_widget_show (label);
2537   gtk_table_attach (GTK_TABLE (table), label,
2538                     0, 1, 0, 1,  GTK_FILL, 0,
2539                     0, 0);
2540
2541   widget = gtk_printer_option_widget_new (NULL);
2542   priv->duplex = GTK_PRINTER_OPTION_WIDGET (widget);
2543   gtk_widget_show (widget);
2544   gtk_table_attach (GTK_TABLE (table), widget,
2545                     1, 2, 0, 1,  GTK_FILL, 0,
2546                     0, 0);
2547   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2548
2549   label = gtk_label_new_with_mnemonic (_("Pages per _side:"));
2550   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2551   gtk_widget_show (label);
2552   gtk_table_attach (GTK_TABLE (table), label,
2553                     0, 1, 1, 2,  GTK_FILL, 0,
2554                     0, 0);
2555
2556   widget = gtk_printer_option_widget_new (NULL);
2557   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
2558   g_signal_connect_swapped (widget, "changed", G_CALLBACK (update_number_up_layout), dialog);
2559   priv->pages_per_sheet = GTK_PRINTER_OPTION_WIDGET (widget);
2560   gtk_widget_show (widget);
2561   gtk_table_attach (GTK_TABLE (table), widget,
2562                     1, 2, 1, 2,  GTK_FILL, 0,
2563                     0, 0);
2564   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2565
2566
2567   label = gtk_label_new_with_mnemonic (_("Page or_dering:"));
2568   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2569   gtk_widget_show (label);
2570   gtk_table_attach (GTK_TABLE (table), label,
2571                     0, 1, 2, 3,  GTK_FILL, 0,
2572                     0, 0);
2573
2574   widget = gtk_printer_option_widget_new (NULL);
2575   g_signal_connect_swapped (widget, "changed", G_CALLBACK (redraw_page_layout_preview), dialog);
2576   priv->number_up_layout = GTK_PRINTER_OPTION_WIDGET (widget);
2577   gtk_widget_show (widget);
2578   gtk_table_attach (GTK_TABLE (table), widget,
2579                     1, 2, 2, 3,  GTK_FILL, 0,
2580                     0, 0);
2581   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2582
2583   label = gtk_label_new_with_mnemonic (_("_Only print:"));
2584   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2585   gtk_widget_show (label);
2586   gtk_table_attach (GTK_TABLE (table), label,
2587                     0, 1, 3, 4,  GTK_FILL, 0,
2588                     0, 0);
2589
2590   combo = gtk_combo_box_new_text ();
2591   priv->page_set_combo = combo;
2592   gtk_widget_show (combo);
2593   gtk_table_attach (GTK_TABLE (table), combo,
2594                     1, 2, 3, 4,  GTK_FILL, 0,
2595                     0, 0);
2596   gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo);
2597   /* In enum order */
2598   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("All sheets"));  
2599   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Even sheets"));  
2600   gtk_combo_box_append_text (GTK_COMBO_BOX (combo), _("Odd sheets"));  
2601   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
2602
2603   label = gtk_label_new_with_mnemonic (_("Sc_ale:"));
2604   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2605   gtk_widget_show (label);
2606   gtk_table_attach (GTK_TABLE (table), label,
2607                     0, 1, 4, 5,  GTK_FILL, 0,
2608                     0, 0);
2609
2610   hbox2 = gtk_hbox_new (FALSE, 6);
2611   gtk_widget_show (hbox2);
2612   gtk_table_attach (GTK_TABLE (table), hbox2,
2613                     1, 2, 4, 5,  GTK_FILL, 0,
2614                     0, 0);
2615   
2616   spinbutton = gtk_spin_button_new_with_range (1.0, 1000.0, 1.0);
2617   priv->scale_spin = spinbutton;
2618   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinbutton), 1);
2619   gtk_spin_button_set_value (GTK_SPIN_BUTTON (spinbutton), 100.0);
2620   gtk_box_pack_start (GTK_BOX (hbox2), spinbutton, FALSE, FALSE, 0);
2621   gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
2622   gtk_widget_show (spinbutton);
2623   label = gtk_label_new ("%"); /* FIXMEchpe does there exist any language where % needs to be translated? */
2624   gtk_widget_show (label);
2625   gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, FALSE, 0);
2626
2627   table = gtk_table_new (4, 2, FALSE);
2628   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2629   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2630   frame = wrap_in_frame (_("Paper"), table);
2631   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 6);
2632   gtk_widget_show (table);
2633
2634   label = gtk_label_new_with_mnemonic (_("Paper _type:"));
2635   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2636   gtk_widget_show (label);
2637   gtk_table_attach (GTK_TABLE (table), label,
2638                     0, 1, 0, 1,  GTK_FILL, 0,
2639                     0, 0);
2640
2641   widget = gtk_printer_option_widget_new (NULL);
2642   priv->paper_type = GTK_PRINTER_OPTION_WIDGET (widget);
2643   gtk_widget_show (widget);
2644   gtk_table_attach (GTK_TABLE (table), widget,
2645                     1, 2, 0, 1,  GTK_FILL, 0,
2646                     0, 0);
2647   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2648
2649   label = gtk_label_new_with_mnemonic (_("Paper _source:"));
2650   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2651   gtk_widget_show (label);
2652   gtk_table_attach (GTK_TABLE (table), label,
2653                     0, 1, 1, 2,  GTK_FILL, 0,
2654                     0, 0);
2655
2656   widget = gtk_printer_option_widget_new (NULL);
2657   priv->paper_source = GTK_PRINTER_OPTION_WIDGET (widget);
2658   gtk_widget_show (widget);
2659   gtk_table_attach (GTK_TABLE (table), widget,
2660                     1, 2, 1, 2,  GTK_FILL, 0,
2661                     0, 0);
2662   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2663
2664   label = gtk_label_new_with_mnemonic (_("Output t_ray:"));
2665   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2666   gtk_widget_show (label);
2667   gtk_table_attach (GTK_TABLE (table), label,
2668                     0, 1, 2, 3,  GTK_FILL, 0,
2669                     0, 0);
2670
2671   widget = gtk_printer_option_widget_new (NULL);
2672   priv->output_tray = GTK_PRINTER_OPTION_WIDGET (widget);
2673   gtk_widget_show (widget);
2674   gtk_table_attach (GTK_TABLE (table), widget,
2675                     1, 2, 2, 3,  GTK_FILL, 0,
2676                     0, 0);
2677   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2678
2679   /* Add the page layout preview */
2680   hbox2 = gtk_hbox_new (FALSE, 0);
2681   gtk_widget_show (hbox2);
2682   gtk_box_pack_start (GTK_BOX (main_vbox), hbox2, TRUE, TRUE, 0);
2683
2684   draw = gtk_drawing_area_new ();
2685   GTK_WIDGET_SET_FLAGS (draw, GTK_NO_WINDOW);
2686   priv->page_layout_preview = draw;
2687   gtk_widget_set_size_request (draw, 200, 200);
2688   g_signal_connect (draw, "expose-event", G_CALLBACK (draw_page_cb), dialog);
2689   gtk_widget_show (draw);
2690
2691   gtk_box_pack_start (GTK_BOX (hbox2), draw, TRUE, FALSE, 0);
2692   
2693   label = gtk_label_new (_("Page Setup"));
2694   gtk_widget_show (label);
2695   
2696   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2697                             main_vbox, label);
2698 }
2699
2700 static void
2701 create_job_page (GtkPrintUnixDialog *dialog)
2702 {
2703   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2704   GtkWidget *main_table, *label;
2705   GtkWidget *frame, *table, *radio;
2706   GtkWidget *entry, *widget;
2707
2708   main_table = gtk_table_new (2, 2, FALSE);
2709   gtk_container_set_border_width (GTK_CONTAINER (main_table), 12);
2710   gtk_table_set_row_spacings (GTK_TABLE (main_table), 18);
2711   gtk_table_set_col_spacings (GTK_TABLE (main_table), 18);
2712
2713   table = gtk_table_new (2, 2, FALSE);
2714   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2715   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2716   frame = wrap_in_frame (_("Job Details"), table);
2717   gtk_table_attach (GTK_TABLE (main_table), frame,
2718                     0, 1, 0, 1,  GTK_FILL, 0,
2719                     0, 0);
2720   gtk_widget_show (table);
2721
2722   label = gtk_label_new_with_mnemonic (_("Pri_ority:"));
2723   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2724   gtk_widget_show (label);
2725   gtk_table_attach (GTK_TABLE (table), label,
2726                     0, 1, 0, 1,  GTK_FILL, 0,
2727                     0, 0);
2728
2729   widget = gtk_printer_option_widget_new (NULL);
2730   priv->job_prio = GTK_PRINTER_OPTION_WIDGET (widget);
2731   gtk_widget_show (widget);
2732   gtk_table_attach (GTK_TABLE (table), widget,
2733                     1, 2, 0, 1,  GTK_FILL, 0,
2734                     0, 0);
2735   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2736
2737   label = gtk_label_new_with_mnemonic (_("_Billing info:"));
2738   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2739   gtk_widget_show (label);
2740   gtk_table_attach (GTK_TABLE (table), label,
2741                     0, 1, 1, 2,  GTK_FILL, 0,
2742                     0, 0);
2743
2744   widget = gtk_printer_option_widget_new (NULL);
2745   priv->billing_info = GTK_PRINTER_OPTION_WIDGET (widget);
2746   gtk_widget_show (widget);
2747   gtk_table_attach (GTK_TABLE (table), widget,
2748                     1, 2, 1, 2,  GTK_FILL, 0,
2749                     0, 0);
2750   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2751
2752   table = gtk_table_new (2, 2, FALSE);
2753   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2754   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2755   frame = wrap_in_frame (_("Print Document"), table);
2756   gtk_table_attach (GTK_TABLE (main_table), frame,
2757                     0, 1, 1, 2,  GTK_FILL, 0,
2758                     0, 0);
2759   gtk_widget_show (table);
2760
2761   /* Translators: this is one of the choices for the print at option 
2762    * in the print dialog
2763    */
2764   radio = gtk_radio_button_new_with_mnemonic (NULL, _("_Now"));
2765   priv->print_now_radio = radio;
2766   gtk_widget_show (radio);
2767   gtk_table_attach (GTK_TABLE (table), radio,
2768                     0, 2, 0, 1,  GTK_FILL, 0,
2769                     0, 0);
2770   /* Translators: this is one of the choices for the print at option 
2771    * in the print dialog. It also serves as the label for an entry that
2772    * allows the user to enter a time.
2773    */
2774   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2775                                               _("A_t:"));
2776   priv->print_at_radio = radio;
2777   gtk_widget_show (radio);
2778   gtk_table_attach (GTK_TABLE (table), radio,
2779                     0, 1, 1, 2,  GTK_FILL, 0,
2780                     0, 0);
2781
2782   entry = gtk_entry_new ();
2783   priv->print_at_entry = entry;
2784   gtk_widget_show (entry);
2785   gtk_table_attach (GTK_TABLE (table), entry,
2786                     1, 2, 1, 2,  GTK_FILL, 0,
2787                     0, 0);
2788
2789   /* Translators: this is one of the choices for the print at option 
2790    * in the print dialog. It means that the print job will not be
2791    * printed until it explicitly gets 'released'.
2792    */
2793   radio = gtk_radio_button_new_with_mnemonic (gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio)),
2794                                               _("On _hold"));
2795   priv->print_hold_radio = radio;
2796   gtk_widget_show (radio);
2797   gtk_table_attach (GTK_TABLE (table), radio,
2798                     0, 2, 2, 3,  GTK_FILL, 0,
2799                     0, 0);
2800
2801   g_signal_connect_swapped (priv->print_now_radio, "toggled",
2802                             G_CALLBACK (update_print_at_option), dialog);
2803   g_signal_connect_swapped (priv->print_at_radio, "toggled",
2804                             G_CALLBACK (update_print_at_option), dialog);
2805   g_signal_connect_swapped (priv->print_at_entry, "changed",
2806                             G_CALLBACK (update_print_at_option), dialog);
2807   g_signal_connect_swapped (priv->print_hold_radio, "toggled",
2808                             G_CALLBACK (update_print_at_option), dialog);
2809
2810   table = gtk_table_new (2, 2, FALSE);
2811   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2812   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2813   frame = wrap_in_frame (_("Add Cover Page"), table);
2814   gtk_table_attach (GTK_TABLE (main_table), frame,
2815                     1, 2, 0, 1,  GTK_FILL, 0,
2816                     0, 0);
2817   gtk_widget_show (table);
2818
2819   /* Translators, this is the label used for the option in the print 
2820    * dialog that controls the front cover page.
2821    */
2822   label = gtk_label_new_with_mnemonic (_("Be_fore:"));
2823   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2824   gtk_widget_show (label);
2825   gtk_table_attach (GTK_TABLE (table), label,
2826                     0, 1, 0, 1,  GTK_FILL, 0,
2827                     0, 0);
2828
2829   widget = gtk_printer_option_widget_new (NULL);
2830   priv->cover_before = GTK_PRINTER_OPTION_WIDGET (widget);
2831   gtk_widget_show (widget);
2832   gtk_table_attach (GTK_TABLE (table), widget,
2833                     1, 2, 0, 1,  GTK_FILL, 0,
2834                     0, 0);
2835   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2836
2837   /* Translators, this is the label used for the option in the print 
2838    * dialog that controls the back cover page.
2839    */
2840   label = gtk_label_new_with_mnemonic (_("_After:"));
2841   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
2842   gtk_widget_show (label);
2843   gtk_table_attach (GTK_TABLE (table), label,
2844                     0, 1, 1, 2,  GTK_FILL, 0,
2845                     0, 0);
2846
2847   widget = gtk_printer_option_widget_new (NULL);
2848   priv->cover_after = GTK_PRINTER_OPTION_WIDGET (widget);
2849   gtk_widget_show (widget);
2850   gtk_table_attach (GTK_TABLE (table), widget,
2851                     1, 2, 1, 2,  GTK_FILL, 0,
2852                     0, 0);
2853   gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget);
2854
2855   /* Translators: this is the tab label for the notebook tab containing
2856    * job-specific options in the print dialog
2857    */
2858   label = gtk_label_new (_("Job"));
2859   gtk_widget_show (label);
2860
2861   priv->job_page = main_table;
2862   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2863                             main_table, label);
2864 }
2865
2866 static void 
2867 create_optional_page (GtkPrintUnixDialog  *dialog,
2868                       const gchar         *text,
2869                       GtkWidget          **table_out,
2870                       GtkWidget          **page_out)
2871 {
2872   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2873   GtkWidget *table, *label, *scrolled;
2874
2875   scrolled = gtk_scrolled_window_new (NULL, NULL);
2876   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2877                                   GTK_POLICY_NEVER,
2878                                   GTK_POLICY_AUTOMATIC);
2879   
2880   table = gtk_table_new (1, 2, FALSE);
2881   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2882   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
2883   gtk_container_set_border_width (GTK_CONTAINER (table), 12);
2884   gtk_widget_show (table);
2885
2886   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
2887                                          table);
2888   gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
2889                                 GTK_SHADOW_NONE);
2890   
2891   label = gtk_label_new (text);
2892   gtk_widget_show (label);
2893   
2894   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2895                             scrolled, label);
2896
2897   *table_out = table;
2898   *page_out = scrolled;
2899 }
2900
2901 static void
2902 create_advanced_page (GtkPrintUnixDialog *dialog)
2903 {
2904   GtkPrintUnixDialogPrivate *priv = dialog->priv;
2905   GtkWidget *main_vbox, *label, *scrolled;
2906
2907   scrolled = gtk_scrolled_window_new (NULL, NULL);
2908   priv->advanced_page = scrolled;
2909   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
2910                                   GTK_POLICY_NEVER,
2911                                   GTK_POLICY_AUTOMATIC);
2912
2913   main_vbox = gtk_vbox_new (FALSE, 18);
2914   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
2915   gtk_widget_show (main_vbox);
2916
2917   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
2918                                          main_vbox);
2919   gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN(scrolled)->child),
2920                                 GTK_SHADOW_NONE);
2921   
2922   priv->advanced_vbox = main_vbox;
2923   
2924   label = gtk_label_new (_("Advanced"));
2925   gtk_widget_show (label);
2926   
2927   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
2928                             scrolled, label);
2929 }
2930
2931
2932 static void
2933 populate_dialog (GtkPrintUnixDialog *print_dialog)
2934 {
2935   GtkPrintUnixDialogPrivate *priv = print_dialog->priv;
2936   GtkDialog *dialog = GTK_DIALOG (print_dialog);
2937   GtkWidget *vbox, *conflict_hbox, *image, *label;
2938
2939   gtk_dialog_set_has_separator (dialog, FALSE);
2940   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
2941   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
2942   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
2943   gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
2944
2945   vbox = gtk_vbox_new (FALSE, 6);
2946   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
2947   gtk_box_pack_start (GTK_BOX (dialog->vbox), vbox, TRUE, TRUE, 0);
2948   gtk_widget_show (vbox);
2949
2950   priv->notebook = gtk_notebook_new ();
2951   gtk_box_pack_start (GTK_BOX (vbox), priv->notebook, TRUE, TRUE, 0);
2952   gtk_widget_show (priv->notebook);
2953
2954   create_printer_list_model (print_dialog);
2955
2956   create_main_page (print_dialog);
2957   create_page_setup_page (print_dialog);
2958   create_job_page (print_dialog);
2959   create_optional_page (print_dialog, _("Image Quality"),
2960                         &priv->image_quality_table,
2961                         &priv->image_quality_page);
2962   create_optional_page (print_dialog, _("Color"),
2963                         &priv->color_table,
2964                         &priv->color_page);
2965   create_optional_page (print_dialog, _("Finishing"),
2966                         &priv->finishing_table,
2967                         &priv->finishing_page);
2968   create_advanced_page (print_dialog);
2969
2970   priv->conflicts_widget = conflict_hbox = gtk_hbox_new (FALSE, 12);
2971   gtk_box_pack_end (GTK_BOX (vbox), conflict_hbox, FALSE, FALSE, 0);
2972   image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
2973   gtk_widget_show (image);
2974   gtk_box_pack_start (GTK_BOX (conflict_hbox), image, FALSE, TRUE, 0);
2975   label = gtk_label_new (_("Some of the settings in the dialog conflict"));
2976   gtk_widget_show (label);
2977   gtk_box_pack_start (GTK_BOX (conflict_hbox), label, FALSE, TRUE, 0);
2978   
2979   load_print_backends (print_dialog);
2980 }
2981
2982 /**
2983  * gtk_print_unix_dialog_new:
2984  * @title: Title of the dialog, or %NULL
2985  * @parent: Transient parent of the dialog, or %NULL
2986  *
2987  * Creates a new #GtkPrintUnixDialog.
2988  *
2989  * Return value: a new #GtkPrintUnixDialog
2990  *
2991  * Since: 2.10
2992  **/
2993 GtkWidget *
2994 gtk_print_unix_dialog_new (const gchar *title,
2995                            GtkWindow   *parent)
2996 {
2997   GtkWidget *result;
2998   const gchar *_title = _("Print");
2999
3000   if (title)
3001     _title = title;
3002
3003   result = g_object_new (GTK_TYPE_PRINT_UNIX_DIALOG,
3004                          "transient-for", parent,
3005                          "title", _title,
3006                          "has-separator", FALSE,
3007                          NULL);
3008   
3009   return result;
3010 }
3011
3012 /**
3013  * gtk_print_unix_dialog_get_selected_printer:
3014  * @dialog: a #GtkPrintUnixDialog
3015  * 
3016  * Gets the currently selected printer.
3017  * 
3018  * Returns: the currently selected printer
3019  * 
3020  * Since: 2.10
3021  */
3022 GtkPrinter *
3023 gtk_print_unix_dialog_get_selected_printer (GtkPrintUnixDialog *dialog)
3024 {
3025   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3026
3027   return dialog->priv->current_printer;
3028 }
3029
3030 /**
3031  * gtk_print_unix_dialog_set_page_setup:
3032  * @dialog: a #GtkPrintUnixDialog
3033  * @page_setup: a #GtkPageSetup
3034  * 
3035  * Sets the page setup of the #GtkPrintUnixDialog.
3036  *
3037  * Since: 2.10
3038  */
3039 void
3040 gtk_print_unix_dialog_set_page_setup (GtkPrintUnixDialog *dialog,
3041                                       GtkPageSetup       *page_setup)
3042 {
3043   GtkPrintUnixDialogPrivate *priv;
3044
3045   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3046   g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
3047
3048   priv = dialog->priv;
3049
3050   if (priv->page_setup != page_setup)
3051     {
3052       g_object_unref (priv->page_setup);
3053       priv->page_setup = g_object_ref (page_setup);
3054
3055       priv->page_setup_set = TRUE;
3056
3057       g_object_notify (G_OBJECT (dialog), "page-setup");
3058     }
3059 }
3060
3061 /**
3062  * gtk_print_unix_dialog_get_page_setup:
3063  * @dialog: a #GtkPrintUnixDialog
3064  * 
3065  * Gets the page setup that is used by the #GtkPrintUnixDialog.
3066  * 
3067  * Returns: the page setup of @dialog.
3068  *
3069  * Since: 2.10
3070  */
3071 GtkPageSetup *
3072 gtk_print_unix_dialog_get_page_setup (GtkPrintUnixDialog *dialog)
3073 {
3074   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3075
3076   return dialog->priv->page_setup;
3077 }
3078
3079 /**
3080  * gtk_print_unix_dialog_set_current_page:
3081  * @dialog: a #GtkPrintUnixDialog
3082  * @current_page: the current page number.
3083  * 
3084  * Sets the current page number. If @current_page is not -1, this enables
3085  * the current page choice for the range of pages to print.
3086  *
3087  * Since: 2.10
3088  */
3089 void
3090 gtk_print_unix_dialog_set_current_page (GtkPrintUnixDialog *dialog,
3091                                         gint                current_page)
3092 {
3093   GtkPrintUnixDialogPrivate *priv;
3094
3095   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3096
3097   priv = dialog->priv;
3098
3099   if (priv->current_page != current_page)
3100     {
3101       priv->current_page = current_page;
3102
3103       if (priv->current_page_radio)
3104         gtk_widget_set_sensitive (priv->current_page_radio, current_page != -1);
3105
3106       g_object_notify (G_OBJECT (dialog), "current-page");
3107     }
3108 }
3109
3110 /**
3111  * gtk_print_unix_dialog_get_current_page:
3112  * @dialog: a #GtkPrintUnixDialog
3113  * 
3114  * Gets the current page of the #GtkPrintDialog.
3115  * 
3116  * Returns: the current page of @dialog
3117  * 
3118  * Since: 2.10
3119  */
3120 gint
3121 gtk_print_unix_dialog_get_current_page (GtkPrintUnixDialog *dialog)
3122 {
3123   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), -1);
3124
3125   return dialog->priv->current_page;
3126 }
3127
3128 static gboolean
3129 set_active_printer (GtkPrintUnixDialog *dialog,
3130                     const gchar        *printer_name)
3131 {
3132   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3133   GtkTreeModel *model;
3134   GtkTreeIter iter, filter_iter;
3135   GtkTreeSelection *selection;
3136   GtkPrinter *printer;
3137
3138   model = GTK_TREE_MODEL (priv->printer_list);
3139
3140   if (gtk_tree_model_get_iter_first (model, &iter))
3141     {
3142       do
3143         {
3144           gtk_tree_model_get (GTK_TREE_MODEL (priv->printer_list), &iter,
3145                               PRINTER_LIST_COL_PRINTER_OBJ, &printer, -1);
3146           if (printer == NULL)
3147             continue;
3148           
3149           if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
3150             {
3151               gtk_tree_model_filter_convert_child_iter_to_iter (priv->printer_list_filter,
3152                                                                 &filter_iter, &iter);
3153               
3154               selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
3155               priv->internal_printer_change = TRUE;
3156               gtk_tree_selection_select_iter (selection, &filter_iter);
3157               priv->internal_printer_change = FALSE;
3158               g_free (priv->waiting_for_printer);
3159               priv->waiting_for_printer = NULL;
3160               
3161               g_object_unref (printer);
3162               return TRUE;
3163             }
3164               
3165           g_object_unref (printer);
3166           
3167         } while (gtk_tree_model_iter_next (model, &iter));
3168     }
3169   
3170   return FALSE;
3171 }
3172
3173 /**
3174  * gtk_print_unix_dialog_set_settings:
3175  * @dialog: a #GtkPrintUnixDialog
3176  * @settings: a #GtkPrintSettings, or %NULL
3177  * 
3178  * Sets the #GtkPrintSettings for the #GtkPrintUnixDialog. Typically,
3179  * this is used to restore saved print settings from a previous print
3180  * operation before the print dialog is shown.
3181  * 
3182  * Since: 2.10
3183  **/
3184 void
3185 gtk_print_unix_dialog_set_settings (GtkPrintUnixDialog *dialog,
3186                                     GtkPrintSettings   *settings)
3187 {
3188   GtkPrintUnixDialogPrivate *priv;
3189   const gchar *printer;
3190   GtkPageRange *ranges;
3191   gint num_ranges;
3192   
3193   g_return_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog));
3194   g_return_if_fail (settings == NULL || GTK_IS_PRINT_SETTINGS (settings));
3195
3196   priv = dialog->priv;
3197
3198   if (settings != NULL)
3199     {
3200       dialog_set_collate (dialog, gtk_print_settings_get_collate (settings));
3201       dialog_set_reverse (dialog, gtk_print_settings_get_reverse (settings));
3202       dialog_set_n_copies (dialog, gtk_print_settings_get_n_copies (settings));
3203       dialog_set_scale (dialog, gtk_print_settings_get_scale (settings));
3204       dialog_set_page_set (dialog, gtk_print_settings_get_page_set (settings));
3205       dialog_set_print_pages (dialog, gtk_print_settings_get_print_pages (settings));
3206       ranges = gtk_print_settings_get_page_ranges (settings, &num_ranges);
3207       if (ranges)
3208         {
3209           dialog_set_page_ranges (dialog, ranges, num_ranges);
3210           g_free (ranges);
3211         }
3212
3213       priv->format_for_printer =
3214         g_strdup (gtk_print_settings_get (settings, "format-for-printer"));
3215     }
3216
3217   if (priv->initial_settings)
3218     g_object_unref (priv->initial_settings);
3219
3220   priv->initial_settings = settings;
3221
3222   g_free (priv->waiting_for_printer);
3223   priv->waiting_for_printer = NULL;
3224   
3225   if (settings)
3226     {
3227       g_object_ref (settings);
3228
3229       printer = gtk_print_settings_get_printer (settings);
3230       
3231       if (printer && !set_active_printer (dialog, printer))
3232         priv->waiting_for_printer = g_strdup (printer); 
3233     }
3234
3235   g_object_notify (G_OBJECT (dialog), "print-settings");
3236 }
3237
3238 /**
3239  * gtk_print_unix_dialog_get_settings:
3240  * @dialog: a #GtkPrintUnixDialog
3241  * 
3242  * Gets a new #GtkPrintSettings object that represents the
3243  * current values in the print dialog. Note that this creates a
3244  * <emphasis>new object</emphasis>, and you need to unref it
3245  * if don't want to keep it.
3246  * 
3247  * Returns: a new #GtkPrintSettings object with the values from @dialog
3248  *
3249  * Since: 2.10
3250  */
3251 GtkPrintSettings *
3252 gtk_print_unix_dialog_get_settings (GtkPrintUnixDialog *dialog)
3253 {
3254   GtkPrintUnixDialogPrivate *priv;
3255   GtkPrintSettings *settings;
3256   GtkPrintPages print_pages;
3257   GtkPageRange *ranges;
3258   gint n_ranges;
3259
3260   g_return_val_if_fail (GTK_IS_PRINT_UNIX_DIALOG (dialog), NULL);
3261
3262   priv = dialog->priv;
3263   settings = gtk_print_settings_new ();
3264
3265   if (priv->current_printer)
3266     gtk_print_settings_set_printer (settings,
3267                                     gtk_printer_get_name (priv->current_printer));
3268   else
3269     gtk_print_settings_set_printer (settings, "default");
3270   
3271   gtk_print_settings_set (settings, "format-for-printer",
3272                           priv->format_for_printer);
3273
3274   
3275   gtk_print_settings_set_collate (settings,
3276                                   dialog_get_collate (dialog));
3277   
3278   gtk_print_settings_set_reverse (settings,
3279                                   dialog_get_reverse (dialog));
3280   
3281   gtk_print_settings_set_n_copies (settings,
3282                                    dialog_get_n_copies (dialog));
3283
3284   gtk_print_settings_set_scale (settings,
3285                                 dialog_get_scale (dialog));
3286   
3287   gtk_print_settings_set_page_set (settings,
3288                                    dialog_get_page_set (dialog));
3289   
3290   print_pages = dialog_get_print_pages (dialog);
3291   gtk_print_settings_set_print_pages (settings, print_pages);
3292
3293   ranges = dialog_get_page_ranges (dialog, &n_ranges);
3294   if (ranges)
3295     {
3296       gtk_print_settings_set_page_ranges  (settings, ranges, n_ranges);
3297       g_free (ranges);
3298     }
3299
3300   /* TODO: print when. How to handle? */
3301
3302   if (priv->current_printer)
3303     _gtk_printer_get_settings_from_options (priv->current_printer,
3304                                             priv->options,
3305                                             settings);
3306   
3307   return settings;
3308 }
3309
3310 /**
3311  * gtk_print_unix_dialog_add_custom_tab:
3312  * @dialog: a #GtkPrintUnixDialog
3313  * @child: the widget to put in the custom tab
3314  * @tab_label: the widget to use as tab label
3315  *
3316  * Adds a custom tab to the print dialog.
3317  *
3318  * Since: 2.10
3319  */
3320 void
3321 gtk_print_unix_dialog_add_custom_tab (GtkPrintUnixDialog *dialog,
3322                                       GtkWidget          *child,
3323                                       GtkWidget          *tab_label)
3324 {
3325   gtk_notebook_insert_page (GTK_NOTEBOOK (dialog->priv->notebook),
3326                             child, tab_label, 2);
3327   gtk_widget_show (child);
3328   gtk_widget_show (tab_label);
3329 }
3330
3331 /**
3332  * gtk_print_unix_dialog_set_manual_capabilities:
3333  * @dialog: a #GtkPrintUnixDialog
3334  * @capabilities: the printing capabilities of your application
3335  *
3336  * This lets you specify the printing capabilities your application
3337  * supports. For instance, if you can handle scaling the output then
3338  * you pass #GTK_PRINT_CAPABILITY_SCALE. If you don't pass that, then
3339  * the dialog will only let you select the scale if the printing
3340  * system automatically handles scaling.
3341  *
3342  * Since: 2.10
3343  */
3344 void
3345 gtk_print_unix_dialog_set_manual_capabilities (GtkPrintUnixDialog   *dialog,
3346                                                GtkPrintCapabilities  capabilities)
3347 {
3348   GtkPrintUnixDialogPrivate *priv = dialog->priv;
3349
3350   priv->manual_capabilities = capabilities;
3351   update_dialog_from_capabilities (dialog);
3352
3353   if (priv->current_printer)
3354     {
3355       GtkTreeSelection *selection;
3356
3357       selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->printer_treeview));
3358
3359       g_object_unref (priv->current_printer);
3360       priv->current_printer = NULL;
3361       priv->internal_printer_change = TRUE;
3362       selected_printer_changed (selection, dialog);
3363       priv->internal_printer_change = FALSE;
3364    }
3365 }
3366
3367 #define __GTK_PRINT_UNIX_DIALOG_C__
3368 #include "gtkaliasdef.c"
3369