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
|