]> Pileus Git - ~andy/gtk/blob - gtk/gtkprinteroptionwidget.c
Change FSF Address
[~andy/gtk] / gtk / gtkprinteroptionwidget.c
1 /* GtkPrinterOptionWidget
2  * Copyright (C) 2006 Alexander Larsson  <alexl@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "config.h"
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <ctype.h>
23
24 #include "gtkintl.h"
25 #include "gtkcheckbutton.h"
26 #include "gtkcelllayout.h"
27 #include "gtkcellrenderertext.h"
28 #include "gtkcombobox.h"
29 #include "gtkfilechooserbutton.h"
30 #include "gtkimage.h"
31 #include "gtklabel.h"
32 #include "gtkliststore.h"
33 #include "gtkradiobutton.h"
34 #include "gtkstock.h"
35 #include "gtkgrid.h"
36 #include "gtktogglebutton.h"
37 #include "gtkorientable.h"
38 #include "gtkprivate.h"
39
40 #include "gtkprinteroptionwidget.h"
41
42 #define GTK_PRINTER_OPTION_WIDGET_GET_PRIVATE(o)  \
43    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINTER_OPTION_WIDGET, GtkPrinterOptionWidgetPrivate))
44
45 static void gtk_printer_option_widget_finalize (GObject *object);
46
47 static void deconstruct_widgets (GtkPrinterOptionWidget *widget);
48 static void construct_widgets (GtkPrinterOptionWidget *widget);
49 static void update_widgets (GtkPrinterOptionWidget *widget);
50
51 struct GtkPrinterOptionWidgetPrivate
52 {
53   GtkPrinterOption *source;
54   gulong source_changed_handler;
55   
56   GtkWidget *check;
57   GtkWidget *combo;
58   GtkWidget *entry;
59   GtkWidget *image;
60   GtkWidget *label;
61   GtkWidget *info_label;
62   GtkWidget *filechooser;
63   GtkWidget *box;
64 };
65
66 enum {
67   CHANGED,
68   LAST_SIGNAL
69 };
70
71 enum {
72   PROP_0,
73   PROP_SOURCE
74 };
75
76 static guint signals[LAST_SIGNAL] = { 0 };
77
78 G_DEFINE_TYPE (GtkPrinterOptionWidget, gtk_printer_option_widget, GTK_TYPE_BOX)
79
80 static void gtk_printer_option_widget_set_property (GObject      *object,
81                                                     guint         prop_id,
82                                                     const GValue *value,
83                                                     GParamSpec   *pspec);
84 static void gtk_printer_option_widget_get_property (GObject      *object,
85                                                     guint         prop_id,
86                                                     GValue       *value,
87                                                     GParamSpec   *pspec);
88 static gboolean gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
89                                                               gboolean  group_cycling);
90
91 static void
92 gtk_printer_option_widget_class_init (GtkPrinterOptionWidgetClass *class)
93 {
94   GObjectClass *object_class;
95   GtkWidgetClass *widget_class;
96
97   object_class = (GObjectClass *) class;
98   widget_class = (GtkWidgetClass *) class;
99
100   object_class->finalize = gtk_printer_option_widget_finalize;
101   object_class->set_property = gtk_printer_option_widget_set_property;
102   object_class->get_property = gtk_printer_option_widget_get_property;
103
104   widget_class->mnemonic_activate = gtk_printer_option_widget_mnemonic_activate;
105
106   g_type_class_add_private (class, sizeof (GtkPrinterOptionWidgetPrivate));
107
108   signals[CHANGED] =
109     g_signal_new ("changed",
110                   G_TYPE_FROM_CLASS (class),
111                   G_SIGNAL_RUN_LAST,
112                   G_STRUCT_OFFSET (GtkPrinterOptionWidgetClass, changed),
113                   NULL, NULL,
114                   g_cclosure_marshal_VOID__VOID,
115                   G_TYPE_NONE, 0);
116
117   g_object_class_install_property (object_class,
118                                    PROP_SOURCE,
119                                    g_param_spec_object ("source",
120                                                         P_("Source option"),
121                                                         P_("The PrinterOption backing this widget"),
122                                                         GTK_TYPE_PRINTER_OPTION,
123                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
124
125 }
126
127 static void
128 gtk_printer_option_widget_init (GtkPrinterOptionWidget *widget)
129 {
130   widget->priv = GTK_PRINTER_OPTION_WIDGET_GET_PRIVATE (widget); 
131
132   gtk_box_set_spacing (GTK_BOX (widget), 12);
133 }
134
135 static void
136 gtk_printer_option_widget_finalize (GObject *object)
137 {
138   GtkPrinterOptionWidget *widget = GTK_PRINTER_OPTION_WIDGET (object);
139   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
140   
141   if (priv->source)
142     {
143       g_object_unref (priv->source);
144       priv->source = NULL;
145     }
146   
147   G_OBJECT_CLASS (gtk_printer_option_widget_parent_class)->finalize (object);
148 }
149
150 static void
151 gtk_printer_option_widget_set_property (GObject         *object,
152                                         guint            prop_id,
153                                         const GValue    *value,
154                                         GParamSpec      *pspec)
155 {
156   GtkPrinterOptionWidget *widget;
157   
158   widget = GTK_PRINTER_OPTION_WIDGET (object);
159
160   switch (prop_id)
161     {
162     case PROP_SOURCE:
163       gtk_printer_option_widget_set_source (widget, g_value_get_object (value));
164       break;
165     default:
166       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
167       break;
168     }
169 }
170
171 static void
172 gtk_printer_option_widget_get_property (GObject    *object,
173                                         guint       prop_id,
174                                         GValue     *value,
175                                         GParamSpec *pspec)
176 {
177   GtkPrinterOptionWidget *widget = GTK_PRINTER_OPTION_WIDGET (object);
178   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
179
180   switch (prop_id)
181     {
182     case PROP_SOURCE:
183       g_value_set_object (value, priv->source);
184       break;
185     default:
186       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
187       break;
188     }
189 }
190
191 static gboolean
192 gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
193                                              gboolean   group_cycling)
194 {
195   GtkPrinterOptionWidget *powidget = GTK_PRINTER_OPTION_WIDGET (widget);
196   GtkPrinterOptionWidgetPrivate *priv = powidget->priv;
197
198   if (priv->check)
199     return gtk_widget_mnemonic_activate (priv->check, group_cycling);
200   if (priv->combo)
201     return gtk_widget_mnemonic_activate (priv->combo, group_cycling);
202   if (priv->entry)
203     return gtk_widget_mnemonic_activate (priv->entry, group_cycling);
204
205   return FALSE;
206 }
207
208 static void
209 emit_changed (GtkPrinterOptionWidget *widget)
210 {
211   g_signal_emit (widget, signals[CHANGED], 0);
212 }
213
214 GtkWidget *
215 gtk_printer_option_widget_new (GtkPrinterOption *source)
216 {
217   return g_object_new (GTK_TYPE_PRINTER_OPTION_WIDGET, "source", source, NULL);
218 }
219
220 static void
221 source_changed_cb (GtkPrinterOption *source,
222                    GtkPrinterOptionWidget  *widget)
223 {
224   update_widgets (widget);
225   emit_changed (widget);
226 }
227
228 void
229 gtk_printer_option_widget_set_source (GtkPrinterOptionWidget *widget,
230                                       GtkPrinterOption       *source)
231 {
232   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
233
234   if (source)
235     g_object_ref (source);
236   
237   if (priv->source)
238     {
239       g_signal_handler_disconnect (priv->source,
240                                    priv->source_changed_handler);
241       g_object_unref (priv->source);
242     }
243
244   priv->source = source;
245
246   if (source)
247     priv->source_changed_handler =
248       g_signal_connect (source, "changed", G_CALLBACK (source_changed_cb), widget);
249
250   construct_widgets (widget);
251   update_widgets (widget);
252
253   g_object_notify (G_OBJECT (widget), "source");
254 }
255
256 enum {
257   NAME_COLUMN,
258   VALUE_COLUMN,
259   N_COLUMNS
260 };
261
262 static void
263 combo_box_set_model (GtkWidget *combo_box)
264 {
265   GtkListStore *store;
266
267   store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
268   gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), GTK_TREE_MODEL (store));
269   g_object_unref (store);
270 }
271
272 static void
273 combo_box_set_view (GtkWidget *combo_box)
274 {
275   GtkCellRenderer *cell;
276
277   cell = gtk_cell_renderer_text_new ();
278   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
279   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
280                                   "text", NAME_COLUMN,
281                                    NULL);
282 }
283
284 static GtkWidget *
285 combo_box_entry_new (void)
286 {
287   GtkWidget *combo_box;
288   combo_box = g_object_new (GTK_TYPE_COMBO_BOX, "has-entry", TRUE, NULL);
289
290   combo_box_set_model (combo_box);
291
292   gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (combo_box), NAME_COLUMN);
293
294   return combo_box;
295 }
296
297 static GtkWidget *
298 combo_box_new (void)
299 {
300   GtkWidget *combo_box;
301   combo_box = gtk_combo_box_new ();
302
303   combo_box_set_model (combo_box);
304   combo_box_set_view (combo_box);
305
306   return combo_box;
307 }
308   
309 static void
310 combo_box_append (GtkWidget   *combo,
311                   const gchar *display_text,
312                   const gchar *value)
313 {
314   GtkTreeModel *model;
315   GtkListStore *store;
316   GtkTreeIter iter;
317   
318   model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
319   store = GTK_LIST_STORE (model);
320
321   gtk_list_store_append (store, &iter);
322   gtk_list_store_set (store, &iter,
323                       NAME_COLUMN, display_text,
324                       VALUE_COLUMN, value,
325                       -1);
326 }
327
328 struct ComboSet {
329   GtkComboBox *combo;
330   const gchar *value;
331 };
332
333 static gboolean
334 set_cb (GtkTreeModel *model, 
335         GtkTreePath  *path, 
336         GtkTreeIter  *iter, 
337         gpointer      data)
338 {
339   struct ComboSet *set_data = data;
340   gboolean found;
341   char *value;
342   
343   gtk_tree_model_get (model, iter, VALUE_COLUMN, &value, -1);
344   found = (strcmp (value, set_data->value) == 0);
345   g_free (value);
346   
347   if (found)
348     gtk_combo_box_set_active_iter (set_data->combo, iter);
349
350   return found;
351 }
352
353 static void
354 combo_box_set (GtkWidget   *combo,
355                const gchar *value)
356 {
357   GtkTreeModel *model;
358   struct ComboSet set_data;
359   
360   model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
361
362   set_data.combo = GTK_COMBO_BOX (combo);
363   set_data.value = value;
364   gtk_tree_model_foreach (model, set_cb, &set_data);
365 }
366
367 static gchar *
368 combo_box_get (GtkWidget *combo, gboolean *custom)
369 {
370   GtkTreeModel *model;
371   gchar *value;
372   GtkTreeIter iter;
373
374   model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
375
376   value = NULL;
377   if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
378     {
379       gtk_tree_model_get (model, &iter, VALUE_COLUMN, &value, -1);
380       *custom = FALSE;
381     }
382   else
383     {
384       if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (combo)))
385         {
386           value = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo)))));
387           *custom = TRUE;
388         }
389
390       if (!value || !gtk_tree_model_get_iter_first (model, &iter))
391         return value;
392
393       /* If the user entered an item from the dropdown list manually, return
394        * the non-custom option instead. */
395       do
396         {
397           gchar *val, *name;
398           gtk_tree_model_get (model, &iter, VALUE_COLUMN, &val,
399                                             NAME_COLUMN, &name, -1);
400           if (g_str_equal (value, name))
401             {
402               *custom = FALSE;
403               g_free (name);
404               g_free (value);
405               return val;
406             }
407
408           g_free (val);
409           g_free (name);
410         }
411       while (gtk_tree_model_iter_next (model, &iter));
412     }
413
414   return value;
415 }
416
417
418 static void
419 deconstruct_widgets (GtkPrinterOptionWidget *widget)
420 {
421   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
422
423   if (priv->check)
424     {
425       gtk_widget_destroy (priv->check);
426       priv->check = NULL;
427     }
428   
429   if (priv->combo)
430     {
431       gtk_widget_destroy (priv->combo);
432       priv->combo = NULL;
433     }
434   
435   if (priv->entry)
436     {
437       gtk_widget_destroy (priv->entry);
438       priv->entry = NULL;
439     }
440
441   /* make sure entry and combo are destroyed first */
442   /* as we use the two of them to create the filechooser */
443   if (priv->filechooser)
444     {
445       gtk_widget_destroy (priv->filechooser);
446       priv->filechooser = NULL;
447     }
448
449   if (priv->image)
450     {
451       gtk_widget_destroy (priv->image);
452       priv->image = NULL;
453     }
454
455   if (priv->label)
456     {
457       gtk_widget_destroy (priv->label);
458       priv->label = NULL;
459     }
460   if (priv->info_label)
461     {
462       gtk_widget_destroy (priv->info_label);
463       priv->info_label = NULL;
464     }
465 }
466
467 static void
468 check_toggled_cb (GtkToggleButton        *toggle_button,
469                   GtkPrinterOptionWidget *widget)
470 {
471   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
472
473   g_signal_handler_block (priv->source, priv->source_changed_handler);
474   gtk_printer_option_set_boolean (priv->source,
475                                   gtk_toggle_button_get_active (toggle_button));
476   g_signal_handler_unblock (priv->source, priv->source_changed_handler);
477   emit_changed (widget);
478 }
479
480 static void
481 filesave_changed_cb (GtkWidget              *button,
482                      GtkPrinterOptionWidget *widget)
483 {
484   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
485   gchar *uri, *file;
486   gchar *directory;
487
488   file = g_filename_from_utf8 (gtk_entry_get_text (GTK_ENTRY (priv->entry)),
489                                -1, NULL, NULL, NULL);
490   if (file == NULL)
491     return;
492
493   /* combine the value of the chooser with the value of the entry */
494   g_signal_handler_block (priv->source, priv->source_changed_handler);  
495
496   directory = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (priv->combo));
497
498   if ((g_uri_parse_scheme (file) == NULL) && (directory != NULL))
499     {
500       if (g_path_is_absolute (file))
501         uri = g_filename_to_uri (file, NULL, NULL);
502       else
503         {
504           gchar *path;
505
506 #ifdef G_OS_UNIX
507           if (file[0] == '~' && file[1] == '/')
508             {
509               path = g_build_filename (g_get_home_dir (), file + 2, NULL);
510             }
511           else
512 #endif
513             {
514               path = g_build_filename (directory, file, NULL);
515             }
516
517           uri = g_filename_to_uri (path, NULL, NULL);
518
519           g_free (path);
520         }
521     }
522   else
523     {
524       if (g_uri_parse_scheme (file) != NULL)
525         uri = g_strdup (file);
526       else
527         uri = g_build_path ("/", gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (priv->combo)), file, NULL);
528     }
529  
530   if (uri)
531     gtk_printer_option_set (priv->source, uri);
532
533   g_free (uri);
534   g_free (file);
535   g_free (directory);
536
537   g_signal_handler_unblock (priv->source, priv->source_changed_handler);
538   emit_changed (widget);
539 }
540
541 static gchar *
542 filter_numeric (const gchar *val,
543                 gboolean     allow_neg,
544                 gboolean     allow_dec,
545                 gboolean    *changed_out)
546 {
547   gchar *filtered_val;
548   int i, j;
549   int len = strlen (val);
550   gboolean dec_set = FALSE;
551
552   filtered_val = g_malloc (len + 1);
553
554   for (i = 0, j = 0; i < len; i++)
555     {
556       if (isdigit (val[i]))
557         {
558           filtered_val[j] = val[i];
559           j++;
560         }
561       else if (allow_dec && !dec_set && 
562                (val[i] == '.' || val[i] == ','))
563         {
564           /* allow one period or comma
565            * we should be checking locals
566            * but this is good enough for now
567            */
568           filtered_val[j] = val[i];
569           dec_set = TRUE;
570           j++;
571         }
572       else if (allow_neg && i == 0 && val[0] == '-')
573         {
574           filtered_val[0] = val[0];
575           j++;
576         }
577     }
578
579   filtered_val[j] = '\0';
580   *changed_out = !(i == j);
581
582   return filtered_val;
583 }
584
585 static void
586 combo_changed_cb (GtkWidget              *combo,
587                   GtkPrinterOptionWidget *widget)
588 {
589   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
590   gchar *value;
591   gchar *filtered_val = NULL;
592   gboolean changed;
593   gboolean custom = TRUE;
594
595   g_signal_handler_block (priv->source, priv->source_changed_handler);
596   
597   value = combo_box_get (combo, &custom);
598
599   /* Handle constraints if the user entered a custom value. */
600   if (custom)
601     {
602       switch (priv->source->type)
603         {
604         case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
605           filtered_val = filter_numeric (value, FALSE, FALSE, &changed);
606           break;
607         case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
608           filtered_val = filter_numeric (value, TRUE, FALSE, &changed);
609           break;
610         case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
611           filtered_val = filter_numeric (value, TRUE, TRUE, &changed);
612           break;
613         default:
614           break;
615         }
616     }
617
618   if (filtered_val)
619     {
620       g_free (value);
621
622       if (changed)
623         {
624           GtkEntry *entry;
625           
626           entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo)));
627
628           gtk_entry_set_text (entry, filtered_val);
629         }
630       value = filtered_val;
631     }
632
633   if (value)
634     gtk_printer_option_set (priv->source, value);
635   g_free (value);
636   g_signal_handler_unblock (priv->source, priv->source_changed_handler);
637   emit_changed (widget);
638 }
639
640 static void
641 entry_changed_cb (GtkWidget              *entry,
642                   GtkPrinterOptionWidget *widget)
643 {
644   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
645   const gchar *value;
646   
647   g_signal_handler_block (priv->source, priv->source_changed_handler);
648   value = gtk_entry_get_text (GTK_ENTRY (entry));
649   if (value)
650     gtk_printer_option_set (priv->source, value);
651   g_signal_handler_unblock (priv->source, priv->source_changed_handler);
652   emit_changed (widget);
653 }
654
655
656 static void
657 radio_changed_cb (GtkWidget              *button,
658                   GtkPrinterOptionWidget *widget)
659 {
660   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
661   gchar *value;
662   
663   g_signal_handler_block (priv->source, priv->source_changed_handler);
664   value = g_object_get_data (G_OBJECT (button), "value");
665   if (value)
666     gtk_printer_option_set (priv->source, value);
667   g_signal_handler_unblock (priv->source, priv->source_changed_handler);
668   emit_changed (widget);
669 }
670
671 static void
672 select_maybe (GtkWidget   *widget, 
673               const gchar *value)
674 {
675   gchar *v = g_object_get_data (G_OBJECT (widget), "value");
676       
677   if (strcmp (value, v) == 0)
678     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
679 }
680
681 static void
682 alternative_set (GtkWidget   *box,
683                  const gchar *value)
684 {
685   gtk_container_foreach (GTK_CONTAINER (box), 
686                          (GtkCallback) select_maybe,
687                          (gpointer) value);
688 }
689
690 static GSList *
691 alternative_append (GtkWidget              *box,
692                     const gchar            *label,
693                     const gchar            *value,
694                     GtkPrinterOptionWidget *widget,
695                     GSList                 *group)
696 {
697   GtkWidget *button;
698
699   button = gtk_radio_button_new_with_label (group, label);
700   gtk_widget_show (button);
701   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
702
703   g_object_set_data (G_OBJECT (button), "value", (gpointer)value);
704   g_signal_connect (button, "toggled", 
705                     G_CALLBACK (radio_changed_cb), widget);
706
707   return gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
708 }
709
710 static void
711 construct_widgets (GtkPrinterOptionWidget *widget)
712 {
713   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
714   GtkPrinterOption *source;
715   char *text;
716   int i;
717   GSList *group;
718
719   source = priv->source;
720   
721   deconstruct_widgets (widget);
722   
723   gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
724
725   if (source == NULL)
726     {
727       priv->combo = combo_box_new ();
728       combo_box_append (priv->combo,_("Not available"), "None");
729       gtk_combo_box_set_active (GTK_COMBO_BOX (priv->combo), 0);
730       gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE);
731       gtk_widget_show (priv->combo);
732       gtk_box_pack_start (GTK_BOX (widget), priv->combo, TRUE, TRUE, 0);
733     }
734   else switch (source->type)
735     {
736     case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
737       priv->check = gtk_check_button_new_with_mnemonic (source->display_text);
738       g_signal_connect (priv->check, "toggled", G_CALLBACK (check_toggled_cb), widget);
739       gtk_widget_show (priv->check);
740       gtk_box_pack_start (GTK_BOX (widget), priv->check, TRUE, TRUE, 0);
741       break;
742     case GTK_PRINTER_OPTION_TYPE_PICKONE:
743     case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD:
744     case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
745     case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
746     case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
747     case GTK_PRINTER_OPTION_TYPE_PICKONE_STRING:
748       if (source->type == GTK_PRINTER_OPTION_TYPE_PICKONE)
749         {
750           priv->combo = combo_box_new ();
751         }
752       else
753         {
754           priv->combo = combo_box_entry_new ();
755
756           if (source->type == GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD ||
757               source->type == GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE)
758             {
759               GtkEntry *entry;
760
761               entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->combo)));
762
763               gtk_entry_set_visibility (entry, FALSE); 
764             }
765         }
766        
767
768       for (i = 0; i < source->num_choices; i++)
769           combo_box_append (priv->combo,
770                             source->choices_display[i],
771                             source->choices[i]);
772       gtk_widget_show (priv->combo);
773       gtk_box_pack_start (GTK_BOX (widget), priv->combo, TRUE, TRUE, 0);
774       g_signal_connect (priv->combo, "changed", G_CALLBACK (combo_changed_cb), widget);
775
776       text = g_strdup_printf ("%s:", source->display_text);
777       priv->label = gtk_label_new_with_mnemonic (text);
778       g_free (text);
779       gtk_widget_show (priv->label);
780       break;
781
782     case GTK_PRINTER_OPTION_TYPE_ALTERNATIVE:
783       group = NULL;
784       priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
785       gtk_widget_show (priv->box);
786       gtk_box_pack_start (GTK_BOX (widget), priv->box, TRUE, TRUE, 0);
787       for (i = 0; i < source->num_choices; i++)
788         group = alternative_append (priv->box,
789                                     source->choices_display[i],
790                                     source->choices[i],
791                                     widget,
792                                     group);
793
794       if (source->display_text)
795         {
796           text = g_strdup_printf ("%s:", source->display_text);
797           priv->label = gtk_label_new_with_mnemonic (text);
798           g_free (text);
799           gtk_widget_show (priv->label);
800         }
801       break;
802
803     case GTK_PRINTER_OPTION_TYPE_STRING:
804       priv->entry = gtk_entry_new ();
805       gtk_entry_set_activates_default (GTK_ENTRY (priv->entry),
806                                        gtk_printer_option_get_activates_default (source));
807       gtk_widget_show (priv->entry);
808       gtk_box_pack_start (GTK_BOX (widget), priv->entry, TRUE, TRUE, 0);
809       g_signal_connect (priv->entry, "changed", G_CALLBACK (entry_changed_cb), widget);
810
811       text = g_strdup_printf ("%s:", source->display_text);
812       priv->label = gtk_label_new_with_mnemonic (text);
813       g_free (text);
814       gtk_widget_show (priv->label);
815
816       break;
817
818     case GTK_PRINTER_OPTION_TYPE_FILESAVE:
819       {
820         GtkWidget *label;
821         
822         priv->filechooser = gtk_grid_new ();
823         gtk_grid_set_row_spacing (GTK_GRID (priv->filechooser), 6);
824         gtk_grid_set_column_spacing (GTK_GRID (priv->filechooser), 12);
825
826         /* TODO: make this a gtkfilechooserentry once we move to GTK */
827         priv->entry = gtk_entry_new ();
828         priv->combo = gtk_file_chooser_button_new (_("Select a folder"),
829                                                    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
830
831         g_object_set (priv->combo, "local-only", FALSE, NULL);
832         gtk_entry_set_activates_default (GTK_ENTRY (priv->entry),
833                                          gtk_printer_option_get_activates_default (source));
834
835         label = gtk_label_new_with_mnemonic (_("_Name:"));
836         gtk_widget_set_halign (label, GTK_ALIGN_START);
837         gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
838         gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->entry);
839
840         gtk_grid_attach (GTK_GRID (priv->filechooser), label, 0, 0, 1, 1);
841         gtk_grid_attach (GTK_GRID (priv->filechooser), priv->entry, 1, 0, 1, 1);
842
843         label = gtk_label_new_with_mnemonic (_("_Save in folder:"));
844         gtk_widget_set_halign (label, GTK_ALIGN_START);
845         gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
846         gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->combo);
847
848         gtk_grid_attach (GTK_GRID (priv->filechooser), label, 0, 1, 1, 1);
849         gtk_grid_attach (GTK_GRID (priv->filechooser), priv->combo, 1, 1, 1, 1);
850
851         gtk_widget_show_all (priv->filechooser);
852         gtk_box_pack_start (GTK_BOX (widget), priv->filechooser, TRUE, TRUE, 0);
853
854         g_signal_connect (priv->entry, "changed", G_CALLBACK (filesave_changed_cb), widget);
855
856         g_signal_connect (priv->combo, "selection-changed", G_CALLBACK (filesave_changed_cb), widget);
857       }
858       break;
859
860     case GTK_PRINTER_OPTION_TYPE_INFO:
861       priv->info_label = gtk_label_new (NULL);
862       gtk_label_set_selectable (GTK_LABEL (priv->info_label), TRUE);
863       gtk_widget_show (priv->info_label);
864       gtk_box_pack_start (GTK_BOX (widget), priv->info_label, FALSE, TRUE, 0);
865
866       text = g_strdup_printf ("%s:", source->display_text);
867       priv->label = gtk_label_new_with_mnemonic (text);
868       g_free (text);
869       gtk_widget_show (priv->label);
870
871       break;
872
873     default:
874       break;
875     }
876
877   priv->image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
878   gtk_box_pack_start (GTK_BOX (widget), priv->image, FALSE, FALSE, 0);
879 }
880
881 static void
882 update_widgets (GtkPrinterOptionWidget *widget)
883 {
884   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
885   GtkPrinterOption *source;
886
887   source = priv->source;
888   
889   if (source == NULL)
890     {
891       gtk_widget_hide (priv->image);
892       return;
893     }
894
895   switch (source->type)
896     {
897     case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
898       if (g_ascii_strcasecmp (source->value, "True") == 0)
899         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->check), TRUE);
900       else
901         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->check), FALSE);
902       break;
903     case GTK_PRINTER_OPTION_TYPE_PICKONE:
904       combo_box_set (priv->combo, source->value);
905       break;
906     case GTK_PRINTER_OPTION_TYPE_ALTERNATIVE:
907       alternative_set (priv->box, source->value);
908       break;
909     case GTK_PRINTER_OPTION_TYPE_STRING:
910       gtk_entry_set_text (GTK_ENTRY (priv->entry), source->value);
911       break;
912     case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD:
913     case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
914     case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
915     case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
916     case GTK_PRINTER_OPTION_TYPE_PICKONE_STRING:
917       {
918         GtkEntry *entry;
919
920         entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->combo)));
921         if (gtk_printer_option_has_choice (source, source->value))
922           combo_box_set (priv->combo, source->value);
923         else
924           gtk_entry_set_text (entry, source->value);
925
926         break;
927       }
928     case GTK_PRINTER_OPTION_TYPE_FILESAVE:
929       {
930         gchar *filename = g_filename_from_uri (source->value, NULL, NULL);
931         if (filename != NULL)
932           {
933             gchar *basename, *dirname, *text;
934
935             basename = g_path_get_basename (filename);
936             dirname = g_path_get_dirname (filename);
937
938             text = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
939             
940             /* need to update dirname and basename without triggering function to avoid loosing names */
941             g_signal_handlers_block_by_func (priv->entry, G_CALLBACK (filesave_changed_cb), widget);
942             g_signal_handlers_block_by_func (priv->combo, G_CALLBACK (filesave_changed_cb), widget);
943
944             if (text != NULL)
945               gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
946             if (g_path_is_absolute (dirname))
947               gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (priv->combo),
948                                                    dirname);
949
950             g_signal_handlers_unblock_by_func (priv->entry, G_CALLBACK (filesave_changed_cb), widget);
951             g_signal_handlers_unblock_by_func (priv->combo, G_CALLBACK (filesave_changed_cb), widget);
952             
953             g_free (text);
954             g_free (basename);
955             g_free (dirname);
956             g_free (filename);
957           }
958         else
959           gtk_entry_set_text (GTK_ENTRY (priv->entry), source->value);
960         break;
961       }
962     case GTK_PRINTER_OPTION_TYPE_INFO:
963       gtk_label_set_text (GTK_LABEL (priv->info_label), source->value);
964       break;
965     default:
966       break;
967     }
968
969   if (source->has_conflict)
970     gtk_widget_show (priv->image);
971   else
972     gtk_widget_hide (priv->image);
973 }
974
975 gboolean
976 gtk_printer_option_widget_has_external_label (GtkPrinterOptionWidget *widget)
977 {
978   return widget->priv->label != NULL;
979 }
980
981 GtkWidget *
982 gtk_printer_option_widget_get_external_label (GtkPrinterOptionWidget  *widget)
983 {
984   return widget->priv->label;
985 }
986
987 const gchar *
988 gtk_printer_option_widget_get_value (GtkPrinterOptionWidget *widget)
989 {
990   GtkPrinterOptionWidgetPrivate *priv = widget->priv;
991
992   if (priv->source)
993     return priv->source->value;
994   
995   return "";
996 }