gtkprinteroptionwidget.c 28.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* GtkPrinterOptionWidget
 * Copyright (C) 2006 Alexander Larsson  <alexl@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 17 18 19 20 21
 */

#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
22
#include <ctype.h>
23 24 25 26 27 28

#include "gtkintl.h"
#include "gtkcheckbutton.h"
#include "gtkcelllayout.h"
#include "gtkcellrenderertext.h"
#include "gtkcombobox.h"
29
#include "gtkfilechooserdialog.h"
30 31 32
#include "gtkimage.h"
#include "gtklabel.h"
#include "gtkliststore.h"
33
#include "gtkradiobutton.h"
34
#include "gtkgrid.h"
35
#include "gtktogglebutton.h"
36
#include "gtkorientable.h"
37 38 39 40
#include "gtkprivate.h"

#include "gtkprinteroptionwidget.h"

41 42 43
/* This defines the max file length that the file chooser
 * button should display. The total length will be
 * FILENAME_LENGTH_MAX+3 because the truncated name is prefixed
44
 * with “...”.
45 46 47
 */
#define FILENAME_LENGTH_MAX 27

48 49 50
static void gtk_printer_option_widget_finalize (GObject *object);

static void deconstruct_widgets (GtkPrinterOptionWidget *widget);
51 52 53 54
static void construct_widgets   (GtkPrinterOptionWidget *widget);
static void update_widgets      (GtkPrinterOptionWidget *widget);

static gchar *trim_long_filename (const gchar *filename);
55 56 57 58 59

struct GtkPrinterOptionWidgetPrivate
{
  GtkPrinterOption *source;
  gulong source_changed_handler;
60

61 62 63 64 65
  GtkWidget *check;
  GtkWidget *combo;
  GtkWidget *entry;
  GtkWidget *image;
  GtkWidget *label;
66
  GtkWidget *info_label;
67
  GtkWidget *box;
68 69 70 71
  GtkWidget *button;

  /* the last location for save to file, that the user selected */
  gchar *last_location;
72 73 74 75 76 77 78 79 80
};

enum {
  CHANGED,
  LAST_SIGNAL
};

enum {
  PROP_0,
81
  PROP_SOURCE
82 83 84 85
};

static guint signals[LAST_SIGNAL] = { 0 };

86
G_DEFINE_TYPE_WITH_PRIVATE (GtkPrinterOptionWidget, gtk_printer_option_widget, GTK_TYPE_BOX)
87 88 89 90 91 92 93 94 95

static void gtk_printer_option_widget_set_property (GObject      *object,
						    guint         prop_id,
						    const GValue *value,
						    GParamSpec   *pspec);
static void gtk_printer_option_widget_get_property (GObject      *object,
						    guint         prop_id,
						    GValue       *value,
						    GParamSpec   *pspec);
96
static gboolean gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
97
							     gboolean   group_cycling);
98 99 100 101 102 103 104 105 106 107 108 109 110 111

