]> Pileus Git - ~andy/gtk/blob - gtk/gtkcustompaperunixdialog.c
Change FSF Address
[~andy/gtk] / gtk / gtkcustompaperunixdialog.c
1 /* GtkCustomPaperUnixDialog
2  * Copyright (C) 2006 Alexander Larsson <alexl@redhat.com>
3  * Copyright © 2006, 2007, 2008 Christian Persch
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "config.h"
21 #include <string.h>
22 #include <locale.h>
23
24 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
25 #include <langinfo.h>
26 #endif
27
28 #include "gtkintl.h"
29 #include "gtkprivate.h"
30
31 #include "gtkliststore.h"
32
33 #include "gtktreeviewcolumn.h"
34 #include "gtklabel.h"
35 #include "gtkspinbutton.h"
36
37 #include "gtkcustompaperunixdialog.h"
38 #include "gtkprintbackend.h"
39 #include "gtkprintutils.h"
40
41 #define CUSTOM_PAPER_FILENAME ".gtk-custom-papers"
42
43
44 typedef struct
45 {
46   GtkUnit    display_unit;
47   GtkWidget *spin_button;
48 } UnitWidget;
49
50 struct _GtkCustomPaperUnixDialogPrivate
51 {
52
53   GtkWidget *treeview;
54   GtkWidget *values_box;
55   GtkWidget *printer_combo;
56   GtkWidget *width_widget;
57   GtkWidget *height_widget;
58   GtkWidget *top_widget;
59   GtkWidget *bottom_widget;
60   GtkWidget *left_widget;
61   GtkWidget *right_widget;
62
63   GtkTreeViewColumn *text_column;
64
65   gulong printer_inserted_tag;
66   gulong printer_removed_tag;
67
68   guint request_details_tag;
69   GtkPrinter *request_details_printer;
70
71   guint non_user_change : 1;
72
73   GtkListStore *custom_paper_list;
74   GtkListStore *printer_list;
75
76   GList *print_backends;
77
78   gchar *waiting_for_printer;
79 };
80
81 enum {
82   PRINTER_LIST_COL_NAME,
83   PRINTER_LIST_COL_PRINTER,
84   PRINTER_LIST_N_COLS
85 };
86
87
88 G_DEFINE_TYPE (GtkCustomPaperUnixDialog, gtk_custom_paper_unix_dialog, GTK_TYPE_DIALOG)
89
90
91 static void gtk_custom_paper_unix_dialog_finalize  (GObject                *object);
92 static void populate_dialog                        (GtkCustomPaperUnixDialog *dialog);
93 static void printer_added_cb                       (GtkPrintBackend        *backend,
94                                                     GtkPrinter             *printer,
95                                                     GtkCustomPaperUnixDialog *dialog);
96 static void printer_removed_cb                     (GtkPrintBackend        *backend,
97                                                     GtkPrinter             *printer,
98                                                     GtkCustomPaperUnixDialog *dialog);
99 static void printer_status_cb                      (GtkPrintBackend        *backend,
100                                                     GtkPrinter             *printer,
101                                                     GtkCustomPaperUnixDialog *dialog);
102
103
104
105 GtkUnit
106 _gtk_print_get_default_user_units (void)
107 {
108   /* Translate to the default units to use for presenting
109    * lengths to the user. Translate to default:inch if you
110    * want inches, otherwise translate to default:mm.
111    * Do *not* translate it to "predefinito:mm", if it
112    * it isn't default:mm or default:inch it will not work
113    */
114   gchar *e = _("default:mm");
115
116 #ifdef HAVE__NL_MEASUREMENT_MEASUREMENT
117   gchar *imperial = NULL;
118
119   imperial = nl_langinfo (_NL_MEASUREMENT_MEASUREMENT);
120   if (imperial && imperial[0] == 2 )
121     return GTK_UNIT_INCH;  /* imperial */
122   if (imperial && imperial[0] == 1 )
123     return GTK_UNIT_MM;  /* metric */
124 #endif
125
126   if (strcmp (e, "default:inch")==0)
127     return GTK_UNIT_INCH;
128   else if (strcmp (e, "default:mm"))
129     g_warning ("Whoever translated default:mm did so wrongly.\n");
130   return GTK_UNIT_MM;
131 }
132
133 static char *
134 custom_paper_get_filename (void)
135 {
136   gchar *filename;
137
138   filename = g_build_filename (g_get_home_dir (),
139                                CUSTOM_PAPER_FILENAME, NULL);
140   g_assert (filename != NULL);
141   return filename;
142 }
143
144 GList *
145 _gtk_load_custom_papers (void)
146 {
147   GKeyFile *keyfile;
148   gchar *filename;
149   gchar **groups;
150   gsize n_groups, i;
151   gboolean load_ok;
152   GList *result = NULL;
153
154   filename = custom_paper_get_filename ();
155
156   keyfile = g_key_file_new ();
157   load_ok = g_key_file_load_from_file (keyfile, filename, 0, NULL);
158   g_free (filename);
159   if (!load_ok)
160     {
161       g_key_file_free (keyfile);
162       return NULL;
163     }
164
165   groups = g_key_file_get_groups (keyfile, &n_groups);
166   for (i = 0; i < n_groups; ++i)
167     {
168       GtkPageSetup *page_setup;
169
170       page_setup = gtk_page_setup_new_from_key_file (keyfile, groups[i], NULL);
171       if (!page_setup)
172         continue;
173
174       result = g_list_prepend (result, page_setup);
175     }
176
177   g_strfreev (groups);
178   g_key_file_free (keyfile);
179
180   return g_list_reverse (result);
181 }
182
183 void
184 _gtk_print_load_custom_papers (GtkListStore *store)
185 {
186   GtkTreeIter iter;
187   GList *papers, *p;
188   GtkPageSetup *page_setup;
189
190   gtk_list_store_clear (store);
191
192   papers = _gtk_load_custom_papers ();
193   for (p = papers; p; p = p->next)
194     {
195       page_setup = p->data;
196       gtk_list_store_append (store, &iter);
197       gtk_list_store_set (store, &iter,
198                           0, page_setup,
199                           -1);
200       g_object_unref (page_setup);
201     }
202
203   g_list_free (papers);
204 }
205
206 void
207 _gtk_print_save_custom_papers (GtkListStore *store)
208 {
209   GtkTreeModel *model = GTK_TREE_MODEL (store);
210   GtkTreeIter iter;
211   GKeyFile *keyfile;
212   gchar *filename, *data;
213   gsize len;
214   gint i = 0;
215
216   keyfile = g_key_file_new ();
217
218   if (gtk_tree_model_get_iter_first (model, &iter))
219     {
220       do
221         {
222           GtkPageSetup *page_setup;
223           gchar group[32];
224
225           g_snprintf (group, sizeof (group), "Paper%u", i);
226
227           gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
228
229           gtk_page_setup_to_key_file (page_setup, keyfile, group);
230
231           ++i;
232         } while (gtk_tree_model_iter_next (model, &iter));
233     }
234
235   filename = custom_paper_get_filename ();
236   data = g_key_file_to_data (keyfile, &len, NULL);
237   g_file_set_contents (filename, data, len, NULL);
238   g_free (data);
239   g_free (filename);
240 }
241
242 static void
243 gtk_custom_paper_unix_dialog_class_init (GtkCustomPaperUnixDialogClass *class)
244 {
245   GObjectClass *object_class;
246
247   object_class = (GObjectClass *) class;
248
249   object_class->finalize = gtk_custom_paper_unix_dialog_finalize;
250
251   g_type_class_add_private (class, sizeof (GtkCustomPaperUnixDialogPrivate));
252 }
253
254 static void
255 custom_paper_dialog_response_cb (GtkDialog *dialog,
256                                  gint       response,
257                                  gpointer   user_data)
258 {
259   GtkCustomPaperUnixDialogPrivate *priv = GTK_CUSTOM_PAPER_UNIX_DIALOG (dialog)->priv;
260
261   _gtk_print_save_custom_papers (priv->custom_paper_list);
262 }
263
264 static void
265 gtk_custom_paper_unix_dialog_init (GtkCustomPaperUnixDialog *dialog)
266 {
267   GtkCustomPaperUnixDialogPrivate *priv;
268   GtkTreeIter iter;
269
270   dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
271                                               GTK_TYPE_CUSTOM_PAPER_UNIX_DIALOG,
272                                               GtkCustomPaperUnixDialogPrivate);
273   priv = dialog->priv;
274
275   priv->print_backends = NULL;
276
277   priv->request_details_printer = NULL;
278   priv->request_details_tag = 0;
279
280   priv->printer_list = gtk_list_store_new (PRINTER_LIST_N_COLS,
281                                            G_TYPE_STRING,
282                                            G_TYPE_OBJECT);
283
284   gtk_list_store_append (priv->printer_list, &iter);
285
286   priv->custom_paper_list = gtk_list_store_new (1, G_TYPE_OBJECT);
287   _gtk_print_load_custom_papers (priv->custom_paper_list);
288
289   populate_dialog (dialog);
290
291   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
292                           GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
293                           NULL);
294
295   gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
296
297   g_signal_connect (dialog, "response", G_CALLBACK (custom_paper_dialog_response_cb), NULL);
298 }
299
300 static void
301 gtk_custom_paper_unix_dialog_finalize (GObject *object)
302 {
303   GtkCustomPaperUnixDialog *dialog = GTK_CUSTOM_PAPER_UNIX_DIALOG (object);
304   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
305   GtkPrintBackend *backend;
306   GList *node;
307
308   if (priv->printer_list)
309     {
310       g_signal_handler_disconnect (priv->printer_list, priv->printer_inserted_tag);
311       g_signal_handler_disconnect (priv->printer_list, priv->printer_removed_tag);
312       g_object_unref (priv->printer_list);
313       priv->printer_list = NULL;
314     }
315
316   if (priv->request_details_tag)
317     {
318       g_signal_handler_disconnect (priv->request_details_printer,
319                                    priv->request_details_tag);
320       g_object_unref (priv->request_details_printer);
321       priv->request_details_printer = NULL;
322       priv->request_details_tag = 0;
323     }
324
325   if (priv->custom_paper_list)
326     {
327       g_object_unref (priv->custom_paper_list);
328       priv->custom_paper_list = NULL;
329     }
330
331   g_free (priv->waiting_for_printer);
332   priv->waiting_for_printer = NULL;
333
334   for (node = priv->print_backends; node != NULL; node = node->next)
335     {
336       backend = GTK_PRINT_BACKEND (node->data);
337
338       g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog);
339       g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog);
340       g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog);
341
342       gtk_print_backend_destroy (backend);
343       g_object_unref (backend);
344     }
345
346   g_list_free (priv->print_backends);
347   priv->print_backends = NULL;
348
349   G_OBJECT_CLASS (gtk_custom_paper_unix_dialog_parent_class)->finalize (object);
350 }
351
352 /**
353  * gtk_custom_paper_unix_dialog_new:
354  * @title: (allow-none): the title of the dialog, or %NULL
355  * @parent: (allow-none): transient parent of the dialog, or %NULL
356  *
357  * Creates a new custom paper dialog.
358  *
359  * Returns: the new #GtkCustomPaperUnixDialog
360  *
361  * Since: 2.18
362  */
363 GtkWidget *
364 _gtk_custom_paper_unix_dialog_new (GtkWindow   *parent,
365                                   const gchar *title)
366 {
367   GtkWidget *result;
368
369   if (title == NULL)
370     title = _("Manage Custom Sizes");
371
372   result = g_object_new (GTK_TYPE_CUSTOM_PAPER_UNIX_DIALOG,
373                          "title", title,
374                          "transient-for", parent,
375                          "modal", parent != NULL,
376                          "destroy-with-parent", TRUE,
377                          "resizable", FALSE,
378                          NULL);
379
380   return result;
381 }
382
383 static void
384 printer_added_cb (GtkPrintBackend          *backend,
385                   GtkPrinter               *printer,
386                   GtkCustomPaperUnixDialog *dialog)
387 {
388   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
389   GtkTreeIter iter;
390   gchar *str;
391
392   if (gtk_printer_is_virtual (printer))
393     return;
394
395   str = g_strdup_printf ("<b>%s</b>",
396                          gtk_printer_get_name (printer));
397
398   gtk_list_store_append (priv->printer_list, &iter);
399   gtk_list_store_set (priv->printer_list, &iter,
400                       PRINTER_LIST_COL_NAME, str,
401                       PRINTER_LIST_COL_PRINTER, printer,
402                       -1);
403
404   g_object_set_data_full (G_OBJECT (printer),
405                           "gtk-print-tree-iter",
406                           gtk_tree_iter_copy (&iter),
407                           (GDestroyNotify) gtk_tree_iter_free);
408
409   g_free (str);
410
411   if (priv->waiting_for_printer != NULL &&
412       strcmp (priv->waiting_for_printer,
413               gtk_printer_get_name (printer)) == 0)
414     {
415       gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->printer_combo),
416                                      &iter);
417       priv->waiting_for_printer = NULL;
418     }
419 }
420
421 static void
422 printer_removed_cb (GtkPrintBackend        *backend,
423                     GtkPrinter             *printer,
424                     GtkCustomPaperUnixDialog *dialog)
425 {
426   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
427   GtkTreeIter *iter;
428
429   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
430   gtk_list_store_remove (GTK_LIST_STORE (priv->printer_list), iter);
431 }
432
433
434 static void
435 printer_status_cb (GtkPrintBackend        *backend,
436                    GtkPrinter             *printer,
437                    GtkCustomPaperUnixDialog *dialog)
438 {
439   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
440   GtkTreeIter *iter;
441   gchar *str;
442
443   iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
444
445   str = g_strdup_printf ("<b>%s</b>",
446                          gtk_printer_get_name (printer));
447   gtk_list_store_set (priv->printer_list, iter,
448                       PRINTER_LIST_COL_NAME, str,
449                       -1);
450   g_free (str);
451 }
452
453 static void
454 printer_list_initialize (GtkCustomPaperUnixDialog *dialog,
455                          GtkPrintBackend        *print_backend)
456 {
457   GList *list, *node;
458
459   g_return_if_fail (print_backend != NULL);
460
461   g_signal_connect_object (print_backend,
462                            "printer-added",
463                            (GCallback) printer_added_cb,
464                            G_OBJECT (dialog), 0);
465
466   g_signal_connect_object (print_backend,
467                            "printer-removed",
468                            (GCallback) printer_removed_cb,
469                            G_OBJECT (dialog), 0);
470
471   g_signal_connect_object (print_backend,
472                            "printer-status-changed",
473                            (GCallback) printer_status_cb,
474                            G_OBJECT (dialog), 0);
475
476   list = gtk_print_backend_get_printer_list (print_backend);
477
478   node = list;
479   while (node != NULL)
480     {
481       printer_added_cb (print_backend, node->data, dialog);
482       node = node->next;
483     }
484
485   g_list_free (list);
486 }
487
488 static void
489 load_print_backends (GtkCustomPaperUnixDialog *dialog)
490 {
491   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
492   GList *node;
493
494   if (g_module_supported ())
495     priv->print_backends = gtk_print_backend_load_modules ();
496
497   for (node = priv->print_backends; node != NULL; node = node->next)
498     printer_list_initialize (dialog, GTK_PRINT_BACKEND (node->data));
499 }
500
501 static void unit_widget_changed (GtkCustomPaperUnixDialog *dialog);
502
503 static GtkWidget *
504 new_unit_widget (GtkCustomPaperUnixDialog *dialog,
505                  GtkUnit                   unit,
506                  GtkWidget                *mnemonic_label)
507 {
508   GtkWidget *hbox, *button, *label;
509   UnitWidget *data;
510
511   data = g_new0 (UnitWidget, 1);
512   data->display_unit = unit;
513
514   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
515
516   button = gtk_spin_button_new_with_range (0.0, 9999.0, 1);
517   if (unit == GTK_UNIT_INCH)
518     gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), 2);
519   else
520     gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), 1);
521
522   gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
523   gtk_widget_show (button);
524
525   data->spin_button = button;
526
527   g_signal_connect_swapped (button, "value-changed",
528                             G_CALLBACK (unit_widget_changed), dialog);
529
530   if (unit == GTK_UNIT_INCH)
531     label = gtk_label_new (_("inch"));
532   else
533     label = gtk_label_new (_("mm"));
534
535   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
536   gtk_widget_show (label);
537   gtk_label_set_mnemonic_widget (GTK_LABEL (mnemonic_label), button);
538
539   g_object_set_data_full (G_OBJECT (hbox), "unit-data", data, g_free);
540
541   return hbox;
542 }
543
544 static double
545 unit_widget_get (GtkWidget *unit_widget)
546 {
547   UnitWidget *data = g_object_get_data (G_OBJECT (unit_widget), "unit-data");
548   return _gtk_print_convert_to_mm (gtk_spin_button_get_value (GTK_SPIN_BUTTON (data->spin_button)),
549                                    data->display_unit);
550 }
551
552 static void
553 unit_widget_set (GtkWidget *unit_widget,
554                  gdouble    value)
555 {
556   UnitWidget *data;
557
558   data = g_object_get_data (G_OBJECT (unit_widget), "unit-data");
559   gtk_spin_button_set_value (GTK_SPIN_BUTTON (data->spin_button),
560                              _gtk_print_convert_from_mm (value, data->display_unit));
561 }
562
563 static void
564 custom_paper_printer_data_func (GtkCellLayout   *cell_layout,
565                                 GtkCellRenderer *cell,
566                                 GtkTreeModel    *tree_model,
567                                 GtkTreeIter     *iter,
568                                 gpointer         data)
569 {
570   GtkPrinter *printer;
571
572   gtk_tree_model_get (tree_model, iter,
573                       PRINTER_LIST_COL_PRINTER, &printer, -1);
574
575   if (printer)
576     g_object_set (cell, "text",  gtk_printer_get_name (printer), NULL);
577   else
578     g_object_set (cell, "text",  _("Margins from Printer..."), NULL);
579
580   if (printer)
581     g_object_unref (printer);
582 }
583
584 static void
585 update_combo_sensitivity_from_printers (GtkCustomPaperUnixDialog *dialog)
586 {
587   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
588   GtkTreeIter iter;
589   gboolean sensitive;
590   GtkTreeSelection *selection;
591   GtkTreeModel *model;
592
593   sensitive = FALSE;
594   model = GTK_TREE_MODEL (priv->printer_list);
595   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
596   if (gtk_tree_model_get_iter_first (model, &iter) &&
597       gtk_tree_model_iter_next (model, &iter) &&
598       gtk_tree_selection_get_selected (selection, NULL, &iter))
599     sensitive = TRUE;
600
601   gtk_widget_set_sensitive (priv->printer_combo, sensitive);
602 }
603
604 static void
605 update_custom_widgets_from_list (GtkCustomPaperUnixDialog *dialog)
606 {
607   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
608   GtkTreeSelection *selection;
609   GtkTreeModel *model;
610   GtkTreeIter iter;
611   GtkPageSetup *page_setup;
612
613   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
614   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
615
616   priv->non_user_change = TRUE;
617   if (gtk_tree_selection_get_selected (selection, NULL, &iter))
618     {
619       gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
620
621       unit_widget_set (priv->width_widget,
622                        gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM));
623       unit_widget_set (priv->height_widget,
624                        gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM));
625       unit_widget_set (priv->top_widget,
626                        gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM));
627       unit_widget_set (priv->bottom_widget,
628                        gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM));
629       unit_widget_set (priv->left_widget,
630                        gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM));
631       unit_widget_set (priv->right_widget,
632                        gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM));
633
634       gtk_widget_set_sensitive (priv->values_box, TRUE);
635     }
636   else
637     {
638       gtk_widget_set_sensitive (priv->values_box, FALSE);
639     }
640
641   if (priv->printer_list)
642     update_combo_sensitivity_from_printers (dialog);
643   priv->non_user_change = FALSE;
644 }
645
646 static void
647 selected_custom_paper_changed (GtkTreeSelection         *selection,
648                                GtkCustomPaperUnixDialog *dialog)
649 {
650   update_custom_widgets_from_list (dialog);
651 }
652
653 static void
654 unit_widget_changed (GtkCustomPaperUnixDialog *dialog)
655 {
656   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
657   gdouble w, h, top, bottom, left, right;
658   GtkTreeSelection *selection;
659   GtkTreeIter iter;
660   GtkPageSetup *page_setup;
661   GtkPaperSize *paper_size;
662
663   if (priv->non_user_change)
664     return;
665
666   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
667
668   if (gtk_tree_selection_get_selected (selection, NULL, &iter))
669     {
670       gtk_tree_model_get (GTK_TREE_MODEL (priv->custom_paper_list), &iter, 0, &page_setup, -1);
671
672       w = unit_widget_get (priv->width_widget);
673       h = unit_widget_get (priv->height_widget);
674
675       paper_size = gtk_page_setup_get_paper_size (page_setup);
676       gtk_paper_size_set_size (paper_size, w, h, GTK_UNIT_MM);
677
678       top = unit_widget_get (priv->top_widget);
679       bottom = unit_widget_get (priv->bottom_widget);
680       left = unit_widget_get (priv->left_widget);
681       right = unit_widget_get (priv->right_widget);
682
683       gtk_page_setup_set_top_margin (page_setup, top, GTK_UNIT_MM);
684       gtk_page_setup_set_bottom_margin (page_setup, bottom, GTK_UNIT_MM);
685       gtk_page_setup_set_left_margin (page_setup, left, GTK_UNIT_MM);
686       gtk_page_setup_set_right_margin (page_setup, right, GTK_UNIT_MM);
687
688       g_object_unref (page_setup);
689     }
690 }
691
692 static gboolean
693 custom_paper_name_used (GtkCustomPaperUnixDialog *dialog,
694                         const gchar              *name)
695 {
696   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
697   GtkTreeModel *model;
698   GtkTreeIter iter;
699   GtkPageSetup *page_setup;
700   GtkPaperSize *paper_size;
701
702   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
703
704   if (gtk_tree_model_get_iter_first (model, &iter))
705     {
706       do
707         {
708           gtk_tree_model_get (model, &iter, 0, &page_setup, -1);
709           paper_size = gtk_page_setup_get_paper_size (page_setup);
710           if (strcmp (name,
711                       gtk_paper_size_get_name (paper_size)) == 0)
712             {
713               g_object_unref (page_setup);
714               return TRUE;
715             }
716           g_object_unref (page_setup);
717         } while (gtk_tree_model_iter_next (model, &iter));
718     }
719
720   return FALSE;
721 }
722
723 static void
724 add_custom_paper (GtkCustomPaperUnixDialog *dialog)
725 {
726   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
727   GtkListStore *store;
728   GtkPageSetup *page_setup;
729   GtkPaperSize *paper_size;
730   GtkTreeSelection *selection;
731   GtkTreePath *path;
732   GtkTreeIter iter;
733   gchar *name;
734   gint i;
735
736   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
737   store = priv->custom_paper_list;
738
739   i = 1;
740   name = NULL;
741   do
742     {
743       g_free (name);
744       name = g_strdup_printf (_("Custom Size %d"), i);
745       i++;
746     } while (custom_paper_name_used (dialog, name));
747
748   page_setup = gtk_page_setup_new ();
749   paper_size = gtk_paper_size_new_custom (name, name,
750                                           gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM),
751                                           gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM),
752                                           GTK_UNIT_MM);
753   gtk_page_setup_set_paper_size (page_setup, paper_size);
754   gtk_paper_size_free (paper_size);
755
756   gtk_list_store_append (store, &iter);
757   gtk_list_store_set (store, &iter, 0, page_setup, -1);
758   g_object_unref (page_setup);
759
760   gtk_tree_selection_select_iter (selection, &iter);
761   path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
762   gtk_widget_grab_focus (priv->treeview);
763   gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->treeview), path,
764                             priv->text_column, TRUE);
765   gtk_tree_path_free (path);
766   g_free (name);
767 }
768
769 static void
770 remove_custom_paper (GtkCustomPaperUnixDialog *dialog)
771 {
772   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
773   GtkTreeSelection *selection;
774   GtkTreeIter iter;
775   GtkListStore *store;
776
777   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
778   store = priv->custom_paper_list;
779
780   if (gtk_tree_selection_get_selected (selection, NULL, &iter))
781     {
782       GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
783       gtk_list_store_remove (store, &iter);
784
785       if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
786         gtk_tree_selection_select_iter (selection, &iter);
787       else if (gtk_tree_path_prev (path) && gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
788         gtk_tree_selection_select_iter (selection, &iter);
789
790       gtk_tree_path_free (path);
791     }
792 }
793
794 static void
795 set_margins_from_printer (GtkCustomPaperUnixDialog *dialog,
796                           GtkPrinter               *printer)
797 {
798   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
799   gdouble top, bottom, left, right;
800
801   top = bottom = left = right = 0;
802   if (!gtk_printer_get_hard_margins (printer, &top, &bottom, &left, &right))
803     return;
804
805   priv->non_user_change = TRUE;
806   unit_widget_set (priv->top_widget, _gtk_print_convert_to_mm (top, GTK_UNIT_POINTS));
807   unit_widget_set (priv->bottom_widget, _gtk_print_convert_to_mm (bottom, GTK_UNIT_POINTS));
808   unit_widget_set (priv->left_widget, _gtk_print_convert_to_mm (left, GTK_UNIT_POINTS));
809   unit_widget_set (priv->right_widget, _gtk_print_convert_to_mm (right, GTK_UNIT_POINTS));
810   priv->non_user_change = FALSE;
811
812   /* Only send one change */
813   unit_widget_changed (dialog);
814 }
815
816 static void
817 get_margins_finished_callback (GtkPrinter               *printer,
818                                gboolean                  success,
819                                GtkCustomPaperUnixDialog *dialog)
820 {
821   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
822
823   g_signal_handler_disconnect (priv->request_details_printer,
824                                priv->request_details_tag);
825   g_object_unref (priv->request_details_printer);
826   priv->request_details_tag = 0;
827   priv->request_details_printer = NULL;
828
829   if (success)
830     set_margins_from_printer (dialog, printer);
831
832   gtk_combo_box_set_active (GTK_COMBO_BOX (priv->printer_combo), 0);
833 }
834
835 static void
836 margins_from_printer_changed (GtkCustomPaperUnixDialog *dialog)
837 {
838   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
839   GtkTreeIter iter;
840   GtkComboBox *combo;
841   GtkPrinter *printer;
842
843   combo = GTK_COMBO_BOX (priv->printer_combo);
844
845   if (priv->request_details_tag)
846     {
847       g_signal_handler_disconnect (priv->request_details_printer,
848                                    priv->request_details_tag);
849       g_object_unref (priv->request_details_printer);
850       priv->request_details_printer = NULL;
851       priv->request_details_tag = 0;
852     }
853
854   if (gtk_combo_box_get_active_iter (combo, &iter))
855     {
856       gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
857                           PRINTER_LIST_COL_PRINTER, &printer, -1);
858
859       if (printer)
860         {
861           if (gtk_printer_has_details (printer))
862             {
863               set_margins_from_printer (dialog, printer);
864               gtk_combo_box_set_active (combo, 0);
865             }
866           else
867             {
868               priv->request_details_printer = g_object_ref (printer);
869               priv->request_details_tag =
870                 g_signal_connect (printer, "details-acquired",
871                                   G_CALLBACK (get_margins_finished_callback), dialog);
872               gtk_printer_request_details (printer);
873             }
874
875           g_object_unref (printer);
876         }
877     }
878 }
879
880 static void
881 custom_size_name_edited (GtkCellRenderer          *cell,
882                          gchar                    *path_string,
883                          gchar                    *new_text,
884                          GtkCustomPaperUnixDialog *dialog)
885 {
886   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
887   GtkTreePath *path;
888   GtkTreeIter iter;
889   GtkListStore *store;
890   GtkPageSetup *page_setup;
891   GtkPaperSize *paper_size;
892
893   store = priv->custom_paper_list;
894   path = gtk_tree_path_new_from_string (path_string);
895   gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
896   gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &page_setup, -1);
897   gtk_tree_path_free (path);
898
899   paper_size = gtk_paper_size_new_custom (new_text, new_text,
900                                           gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM),
901                                           gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM),
902                                           GTK_UNIT_MM);
903   gtk_page_setup_set_paper_size (page_setup, paper_size);
904   gtk_paper_size_free (paper_size);
905
906   g_object_unref (page_setup);
907 }
908
909 static void
910 custom_name_func (GtkTreeViewColumn *tree_column,
911                   GtkCellRenderer   *cell,
912                   GtkTreeModel      *tree_model,
913                   GtkTreeIter       *iter,
914                   gpointer           data)
915 {
916   GtkPageSetup *page_setup;
917   GtkPaperSize *paper_size;
918
919   gtk_tree_model_get (tree_model, iter, 0, &page_setup, -1);
920   if (page_setup)
921     {
922       paper_size = gtk_page_setup_get_paper_size (page_setup);
923       g_object_set (cell, "text",  gtk_paper_size_get_display_name (paper_size), NULL);
924       g_object_unref (page_setup);
925     }
926 }
927
928 static GtkWidget *
929 wrap_in_frame (const gchar *label,
930                GtkWidget   *child)
931 {
932   GtkWidget *frame, *label_widget;
933   gchar *bold_text;
934
935   label_widget = gtk_label_new (NULL);
936   gtk_widget_set_halign (label_widget, GTK_ALIGN_START);
937   gtk_widget_set_valign (label_widget, GTK_ALIGN_CENTER);
938   gtk_widget_show (label_widget);
939
940   bold_text = g_markup_printf_escaped ("<b>%s</b>", label);
941   gtk_label_set_markup (GTK_LABEL (label_widget), bold_text);
942   g_free (bold_text);
943
944   frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
945   gtk_box_pack_start (GTK_BOX (frame), label_widget, FALSE, FALSE, 0);
946
947   gtk_widget_set_margin_left (child, 12);
948   gtk_widget_set_halign (child, GTK_ALIGN_FILL);
949   gtk_widget_set_valign (child, GTK_ALIGN_FILL);
950
951   gtk_box_pack_start (GTK_BOX (frame), child, FALSE, FALSE, 0);
952
953   gtk_widget_show (frame);
954
955   return frame;
956 }
957
958 static GtkWidget *
959 toolbutton_new (GtkCustomPaperUnixDialog *dialog,
960                 GIcon                    *icon,
961                 gboolean                  sensitive,
962                 gboolean                  show,
963                 GCallback                 callback)
964 {
965   GtkToolItem *item;
966   GtkWidget *image;
967
968   item = gtk_tool_button_new (NULL, NULL);
969   image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_SMALL_TOOLBAR);
970   gtk_widget_show (image);
971   gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (item), image);
972
973   gtk_widget_set_sensitive (GTK_WIDGET (item), sensitive);
974   g_signal_connect_swapped (item, "clicked", callback, dialog);
975
976   if (show)
977     gtk_widget_show (GTK_WIDGET (item));
978
979   return GTK_WIDGET (item);
980 }
981
982 static void
983 populate_dialog (GtkCustomPaperUnixDialog *dialog)
984 {
985   GtkCustomPaperUnixDialogPrivate *priv = dialog->priv;
986   GtkDialog *cpu_dialog = GTK_DIALOG (dialog);
987   GtkWidget *action_area, *content_area;
988   GtkWidget *grid, *label, *widget, *frame, *combo;
989   GtkWidget *hbox, *vbox, *treeview, *scrolled, *toolbar, *button;
990   GtkCellRenderer *cell;
991   GtkTreeViewColumn *column;
992   GtkTreeIter iter;
993   GtkTreeSelection *selection;
994   GtkUnit user_units;
995   GIcon *icon;
996   GtkStyleContext *context;
997
998   content_area = gtk_dialog_get_content_area (cpu_dialog);
999   action_area = gtk_dialog_get_action_area (cpu_dialog);
1000
1001   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1002   gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
1003   gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
1004   gtk_box_set_spacing (GTK_BOX (action_area), 6);
1005
1006   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 18);
1007   gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
1008   gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 0);
1009   gtk_widget_show (hbox);
1010
1011   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1012   gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
1013   gtk_widget_show (vbox);
1014
1015   scrolled = gtk_scrolled_window_new (NULL, NULL);
1016   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1017                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1018   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
1019                                        GTK_SHADOW_IN);
1020   gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
1021   gtk_widget_show (scrolled);
1022
1023   context = gtk_widget_get_style_context (scrolled);
1024   gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
1025
1026   treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->custom_paper_list));
1027   priv->treeview = treeview;
1028   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
1029   gtk_widget_set_size_request (treeview, 140, -1);
1030
1031   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
1032   gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1033   g_signal_connect (selection, "changed", G_CALLBACK (selected_custom_paper_changed), dialog);
1034
1035   cell = gtk_cell_renderer_text_new ();
1036   g_object_set (cell, "editable", TRUE, NULL);
1037   g_signal_connect (cell, "edited",
1038                     G_CALLBACK (custom_size_name_edited), dialog);
1039   priv->text_column = column =
1040     gtk_tree_view_column_new_with_attributes ("paper", cell, NULL);
1041   gtk_tree_view_column_set_cell_data_func  (column, cell, custom_name_func, NULL, NULL);
1042
1043   gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
1044
1045   gtk_container_add (GTK_CONTAINER (scrolled), treeview);
1046   gtk_widget_show (treeview);
1047
1048   toolbar = gtk_toolbar_new ();
1049   gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_MENU);
1050
1051   context = gtk_widget_get_style_context (toolbar);
1052   gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
1053   gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR);
1054
1055   gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
1056   gtk_widget_show (toolbar);
1057
1058   icon = g_themed_icon_new_with_default_fallbacks ("list-add-symbolic");
1059   button = toolbutton_new (dialog, icon, TRUE, TRUE, G_CALLBACK (add_custom_paper));
1060   g_object_unref (icon);
1061
1062   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (button), 0);
1063
1064   icon = g_themed_icon_new_with_default_fallbacks ("list-remove-symbolic");
1065   button = toolbutton_new (dialog, icon, TRUE, TRUE, G_CALLBACK (remove_custom_paper));
1066   g_object_unref (icon);
1067
1068   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (button), 1);
1069
1070   user_units = _gtk_print_get_default_user_units ();
1071
1072   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
1073   priv->values_box = vbox;
1074   gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
1075   gtk_widget_show (vbox);
1076
1077   grid = gtk_grid_new ();
1078
1079   gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
1080   gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
1081
1082   label = gtk_label_new_with_mnemonic (_("_Width:"));
1083   gtk_widget_set_halign (label, GTK_ALIGN_START);
1084   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1085   gtk_widget_show (label);
1086   gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
1087
1088   widget = new_unit_widget (dialog, user_units, label);
1089   priv->width_widget = widget;
1090   gtk_grid_attach (GTK_GRID (grid), widget, 1, 0, 1, 1);
1091   gtk_widget_show (widget);
1092
1093   label = gtk_label_new_with_mnemonic (_("_Height:"));
1094   gtk_widget_set_halign (label, GTK_ALIGN_START);
1095   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1096   gtk_widget_show (label);
1097   gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
1098
1099   widget = new_unit_widget (dialog, user_units, label);
1100   priv->height_widget = widget;
1101   gtk_grid_attach (GTK_GRID (grid), widget, 1, 1, 1, 1);
1102   gtk_widget_show (widget);
1103
1104   frame = wrap_in_frame (_("Paper Size"), grid);
1105   gtk_widget_show (grid);
1106   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
1107   gtk_widget_show (frame);
1108
1109   grid = gtk_grid_new ();
1110   gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
1111   gtk_grid_set_column_spacing (GTK_GRID (grid), 12);
1112
1113   label = gtk_label_new_with_mnemonic (_("_Top:"));
1114   gtk_widget_set_halign (label, GTK_ALIGN_START);
1115   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1116   gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
1117   gtk_widget_show (label);
1118
1119   widget = new_unit_widget (dialog, user_units, label);
1120   priv->top_widget = widget;
1121   gtk_grid_attach (GTK_GRID (grid), widget, 1, 0, 1, 1);
1122   gtk_widget_show (widget);
1123
1124   label = gtk_label_new_with_mnemonic (_("_Bottom:"));
1125   gtk_widget_set_halign (label, GTK_ALIGN_START);
1126   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1127   gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
1128   gtk_widget_show (label);
1129
1130   widget = new_unit_widget (dialog, user_units, label);
1131   priv->bottom_widget = widget;
1132   gtk_grid_attach (GTK_GRID (grid), widget, 1, 1, 1, 1);
1133   gtk_widget_show (widget);
1134
1135   label = gtk_label_new_with_mnemonic (_("_Left:"));
1136   gtk_widget_set_halign (label, GTK_ALIGN_START);
1137   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1138   gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
1139   gtk_widget_show (label);
1140
1141   widget = new_unit_widget (dialog, user_units, label);
1142   priv->left_widget = widget;
1143   gtk_grid_attach (GTK_GRID (grid), widget, 1, 2, 1, 1);
1144   gtk_widget_show (widget);
1145
1146   label = gtk_label_new_with_mnemonic (_("_Right:"));
1147   gtk_widget_set_halign (label, GTK_ALIGN_START);
1148   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
1149   gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 1, 1);
1150   gtk_widget_show (label);
1151
1152   widget = new_unit_widget (dialog, user_units, label);
1153   priv->right_widget = widget;
1154   gtk_grid_attach (GTK_GRID (grid), widget, 1, 3, 1, 1);
1155   gtk_widget_show (widget);
1156
1157   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1158   gtk_grid_attach (GTK_GRID (grid), hbox, 0, 4, 2, 1);
1159   gtk_widget_show (hbox);
1160
1161   combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (priv->printer_list));
1162   priv->printer_combo = combo;
1163
1164   priv->printer_inserted_tag =
1165     g_signal_connect_swapped (priv->printer_list, "row-inserted",
1166                               G_CALLBACK (update_combo_sensitivity_from_printers), dialog);
1167   priv->printer_removed_tag =
1168     g_signal_connect_swapped (priv->printer_list, "row-deleted",
1169                               G_CALLBACK (update_combo_sensitivity_from_printers), dialog);
1170   update_combo_sensitivity_from_printers (dialog);
1171
1172   cell = gtk_cell_renderer_text_new ();
1173   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
1174   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), cell,
1175                                       custom_paper_printer_data_func,
1176                                       NULL, NULL);
1177
1178   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
1179   gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
1180   gtk_widget_show (combo);
1181
1182   g_signal_connect_swapped (combo, "changed",
1183                             G_CALLBACK (margins_from_printer_changed), dialog);
1184
1185   frame = wrap_in_frame (_("Paper Margins"), grid);
1186   gtk_widget_show (grid);
1187   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
1188   gtk_widget_show (frame);
1189
1190   update_custom_widgets_from_list (dialog);
1191
1192   /* If no custom sizes, add one */
1193   if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->custom_paper_list),
1194                                       &iter))
1195     {
1196       /* Need to realize treeview so we can start the rename */
1197       gtk_widget_realize (treeview);
1198       add_custom_paper (dialog);
1199     }
1200
1201   gtk_window_present (GTK_WINDOW (dialog));
1202   load_print_backends (dialog);
1203 }