]> Pileus Git - ~andy/gtk/blob - gtk/gtkprinteroptionwidget.c
688f5c90f06c2eeba541cfe29bb3033df04fdad1
[~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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24
25 #include "gtkintl.h"
26 #include "gtkalignment.h"
27 #include "gtkcheckbutton.h"
28 #include "gtkcelllayout.h"
29 #include "gtkcellrenderertext.h"
30 #include "gtkcombobox.h"
31 #include "gtkfilechooserbutton.h"
32 #include "gtkimage.h"
33 #include "gtklabel.h"
34 #include "gtkliststore.h"
35 #include "gtkstock.h"
36 #include "gtktable.h"
37 #include "gtktogglebutton.h"
38 #include "gtkprivate.h"
39
40 #include "gtkprinteroptionwidget.h"
41 #include "gtkalias.h"
42
43 #define GTK_PRINTER_OPTION_WIDGET_GET_PRIVATE(o)  \
44    (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_PRINTER_OPTION_WIDGET, GtkPrinterOptionWidgetPrivate))
45
46 static void gtk_printer_option_widget_finalize (GObject *object);
47
48 static void deconstruct_widgets (GtkPrinterOptionWidget *widget);
49 static void construct_widgets (GtkPrinterOptionWidget *widget);
50 static void update_widgets (GtkPrinterOptionWidget *widget);
51
52 struct GtkPrinterOptionWidgetPrivate
53 {
54   GtkPrinterOption *source;
55   gulong source_changed_handler;
56   
57   GtkWidget *check;
58   GtkWidget *combo;
59   GtkWidget *entry;
60   GtkWidget *image;
61   GtkWidget *label;
62   GtkWidget *filechooser;
63 };
64
65 enum {
66   CHANGED,
67   LAST_SIGNAL
68 };
69
70 enum {
71   PROP_0,
72   PROP_SOURCE,
73 };
74
75 static guint signals[LAST_SIGNAL] = { 0 };
76
77 G_DEFINE_TYPE (GtkPrinterOptionWidget, gtk_printer_option_widget, GTK_TYPE_HBOX);
78
79 static void gtk_printer_option_widget_set_property (GObject      *object,
80                                                     guint         prop_id,
81                                                     const GValue *value,
82                                                     GParamSpec   *pspec);
83 static void gtk_printer_option_widget_get_property (GObject      *object,
84                                                     guint         prop_id,
85                                                     GValue       *value,
86                                                     GParamSpec   *pspec);
87 static gboolean gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
88                                                               gboolean   group_cycling);
89
90 static void
91 gtk_printer_option_widget_class_init (GtkPrinterOptionWidgetClass *class)
92 {
93   GObjectClass *object_class;
94   GtkWidgetClass *widget_class;
95
96   object_class = (GObjectClass *) class;
97   widget_class = (GtkWidgetClass *) class;
98
99   object_class->finalize = gtk_printer_option_widget_finalize;
100   object_class->set_property = gtk_printer_option_widget_set_property;
101   object_class->get_property = gtk_printer_option_widget_get_property;
102
103   widget_class->mnemonic_activate = gtk_printer_option_widget_mnemonic_activate;
104
105   g_type_class_add_private (class, sizeof (GtkPrinterOptionWidgetPrivate));  
106
107   signals[CHANGED] =
108     g_signal_new ("changed",
109                   G_TYPE_FROM_CLASS (class),
110                   G_SIGNAL_RUN_LAST,
111                   G_STRUCT_OFFSET (GtkPrinterOptionWidgetClass, changed),
112                   NULL, NULL,
113                   g_cclosure_marshal_VOID__VOID,
114                   G_TYPE_NONE, 0);
115
116   g_object_class_install_property (object_class,
117                                    PROP_SOURCE,
118                                    g_param_spec_object ("source",
119                                                         P_("Source option"),
120                                                         P_("The PrinterOption backing this widget"),
121                                                         GTK_TYPE_PRINTER_OPTION,
122                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
123
124 }
125
126 static void
127 gtk_printer_option_widget_init (GtkPrinterOptionWidget *widget)
128 {
129   widget->priv = GTK_PRINTER_OPTION_WIDGET_GET_PRIVATE (widget); 
130
131   gtk_box_set_spacing (GTK_BOX (widget), 12);
132 }
133
134 static void
135 gtk_printer_option_widget_finalize (GObject *object)
136 {
137   GtkPrinterOptionWidget *widget;
138   
139   widget = GTK_PRINTER_OPTION_WIDGET (object);
140
141   if (widget->priv->source)
142     {
143       g_object_unref (widget->priv->source);
144       widget->priv->source = NULL;
145     }
146   
147   if (G_OBJECT_CLASS (gtk_printer_option_widget_parent_class)->finalize)
148     G_OBJECT_CLASS (gtk_printer_option_widget_parent_class)->finalize (object);
149 }
150
151 static void
152 gtk_printer_option_widget_set_property (GObject         *object,
153                                         guint            prop_id,
154                                         const GValue    *value,
155                                         GParamSpec      *pspec)
156 {
157   GtkPrinterOptionWidget *widget;
158   
159   widget = GTK_PRINTER_OPTION_WIDGET (object);
160
161   switch (prop_id)
162     {
163     case PROP_SOURCE:
164       gtk_printer_option_widget_set_source (widget, g_value_get_object (value));
165       break;
166     default:
167       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
168       break;
169     }
170 }
171
172 static void
173 gtk_printer_option_widget_get_property (GObject    *object,
174                                         guint       prop_id,
175                                         GValue     *value,
176                                         GParamSpec *pspec)
177 {
178   GtkPrinterOptionWidget *widget;
179   
180   widget = GTK_PRINTER_OPTION_WIDGET (object);
181
182   switch (prop_id)
183     {
184     case PROP_SOURCE:
185       g_value_set_object (value, widget->priv->source);
186       break;
187     default:
188       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189       break;
190     }
191 }
192
193 static gboolean
194 gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
195                                              gboolean   group_cycling)
196 {
197   GtkPrinterOptionWidget *powidget = GTK_PRINTER_OPTION_WIDGET (widget);
198   GtkPrinterOptionWidgetPrivate *priv = powidget->priv;
199
200   if (priv->check)
201     return gtk_widget_mnemonic_activate (priv->check, group_cycling);
202   if (priv->combo)
203     return gtk_widget_mnemonic_activate (priv->combo, group_cycling);
204   if (priv->entry)
205     return gtk_widget_mnemonic_activate (priv->entry, group_cycling);
206
207   return FALSE;
208 }
209
210 static void
211 emit_changed (GtkPrinterOptionWidget *widget)
212 {
213   g_signal_emit (widget, signals[CHANGED], 0);
214 }
215
216 GtkWidget *
217 gtk_printer_option_widget_new (GtkPrinterOption *source)
218 {
219   return g_object_new (GTK_TYPE_PRINTER_OPTION_WIDGET, "source", source, NULL);
220 }
221
222 static void
223 source_changed_cb (GtkPrinterOption *source,
224                    GtkPrinterOptionWidget  *widget)
225 {
226   update_widgets (widget);
227   emit_changed (widget);
228 }
229
230 void
231 gtk_printer_option_widget_set_source (GtkPrinterOptionWidget  *widget,
232                                       GtkPrinterOption *source)
233 {
234   if (source)
235     g_object_ref (source);
236   
237   if (widget->priv->source)
238     {
239       g_signal_handler_disconnect (widget->priv->source,
240                                    widget->priv->source_changed_handler);
241       g_object_unref (widget->priv->source);
242     }
243
244   widget->priv->source = source;
245
246   if (source)
247     widget->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 static GtkWidget *
257 combo_box_new (void)
258 {
259   GtkWidget *combo_box;
260   GtkCellRenderer *cell;
261   GtkListStore *store;
262
263   store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
264   combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
265   g_object_unref (store);
266
267   cell = gtk_cell_renderer_text_new ();
268   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
269   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
270                                   "text", 0,
271                                   NULL);
272
273   return combo_box;
274 }
275   
276 static void
277 combo_box_append (GtkWidget *combo,
278                   const char *display_text,
279                   const char *value)
280 {
281   GtkTreeModel *model;
282   GtkListStore *store;
283   GtkTreeIter iter;
284   
285   model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
286   store = GTK_LIST_STORE (model);
287
288   gtk_list_store_append (store, &iter);
289   gtk_list_store_set (store, &iter,
290                       0, display_text,
291                       1, value,
292                       -1);
293 }
294
295 struct ComboSet {
296   GtkComboBox *combo;
297   const char *value;
298 };
299
300 static gboolean
301 set_cb (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
302 {
303   struct ComboSet *set_data = data;
304   gboolean found;
305   char *value;
306   
307   gtk_tree_model_get (model, iter, 1, &value, -1);
308   found = (strcmp (value, set_data->value) == 0);
309   g_free (value);
310   
311   if (found)
312     gtk_combo_box_set_active_iter (set_data->combo, iter);
313
314   return found;
315 }
316
317 static void
318 combo_box_set (GtkWidget *combo,
319                const char *value)
320 {
321   GtkTreeModel *model;
322   GtkListStore *store;
323   struct ComboSet set_data;
324   
325   model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
326   store = GTK_LIST_STORE (model);
327
328   set_data.combo = GTK_COMBO_BOX (combo);
329   set_data.value = value;
330   gtk_tree_model_foreach (model, set_cb, &set_data);
331 }
332
333 static char *
334 combo_box_get (GtkWidget *combo)
335 {
336   GtkTreeModel *model;
337   char *val;
338   GtkTreeIter iter;
339   
340   model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
341
342   val = NULL;
343   if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
344     gtk_tree_model_get (model, &iter,
345                         1, &val,
346                         -1);
347   return val;
348 }
349
350
351 static void
352 deconstruct_widgets (GtkPrinterOptionWidget *widget)
353 {
354   if (widget->priv->check)
355     {
356       gtk_widget_destroy (widget->priv->check);
357       widget->priv->check = NULL;
358     }
359   
360   if (widget->priv->combo)
361     {
362       gtk_widget_destroy (widget->priv->combo);
363       widget->priv->combo = NULL;
364     }
365   
366   if (widget->priv->entry)
367     {
368       gtk_widget_destroy (widget->priv->entry);
369       widget->priv->entry = NULL;
370     }
371
372   /* make sure entry and combo are destroyed first */
373   /* as we use the two of them to create the filechooser */
374   if (widget->priv->filechooser)
375     {
376       gtk_widget_destroy (widget->priv->filechooser);
377       widget->priv->filechooser = NULL;
378     }
379
380   if (widget->priv->image)
381     {
382       gtk_widget_destroy (widget->priv->image);
383       widget->priv->image = NULL;
384     }
385
386   if (widget->priv->label)
387     {
388       gtk_widget_destroy (widget->priv->label);
389       widget->priv->label = NULL;
390     }
391 }
392
393 static void
394 check_toggled_cb (GtkToggleButton *toggle_button,
395                   GtkPrinterOptionWidget *widget)
396 {
397   g_signal_handler_block (widget->priv->source, widget->priv->source_changed_handler);
398   gtk_printer_option_set_boolean (widget->priv->source,
399                                   gtk_toggle_button_get_active (toggle_button));
400   g_signal_handler_unblock (widget->priv->source, widget->priv->source_changed_handler);
401   emit_changed (widget);
402 }
403
404 static void
405 filesave_changed_cb (GtkWidget *w,
406                      GtkPrinterOptionWidget *widget)
407 {
408   char *value;
409   char *directory;
410   const char *file;
411
412   /* combine the value of the chooser with the value of the entry */
413   g_signal_handler_block (widget->priv->source, widget->priv->source_changed_handler);  
414   
415   /* TODO: how do we support nonlocal file systems? */
416   directory = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (widget->priv->combo));
417   file =  gtk_entry_get_text (GTK_ENTRY (widget->priv->entry));
418
419   value = g_build_filename (directory, file, NULL);
420
421   if (value)
422     gtk_printer_option_set (widget->priv->source, value);
423
424   g_free (directory);
425   g_free (value);
426
427   g_signal_handler_unblock (widget->priv->source, widget->priv->source_changed_handler);
428   emit_changed (widget);
429 }
430
431 static void
432 combo_changed_cb (GtkWidget *combo,
433                   GtkPrinterOptionWidget *widget)
434 {
435   char *value;
436   
437   g_signal_handler_block (widget->priv->source, widget->priv->source_changed_handler);
438   value = combo_box_get (combo);
439   if (value)
440     gtk_printer_option_set (widget->priv->source, value);
441   g_free (value);
442   g_signal_handler_unblock (widget->priv->source, widget->priv->source_changed_handler);
443   emit_changed (widget);
444 }
445
446 static void
447 entry_changed_cb (GtkWidget *entry,
448                   GtkPrinterOptionWidget *widget)
449 {
450   const char *value;
451   
452   g_signal_handler_block (widget->priv->source, widget->priv->source_changed_handler);
453   value = gtk_entry_get_text (GTK_ENTRY (entry));
454   if (value)
455     gtk_printer_option_set (widget->priv->source, value);
456   g_signal_handler_unblock (widget->priv->source, widget->priv->source_changed_handler);
457   emit_changed (widget);
458 }
459
460
461 static void
462 construct_widgets (GtkPrinterOptionWidget *widget)
463 {
464   GtkPrinterOption *source;
465   char *text;
466   int i;
467
468   source = widget->priv->source;
469   
470   deconstruct_widgets (widget);
471   
472   if (source == NULL)
473     {
474       widget->priv->combo = combo_box_new ();
475       combo_box_append (widget->priv->combo,_("Not available"), "None");
476       gtk_combo_box_set_active (GTK_COMBO_BOX (widget->priv->combo), 0);
477       gtk_widget_set_sensitive (widget->priv->combo, FALSE);
478       gtk_widget_show (widget->priv->combo);
479       gtk_box_pack_start (GTK_BOX (widget), widget->priv->combo, TRUE, TRUE, 0);
480     }
481   else switch (source->type)
482     {
483     case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
484       widget->priv->check = gtk_check_button_new_with_mnemonic (source->display_text);
485       g_signal_connect (widget->priv->check, "toggled", G_CALLBACK (check_toggled_cb), widget);
486       gtk_widget_show (widget->priv->check);
487       gtk_box_pack_start (GTK_BOX (widget), widget->priv->check, TRUE, TRUE, 0);
488       break;
489     case GTK_PRINTER_OPTION_TYPE_PICKONE:
490       widget->priv->combo = combo_box_new ();
491       for (i = 0; i < source->num_choices; i++)
492           combo_box_append (widget->priv->combo,
493                             source->choices_display[i],
494                             source->choices[i]);
495       gtk_widget_show (widget->priv->combo);
496       gtk_box_pack_start (GTK_BOX (widget), widget->priv->combo, TRUE, TRUE, 0);
497       g_signal_connect (widget->priv->combo, "changed", G_CALLBACK (combo_changed_cb), widget);
498
499       text = g_strdup_printf ("%s:", source->display_text);
500       widget->priv->label = gtk_label_new_with_mnemonic (text);
501       g_free (text);
502       gtk_widget_show (widget->priv->label);
503       break;
504     case GTK_PRINTER_OPTION_TYPE_STRING:
505       widget->priv->entry = gtk_entry_new ();
506       gtk_widget_show (widget->priv->entry);
507       gtk_box_pack_start (GTK_BOX (widget), widget->priv->entry, TRUE, TRUE, 0);
508       g_signal_connect (widget->priv->entry, "changed", G_CALLBACK (entry_changed_cb), widget);
509
510       text = g_strdup_printf ("%s:", source->display_text);
511       widget->priv->label = gtk_label_new_with_mnemonic (text);
512       g_free (text);
513       gtk_widget_show (widget->priv->label);
514
515       break;
516
517     case GTK_PRINTER_OPTION_TYPE_FILESAVE:
518       {
519         GtkWidget *label;
520         
521         widget->priv->filechooser = gtk_table_new (2, 2, FALSE);
522         gtk_table_set_row_spacings (GTK_TABLE (widget->priv->filechooser), 6);
523         gtk_table_set_col_spacings (GTK_TABLE (widget->priv->filechooser), 12);
524
525         /* TODO: make this a gtkfilechooserentry once we move to GTK */
526         widget->priv->entry = gtk_entry_new ();
527         widget->priv->combo = gtk_file_chooser_button_new (_("Print to PDF"),
528                                                            GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
529
530         label = gtk_label_new_with_mnemonic (_("_Name:"));
531         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
532         gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget->priv->entry);
533
534         gtk_table_attach (GTK_TABLE (widget->priv->filechooser), label,
535                           0, 1, 0, 1, GTK_FILL, 0,
536                           0, 0);
537
538         gtk_table_attach (GTK_TABLE (widget->priv->filechooser), widget->priv->entry,
539                           1, 2, 0, 1, GTK_FILL, 0,
540                           0, 0);
541
542         label = gtk_label_new_with_mnemonic (_("_Save in folder:"));
543         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
544         gtk_label_set_mnemonic_widget (GTK_LABEL (label), widget->priv->combo);
545
546         gtk_table_attach (GTK_TABLE (widget->priv->filechooser), label,
547                           0, 1, 1, 2, GTK_FILL, 0,
548                           0, 0);
549
550         gtk_table_attach (GTK_TABLE (widget->priv->filechooser), widget->priv->combo,
551                           1, 2, 1, 2, GTK_FILL, 0,
552                           0, 0);
553
554         gtk_widget_show_all (widget->priv->filechooser);
555         gtk_box_pack_start (GTK_BOX (widget), widget->priv->filechooser, TRUE, TRUE, 0);
556
557         g_signal_connect (widget->priv->entry, "changed", G_CALLBACK (filesave_changed_cb), widget);
558
559         g_signal_connect (widget->priv->combo, "current-folder-changed", G_CALLBACK (filesave_changed_cb), widget);
560       }
561       break;
562     default:
563       break;
564     }
565
566   widget->priv->image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
567   gtk_box_pack_start (GTK_BOX (widget), widget->priv->image, FALSE, FALSE, 0);
568 }
569
570 static void
571 update_widgets (GtkPrinterOptionWidget *widget)
572 {
573   GtkPrinterOption *source;
574
575   source = widget->priv->source;
576   
577   if (source == NULL)
578     {
579       gtk_widget_hide (widget->priv->image);
580       return;
581     }
582
583   switch (source->type)
584     {
585     case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
586       if (strcmp (source->value, "True") == 0)
587         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget->priv->check), TRUE);
588       else
589         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget->priv->check), FALSE);
590       break;
591     case GTK_PRINTER_OPTION_TYPE_PICKONE:
592       combo_box_set (widget->priv->combo, source->value);
593       break;
594     case GTK_PRINTER_OPTION_TYPE_STRING:
595       gtk_entry_set_text (GTK_ENTRY (widget->priv->entry), source->value);
596       break;
597     case GTK_PRINTER_OPTION_TYPE_FILESAVE:
598       {
599         char *basename = g_path_get_basename (source->value);
600         char *dirname = g_path_get_dirname (source->value);
601         gtk_entry_set_text (GTK_ENTRY (widget->priv->entry), basename);
602         if (g_path_is_absolute (dirname))
603           gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget->priv->combo),
604                                                dirname);
605         g_free (basename);
606         g_free (dirname);
607         break;
608       }
609     default:
610       break;
611     }
612
613   if (source->has_conflict)
614     gtk_widget_show (widget->priv->image);
615   else
616     gtk_widget_hide (widget->priv->image);
617 }
618
619 gboolean
620 gtk_printer_option_widget_has_external_label (GtkPrinterOptionWidget  *widget)
621 {
622   return widget->priv->label != NULL;
623 }
624
625 GtkWidget *
626 gtk_printer_option_widget_get_external_label (GtkPrinterOptionWidget  *widget)
627 {
628   return widget->priv->label;
629 }
630
631 const char *
632 gtk_printer_option_widget_get_value (GtkPrinterOptionWidget  *widget)
633 {
634   if (widget->priv->source)
635     return widget->priv->source->value;
636   
637   return "";
638 }
639
640 #define __GTK_PRINTER_OPTION_WIDGET_C__
641 #include "gtkaliasdef.c"