static void
gtk_printer_option_widget_class_init (GtkPrinterOptionWidgetClass *class)
{
  GObjectClass *object_class;
  GtkWidgetClass *widget_class;

  object_class = (GObjectClass *) class;
  widget_class = (GtkWidgetClass *) class;

  object_class->finalize = gtk_printer_option_widget_finalize;
  object_class->set_property = gtk_printer_option_widget_set_property;
  object_class->get_property = gtk_printer_option_widget_get_property;

112 113
  widget_class->mnemonic_activate = gtk_printer_option_widget_mnemonic_activate;

114
  signals[CHANGED] =
115
    g_signal_new (I_("changed"),
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
		  G_TYPE_FROM_CLASS (class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkPrinterOptionWidgetClass, changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  g_object_class_install_property (object_class,
                                   PROP_SOURCE,
                                   g_param_spec_object ("source",
							P_("Source option"),
							P_("The PrinterOption backing this widget"),
							GTK_TYPE_PRINTER_OPTION,
							GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));

}

static void
gtk_printer_option_widget_init (GtkPrinterOptionWidget *widget)
{
136
  widget->priv = gtk_printer_option_widget_get_instance_private (widget);
137 138

  gtk_box_set_spacing (GTK_BOX (widget), 12);
139 140 141 142 143
}

static void
gtk_printer_option_widget_finalize (GObject *object)
{
144 145
  GtkPrinterOptionWidget *widget = GTK_PRINTER_OPTION_WIDGET (object);
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
146
  
147
  if (priv->source)
148
    {
149 150
      g_signal_handler_disconnect (priv->source,
				   priv->source_changed_handler);
151 152
      g_object_unref (priv->source);
      priv->source = NULL;
153 154
    }
  
155
  G_OBJECT_CLASS (gtk_printer_option_widget_parent_class)->finalize (object);
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
}

static void
gtk_printer_option_widget_set_property (GObject         *object,
					guint            prop_id,
					const GValue    *value,
					GParamSpec      *pspec)
{
  GtkPrinterOptionWidget *widget;
  
  widget = GTK_PRINTER_OPTION_WIDGET (object);

  switch (prop_id)
    {
    case PROP_SOURCE:
      gtk_printer_option_widget_set_source (widget, g_value_get_object (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_printer_option_widget_get_property (GObject    *object,
					guint       prop_id,
					GValue     *value,
					GParamSpec *pspec)
{
185 186
  GtkPrinterOptionWidget *widget = GTK_PRINTER_OPTION_WIDGET (object);
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
187 188 189 190

  switch (prop_id)
    {
    case PROP_SOURCE:
191
      g_value_set_object (value, priv->source);
192 193 194 195 196 197 198
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

199 200 201 202 203 204 205 206 207 208 209 210 211
static gboolean
gtk_printer_option_widget_mnemonic_activate (GtkWidget *widget,
					     gboolean   group_cycling)
{
  GtkPrinterOptionWidget *powidget = GTK_PRINTER_OPTION_WIDGET (widget);
  GtkPrinterOptionWidgetPrivate *priv = powidget->priv;

  if (priv->check)
    return gtk_widget_mnemonic_activate (priv->check, group_cycling);
  if (priv->combo)
    return gtk_widget_mnemonic_activate (priv->combo, group_cycling);
  if (priv->entry)
    return gtk_widget_mnemonic_activate (priv->entry, group_cycling);
212 213
  if (priv->button)
    return gtk_widget_mnemonic_activate (priv->button, group_cycling);
214 215 216 217

  return FALSE;
}

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
static void
emit_changed (GtkPrinterOptionWidget *widget)
{
  g_signal_emit (widget, signals[CHANGED], 0);
}

GtkWidget *
gtk_printer_option_widget_new (GtkPrinterOption *source)
{
  return g_object_new (GTK_TYPE_PRINTER_OPTION_WIDGET, "source", source, NULL);
}

static void
source_changed_cb (GtkPrinterOption *source,
		   GtkPrinterOptionWidget  *widget)
{
  update_widgets (widget);
  emit_changed (widget);
}

void
Matthias Clasen's avatar
Matthias Clasen committed
239 240
gtk_printer_option_widget_set_source (GtkPrinterOptionWidget *widget,
				      GtkPrinterOption       *source)
241
{
242 243
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;

244 245 246
  if (source)
    g_object_ref (source);
  
247
  if (priv->source)
248
    {
249 250 251
      g_signal_handler_disconnect (priv->source,
				   priv->source_changed_handler);
      g_object_unref (priv->source);
252 253
    }

254
  priv->source = source;
255 256

  if (source)
257
    priv->source_changed_handler =
258 259 260 261 262 263 264 265
      g_signal_connect (source, "changed", G_CALLBACK (source_changed_cb), widget);

  construct_widgets (widget);
  update_widgets (widget);

  g_object_notify (G_OBJECT (widget), "source");
}

Matthias Clasen's avatar
Matthias Clasen committed
266 267 268 269 270 271
enum {
  NAME_COLUMN,
  VALUE_COLUMN,
  N_COLUMNS
};

272 273
static void
combo_box_set_model (GtkWidget *combo_box)
274 275 276
{
  GtkListStore *store;

Matthias Clasen's avatar
Matthias Clasen committed
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 283 284 285
}

static void
combo_box_set_view (GtkWidget *combo_box)
{
  GtkCellRenderer *cell;
286 287 288 289

  cell = gtk_cell_renderer_text_new ();
  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
Matthias Clasen's avatar
Matthias Clasen committed
290
                                  "text", NAME_COLUMN,
291 292 293 294 295 296 297
                                   NULL);
}

static GtkWidget *
combo_box_entry_new (void)
{
  GtkWidget *combo_box;
298
  combo_box = g_object_new (GTK_TYPE_COMBO_BOX, "has-entry", TRUE, NULL);
299 300 301

  combo_box_set_model (combo_box);

302
  gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (combo_box), NAME_COLUMN);
303 304 305 306 307 308 309 310 311 312 313 314

  return combo_box;
}

static GtkWidget *
combo_box_new (void)
{
  GtkWidget *combo_box;
  combo_box = gtk_combo_box_new ();

  combo_box_set_model (combo_box);
  combo_box_set_view (combo_box);
315 316 317 318 319

  return combo_box;
}
  
static void
Matthias Clasen's avatar
Matthias Clasen committed
320 321 322
combo_box_append (GtkWidget   *combo,
		  const gchar *display_text,
		  const gchar *value)
323 324 325 326 327 328 329 330 331 332
{
  GtkTreeModel *model;
  GtkListStore *store;
  GtkTreeIter iter;
  
  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
  store = GTK_LIST_STORE (model);

  gtk_list_store_append (store, &iter);
  gtk_list_store_set (store, &iter,
Matthias Clasen's avatar
Matthias Clasen committed
333 334
		      NAME_COLUMN, display_text,
		      VALUE_COLUMN, value,
335 336 337 338 339
		      -1);
}

struct ComboSet {
  GtkComboBox *combo;
Matthias Clasen's avatar
Matthias Clasen committed
340
  const gchar *value;
341 342 343
};

static gboolean
Matthias Clasen's avatar
Matthias Clasen committed
344 345 346 347
set_cb (GtkTreeModel *model, 
	GtkTreePath  *path, 
	GtkTreeIter  *iter, 
	gpointer      data)
348 349 350 351 352
{
  struct ComboSet *set_data = data;
  gboolean found;
  char *value;
  
Matthias Clasen's avatar
Matthias Clasen committed
353
  gtk_tree_model_get (model, iter, VALUE_COLUMN, &value, -1);
354 355 356 357 358 359 360 361 362 363
  found = (strcmp (value, set_data->value) == 0);
  g_free (value);
  
  if (found)
    gtk_combo_box_set_active_iter (set_data->combo, iter);

  return found;
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
364 365
combo_box_set (GtkWidget   *combo,
	       const gchar *value)
366 367 368 369 370 371 372 373 374 375 376
{
  GtkTreeModel *model;
  struct ComboSet set_data;
  
  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));

  set_data.combo = GTK_COMBO_BOX (combo);
  set_data.value = value;
  gtk_tree_model_foreach (model, set_cb, &set_data);
}

377 378
static gchar *
combo_box_get (GtkWidget *combo, gboolean *custom)
379 380
{
  GtkTreeModel *model;
Matthias Clasen's avatar
Matthias Clasen committed
381
  gchar *value;
382 383
  GtkTreeIter iter;

384
  model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
385

386 387
  value = NULL;
  if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
    {
      gtk_tree_model_get (model, &iter, VALUE_COLUMN, &value, -1);
      *custom = FALSE;
    }
  else
    {
      if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (combo)))
        {
          value = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo)))));
          *custom = TRUE;
        }

      if (!value || !gtk_tree_model_get_iter_first (model, &iter))
        return value;

      /* If the user entered an item from the dropdown list manually, return
       * the non-custom option instead. */
      do
        {
          gchar *val, *name;
          gtk_tree_model_get (model, &iter, VALUE_COLUMN, &val,
                                            NAME_COLUMN, &name, -1);
          if (g_str_equal (value, name))
            {
              *custom = FALSE;
              g_free (name);
              g_free (value);
              return val;
            }

          g_free (val);
          g_free (name);
        }
      while (gtk_tree_model_iter_next (model, &iter));
    }
