File: Multiselect.pm

package info (click to toggle)
debconf 1.5.91
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 5,180 kB
  • sloc: perl: 8,500; sh: 262; python: 182; makefile: 144
file content (140 lines) | stat: -rw-r--r-- 3,359 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/perl

=head1 NAME

Debconf::Element::Teletype::Multiselect - select multiple items

=cut

package Debconf::Element::Teletype::Multiselect;
use warnings;
use strict;
use Debconf::Gettext;
use Debconf::Config;
use base qw(Debconf::Element::Multiselect Debconf::Element::Teletype::Select);

=head1 DESCRIPTION

This lets the user select multiple items from a list of values, using a
teletype interface. (This is hard to do in plain text, and the UI I have made
isn't very intuitive. Better UI designs welcomed.)

=cut

=head1 METHODS

=over 4

=item expand_ranges

Expand ranges of numbers input by the user.

    expand_ranges(qw(1 foo 4-6 bar));
    => qw(1 foo 4 5 6 bar)

=back

=cut

sub expand_ranges {
	my @ranges = @_;
	my @accumulator;
	for my $item (@ranges) {
		if ($item =~ /\A(\d+)-(\d+)\Z/) {
			my ($begin, $end) = ($1, $2);
			for (my $i = $begin; $i <= $end; $i++) {
				push @accumulator, $i;
			}
		}
		else {
			push @accumulator, $item;
		}
	}
	return @accumulator;
}

sub show {
	my $this=shift;

	my @selected;
	my $none_of_the_above=gettext("none of the above");

	my @choices=$this->question->choices_split;
	my %value = map { $_ => 1 } $this->translate_default;
	if ($this->frontend->promptdefault && $this->question->value ne '') {
		push @choices, $none_of_the_above;
	}
	my @completions=@choices;
	my $i=1;
	my %choicenum=map { $_ => $i++ } @choices;

	# Print out the question.
	$this->frontend->display($this->question->extended_description."\n");

	# If this is not terse mode, we want to print out choices, and
	# add numbers to the completions, and use numbers in the default
	# prompt.
	my $default;
	if (Debconf::Config->terse eq 'false') {
		$this->printlist(@choices);
		$this->frontend->display("\n(".gettext("Enter the items or ranges you want to select, separated by spaces.").")\n");
		push @completions, 1..@choices;
		$default=join(" ", map { $choicenum{$_} }
		                   grep { $value{$_} } @choices);
	}
	else {
		$default=join(" ", grep { $value{$_} } @choices);
	}

	# Prompt until a valid answer is entered.
	while (1) {
		$_=$this->frontend->prompt(
			prompt => $this->question->description,
		 	default => $default,
			completions => [@completions],
			completion_append_character => " ",
			question => $this->question,
		);
		return unless defined $_;

		# Split up what they entered. They can separate items
		# with whitespace or commas.
		@selected=split(/[	 ,]+/, $_);

		@selected=expand_ranges(@selected);

		# Expand what they entered.
		@selected=map { $this->expandabbrev($_, @choices) } @selected;

		# Test to make sure everything they entered expanded ok.
		# If not loop.
		next if grep { $_ eq '' } @selected;

		# Make sure that they didn't select "none of the above"
		# along with some other item. That's undefined, so don't
		# accept it.
		if ($#selected > 0) {
			map { next if $_ eq $none_of_the_above } @selected;
		}

		last;
	}

	$this->frontend->display("\n");

	if (defined $selected[0] && $selected[0] eq $none_of_the_above) {
		$this->value('');
	}
	else {
		# Make sure that no item was entered twice. If so, remove
		# the duplicate.
		my %selected=map { $_ => 1 } @selected;

		# Translate back to C locale, and join the list.
		$this->value(join(', ', $this->order_values(
				map { $this->translate_to_C($_) }
		                keys %selected)));
	}
}

1