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