Matthias Clasen's avatar
Matthias Clasen committed
423 424

  return value;
425 426 427 428 429 430
}


static void
deconstruct_widgets (GtkPrinterOptionWidget *widget)
{
431 432 433
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;

  if (priv->check)
434
    {
435 436
      gtk_widget_destroy (priv->check);
      priv->check = NULL;
437 438
    }
  
439
  if (priv->combo)
440
    {
441 442
      gtk_widget_destroy (priv->combo);
      priv->combo = NULL;
443 444
    }
  
445
  if (priv->entry)
446
    {
447 448
      gtk_widget_destroy (priv->entry);
      priv->entry = NULL;
449 450
    }

451
  if (priv->image)
452
    {
453 454
      gtk_widget_destroy (priv->image);
      priv->image = NULL;
455 456
    }

457
  if (priv->label)
458
    {
459 460
      gtk_widget_destroy (priv->label);
      priv->label = NULL;
461
    }
462 463 464 465 466
  if (priv->info_label)
    {
      gtk_widget_destroy (priv->info_label);
      priv->info_label = NULL;
    }
467 468 469
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
470
check_toggled_cb (GtkToggleButton        *toggle_button,
471 472
		  GtkPrinterOptionWidget *widget)
{
473 474 475 476
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;

  g_signal_handler_block (priv->source, priv->source_changed_handler);
  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 480 481 482
  emit_changed (widget);
}

static void
483 484 485
dialog_response_callback (GtkDialog              *dialog,
                          gint                    response_id,
                          GtkPrinterOptionWidget *widget)
486
{
487
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
488 489
  gchar *uri = NULL;
  gchar *new_location = NULL;
490

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
  if (response_id == GTK_RESPONSE_ACCEPT)
    {
      gchar *filename;
      gchar *filename_utf8;
      gchar *filename_short;

      new_location = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));

      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
      filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
      filename_short = trim_long_filename (filename_utf8);
      gtk_button_set_label (GTK_BUTTON (priv->button), filename_short);
      g_free (filename_short);
      g_free (filename_utf8);
      g_free (filename);
    }
507

508
  gtk_widget_destroy (GTK_WIDGET (dialog));
509

510 511 512 513
  if (new_location)
    uri = new_location;
  else
    uri = priv->last_location;
514

515
  if (uri)
516
    {
517 518 519
      gtk_printer_option_set (priv->source, uri);
      emit_changed (widget);
    }
Matthias Clasen's avatar
Matthias Clasen committed
520

521 522 523
  g_free (new_location);
  g_free (priv->last_location);
  priv->last_location = NULL;
Matthias Clasen's avatar
Matthias Clasen committed
524

525 526 527
  /* unblock the handler which was blocked in the filesave_choose_cb function */
  g_signal_handler_unblock (priv->source, priv->source_changed_handler);
}
Matthias Clasen's avatar
Matthias Clasen committed
528

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
static void
filesave_choose_cb (GtkWidget              *button,
                    GtkPrinterOptionWidget *widget)
{
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
  gchar *last_location = NULL;
  GtkWidget *dialog;
  GtkWindow *toplevel;

  /* this will be unblocked in the dialog_response_callback function */
  g_signal_handler_block (priv->source, priv->source_changed_handler);

  toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
  dialog = gtk_file_chooser_dialog_new (_("Select a filename"),
                                        toplevel,
                                        GTK_FILE_CHOOSER_ACTION_SAVE,
545
                                        _("_Cancel"), GTK_RESPONSE_CANCEL,
546 547 548 549 550 551 552 553
                                        _("_Select"), GTK_RESPONSE_ACCEPT,
                                        NULL);

  /* The confirmation dialog will appear, when the user clicks print */
  gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), FALSE);

  /* select the current filename in the dialog */
  if (priv->source != NULL)
554
    {
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
      priv->last_location = last_location = g_strdup (priv->source->value);
      if (last_location)
        {
          GFile *file;
          gchar *basename;
          gchar *basename_utf8;

          gtk_file_chooser_select_uri (GTK_FILE_CHOOSER (dialog), last_location);
          file = g_file_new_for_uri (last_location);
          basename = g_file_get_basename (file);
          basename_utf8 = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
          gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), basename_utf8);
          g_free (basename_utf8);
          g_free (basename);
          g_object_unref (file);
        }
571
    }
572

573 574 575 576
  g_signal_connect (dialog, "response",
                    G_CALLBACK (dialog_response_callback), widget);
  gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
  gtk_window_present (GTK_WINDOW (dialog));
577 578
}

Matthias Clasen's avatar
Matthias Clasen committed
579 580 581 582 583
static gchar *
filter_numeric (const gchar *val,
                gboolean     allow_neg,
		gboolean     allow_dec,
                gboolean    *changed_out)
584 585 586 587 588 589 590 591 592 593
{
  gchar *filtered_val;
  int i, j;
  int len = strlen (val);
  gboolean dec_set = FALSE;

  filtered_val = g_malloc (len + 1);

  for (i = 0, j = 0; i < len; i++)
    {
Matthias Clasen's avatar
Matthias Clasen committed
594
      if (isdigit (val[i]))
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
        {
          filtered_val[j] = val[i];
	  j++;
	}
      else if (allow_dec && !dec_set && 
               (val[i] == '.' || val[i] == ','))
        {
	  /* allow one period or comma
	   * we should be checking locals
	   * but this is good enough for now
	   */
          filtered_val[j] = val[i];
	  dec_set = TRUE;
	  j++;
	}
      else if (allow_neg && i == 0 && val[0] == '-')
        {
          filtered_val[0] = val[0];
	  j++;
	}
    }

  filtered_val[j] = '\0';
  *changed_out = !(i == j);

  return filtered_val;
}
Matthias Clasen's avatar
Matthias Clasen committed
622

623
static void
Matthias Clasen's avatar
Matthias Clasen committed
624
combo_changed_cb (GtkWidget              *combo,
625 626
		  GtkPrinterOptionWidget *widget)
{
627
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
628 629 630
  gchar *value;
  gchar *filtered_val = NULL;
  gboolean changed;
631
  gboolean custom = TRUE;
632

633
  g_signal_handler_block (priv->source, priv->source_changed_handler);
634
  
635
  value = combo_box_get (combo, &custom);
636

637 638
  /* Handle constraints if the user entered a custom value. */
  if (custom)
639
    {
640 641 642 643 644 645 646 647 648 649 650 651 652 653
      switch (priv->source->type)
        {
        case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
          filtered_val = filter_numeric (value, FALSE, FALSE, &changed);
          break;
        case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
          filtered_val = filter_numeric (value, TRUE, FALSE, &changed);
          break;
        case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
          filtered_val = filter_numeric (value, TRUE, TRUE, &changed);
          break;
        default:
          break;
        }
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
    }

  if (filtered_val)
    {
      g_free (value);

      if (changed)
        {
          GtkEntry *entry;
	  
	  entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (combo)));

          gtk_entry_set_text (entry, filtered_val);
	}
      value = filtered_val;
    }

671
  if (value)
672
    gtk_printer_option_set (priv->source, value);
673
  g_free (value);
674
  g_signal_handler_unblock (priv->source, priv->source_changed_handler);
675 676 677 678
  emit_changed (widget);
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
679
entry_changed_cb (GtkWidget              *entry,
680 681
		  GtkPrinterOptionWidget *widget)
{
682
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
Matthias Clasen's avatar
Matthias Clasen committed
683
  const gchar *value;
684
  
685
  g_signal_handler_block (priv->source, priv->source_changed_handler);
686 687
  value = gtk_entry_get_text (GTK_ENTRY (entry));
  if (value)
688 689
    gtk_printer_option_set (priv->source, value);
  g_signal_handler_unblock (priv->source, priv->source_changed_handler);
690 691 692 693
  emit_changed (widget);
}


694 695 696 697 698
static void
radio_changed_cb (GtkWidget              *button,
		  GtkPrinterOptionWidget *widget)
{
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
Matthias Clasen's avatar
Matthias Clasen committed
699
  gchar *value;
700 701 702 703 704 705 706 707 708 709
  
  g_signal_handler_block (priv->source, priv->source_changed_handler);
  value = g_object_get_data (G_OBJECT (button), "value");
  if (value)
    gtk_printer_option_set (priv->source, value);
  g_signal_handler_unblock (priv->source, priv->source_changed_handler);
  emit_changed (widget);
}

static void
Matthias Clasen's avatar
~  
Matthias Clasen committed
710 711
select_maybe (GtkWidget   *widget, 
	      const gchar *value)
712
{
Matthias Clasen's avatar
Matthias Clasen committed
713
  gchar *v = g_object_get_data (G_OBJECT (widget), "value");
714
      
Matthias Clasen's avatar
~  
Matthias Clasen committed
715 716 717
  if (strcmp (value, v) == 0)
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
}
718

Matthias Clasen's avatar
~  
Matthias Clasen committed
719 720 721 722 723 724
static void
alternative_set (GtkWidget   *box,
		 const gchar *value)
{
  gtk_container_foreach (GTK_CONTAINER (box), 
			 (GtkCallback) select_maybe,
725
			 (gpointer) value);
726 727 728
}

static GSList *
Matthias Clasen's avatar
Matthias Clasen committed
729 730 731
alternative_append (GtkWidget              *box,
		    const gchar            *label,
                    const gchar            *value,
732
		    GtkPrinterOptionWidget *widget,
Matthias Clasen's avatar
Matthias Clasen committed
733
		    GSList                 *group)
734 735 736 737 738
{
  GtkWidget *button;

  button = gtk_radio_button_new_with_label (group, label);
  gtk_widget_show (button);
739
  gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
740 741 742 743 744 745 746 747 748
  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);

  g_object_set_data (G_OBJECT (button), "value", (gpointer)value);
  g_signal_connect (button, "toggled", 
		    G_CALLBACK (radio_changed_cb), widget);

  return gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
}

749 750 751
static void
construct_widgets (GtkPrinterOptionWidget *widget)
{
752
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
753 754 755
  GtkPrinterOption *source;
  char *text;
  int i;
756
  GSList *group;
757

758
  source = priv->source;
759 760 761
  
  deconstruct_widgets (widget);
  
762
  gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
763

764 765
  if (source == NULL)
    {
766 767 768
      priv->combo = combo_box_new ();
      combo_box_append (priv->combo,_("Not available"), "None");
      gtk_combo_box_set_active (GTK_COMBO_BOX (priv->combo), 0);
769
      gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE);
770 771
      gtk_widget_show (priv->combo);
      gtk_box_pack_start (GTK_BOX (widget), priv->combo, TRUE, TRUE, 0);
772 773 774 775
    }
  else switch (source->type)
    {
    case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
776 777 778 779
      priv->check = gtk_check_button_new_with_mnemonic (source->display_text);
      g_signal_connect (priv->check, "toggled", G_CALLBACK (check_toggled_cb), widget);
      gtk_widget_show (priv->check);
      gtk_box_pack_start (GTK_BOX (widget), priv->check, TRUE, TRUE, 0);
780 781
      break;
    case GTK_PRINTER_OPTION_TYPE_PICKONE:
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
    case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD:
    case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
    case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
    case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
    case GTK_PRINTER_OPTION_TYPE_PICKONE_STRING:
      if (source->type == GTK_PRINTER_OPTION_TYPE_PICKONE)
        {
          priv->combo = combo_box_new ();
	}
      else
        {
          priv->combo = combo_box_entry_new ();

          if (source->type == GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD ||
	      source->type == GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE)
	    {
              GtkEntry *entry;

	      entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->combo)));

              gtk_entry_set_visibility (entry, FALSE); 
	    }
        }

806
      for (i = 0; i < source->num_choices; i++)
807 808 809
        combo_box_append (priv->combo,
                          source->choices_display[i],
                          source->choices[i]);
810 811 812
      gtk_widget_show (priv->combo);
      gtk_box_pack_start (GTK_BOX (widget), priv->combo, TRUE, TRUE, 0);
      g_signal_connect (priv->combo, "changed", G_CALLBACK (combo_changed_cb), widget);
813

814
      text = g_strdup_printf ("%s:", source->display_text);
815
      priv->label = gtk_label_new_with_mnemonic (text);
816
      g_free (text);
817
      gtk_widget_show (priv->label);
818
      break;
819 820 821

    case GTK_PRINTER_OPTION_TYPE_ALTERNATIVE:
      group = NULL;
822
      priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
823
      gtk_widget_set_valign (priv->box, GTK_ALIGN_BASELINE);
824 825 826
      gtk_widget_show (priv->box);
      gtk_box_pack_start (GTK_BOX (widget), priv->box, TRUE, TRUE, 0);
      for (i = 0; i < source->num_choices; i++)
827 828 829 830 831 832 833 834 835 836
        {
	  group = alternative_append (priv->box,
                                      source->choices_display[i],
                                      source->choices[i],
                                      widget,
                                      group);
          /* for mnemonic activation */
          if (i == 0)
            priv->button = group->data;
        }
837 838 839 840 841

      if (source->display_text)
	{
	  text = g_strdup_printf ("%s:", source->display_text);
	  priv->label = gtk_label_new_with_mnemonic (text);
842
          gtk_widget_set_valign (priv->label, GTK_ALIGN_BASELINE);
843 844 845 846 847
	  g_free (text);
	  gtk_widget_show (priv->label);
	}
      break;

848
    case GTK_PRINTER_OPTION_TYPE_STRING:
849
      priv->entry = gtk_entry_new ();
850 851
      gtk_entry_set_activates_default (GTK_ENTRY (priv->entry),
                                       gtk_printer_option_get_activates_default (source));
852 853 854
      gtk_widget_show (priv->entry);
      gtk_box_pack_start (GTK_BOX (widget), priv->entry, TRUE, TRUE, 0);
      g_signal_connect (priv->entry, "changed", G_CALLBACK (entry_changed_cb), widget);
855

856
      text = g_strdup_printf ("%s:", source->display_text);
857
      priv->label = gtk_label_new_with_mnemonic (text);
858
      g_free (text);
859
      gtk_widget_show (priv->label);
860 861 862 863

      break;

    case GTK_PRINTER_OPTION_TYPE_FILESAVE:
864 865 866 867
      priv->button = gtk_button_new ();
      gtk_widget_show (priv->button);
      gtk_box_pack_start (GTK_BOX (widget), priv->button, TRUE, TRUE, 0);
      g_signal_connect (priv->button, "clicked", G_CALLBACK (filesave_choose_cb), widget);
868

869 870 871 872
      text = g_strdup_printf ("%s:", source->display_text);
      priv->label = gtk_label_new_with_mnemonic (text);
      g_free (text);
      gtk_widget_show (priv->label);
873 874

      break;
875 876 877 878

    case GTK_PRINTER_OPTION_TYPE_INFO:
      priv->info_label = gtk_label_new (NULL);
      gtk_label_set_selectable (GTK_LABEL (priv->info_label), TRUE);
879 880
      gtk_widget_show (priv->info_label);
      gtk_box_pack_start (GTK_BOX (widget), priv->info_label, FALSE, TRUE, 0);
881 882 883 884 885 886 887 888

      text = g_strdup_printf ("%s:", source->display_text);
      priv->label = gtk_label_new_with_mnemonic (text);
      g_free (text);
      gtk_widget_show (priv->label);

      break;

889 890 891 892
    default:
      break;
    }

893
  priv->image = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_MENU);
894
  gtk_box_pack_start (GTK_BOX (widget), priv->image, FALSE, FALSE, 0);
895 896
}

897
/*
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
 * If the filename exceeds FILENAME_LENGTH_MAX, then trim it and replace
 * the first three letters with three dots.
 */
static gchar *
trim_long_filename (const gchar *filename)
{
  const gchar *home;
  gint len, offset;
  gchar *result;

  home = g_get_home_dir ();
  if (g_str_has_prefix (filename, home))
    {
      gchar *homeless_filename;

      offset = g_utf8_strlen (home, -1);
      len = g_utf8_strlen (filename, -1);
      homeless_filename = g_utf8_substring (filename, offset, len);
      result = g_strconcat ("~", homeless_filename, NULL);
      g_free (homeless_filename);
    }
  else
    result = g_strdup (filename);

  len = g_utf8_strlen (result, -1);
  if (len > FILENAME_LENGTH_MAX)
    {
      gchar *suffix;

      suffix = g_utf8_substring (result, len - FILENAME_LENGTH_MAX, len);
      g_free (result);
      result = g_strconcat ("...", suffix, NULL);
      g_free (suffix);
    }

  return result;
}

936 937 938
static void
update_widgets (GtkPrinterOptionWidget *widget)
{
939
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;
940 941
  GtkPrinterOption *source;

942
  source = priv->source;
943 944 945
  
  if (source == NULL)
    {
946
      gtk_widget_hide (priv->image);
947 948 949 950 951 952
      return;
    }

  switch (source->type)
    {
    case GTK_PRINTER_OPTION_TYPE_BOOLEAN:
953
      if (g_ascii_strcasecmp (source->value, "True") == 0)
954
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->check), TRUE);
955
      else
956
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->check), FALSE);
957 958
      break;
    case GTK_PRINTER_OPTION_TYPE_PICKONE:
959
      combo_box_set (priv->combo, source->value);
960
      break;
961 962 963
    case GTK_PRINTER_OPTION_TYPE_ALTERNATIVE:
      alternative_set (priv->box, source->value);
      break;
964
    case GTK_PRINTER_OPTION_TYPE_STRING:
965
      gtk_entry_set_text (GTK_ENTRY (priv->entry), source->value);
966
      break;
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
    case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSWORD:
    case GTK_PRINTER_OPTION_TYPE_PICKONE_PASSCODE:
    case GTK_PRINTER_OPTION_TYPE_PICKONE_REAL:
    case GTK_PRINTER_OPTION_TYPE_PICKONE_INT:
    case GTK_PRINTER_OPTION_TYPE_PICKONE_STRING:
      {
        GtkEntry *entry;

        entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->combo)));
        if (gtk_printer_option_has_choice (source, source->value))
          combo_box_set (priv->combo, source->value);
        else
          gtk_entry_set_text (entry, source->value);

        break;
      }
983 984
    case GTK_PRINTER_OPTION_TYPE_FILESAVE:
      {
985 986 987 988
        gchar *text;
        gchar *filename;

        filename = g_filename_from_uri (source->value, NULL, NULL);
989 990
        if (filename != NULL)
          {
991 992 993 994
            text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
            if (text != NULL)
              {
                gchar *short_filename;
995

996 997 998 999
                short_filename = trim_long_filename (text);
                gtk_button_set_label (GTK_BUTTON (priv->button), short_filename);
                g_free (short_filename);
              }
1000 1001 1002 1003

            g_free (text);
            g_free (filename);
          }
1004 1005 1006
        else
          gtk_button_set_label (GTK_BUTTON (priv->button), source->value);
        break;
1007
      }
1008 1009 1010
    case GTK_PRINTER_OPTION_TYPE_INFO:
      gtk_label_set_text (GTK_LABEL (priv->info_label), source->value);
      break;
1011 1012 1013 1014 1015
    default:
      break;
    }

  if (source->has_conflict)
1016
    gtk_widget_show (priv->image);
1017
  else
1018
    gtk_widget_hide (priv->image);
1019 1020 1021
}

gboolean
Matthias Clasen's avatar
Matthias Clasen committed
1022
gtk_printer_option_widget_has_external_label (GtkPrinterOptionWidget *widget)
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
{
  return widget->priv->label != NULL;
}

GtkWidget *
gtk_printer_option_widget_get_external_label (GtkPrinterOptionWidget  *widget)
{
  return widget->priv->label;
}

Matthias Clasen's avatar
Matthias Clasen committed
1033 1034
const gchar *
gtk_printer_option_widget_get_value (GtkPrinterOptionWidget *widget)
1035
{
1036 1037 1038 1039
  GtkPrinterOptionWidgetPrivate *priv = widget->priv;

  if (priv->source)
    return priv->source->value;
1040

1041 1042
  return "";
}