diff options
author | Dexter Morgan <dmorgan@mageia.org> | 2011-06-02 20:51:35 +0000 |
---|---|---|
committer | Dexter Morgan <dmorgan@mageia.org> | 2011-06-02 20:51:35 +0000 |
commit | a9b2bdafaf625d10aef2f476aa4014fd36c846bc (patch) | |
tree | 2364afc0ee6739b59a25c44d68c9f003bcaf03d9 /perl-install/wizards.pm | |
download | drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.tar drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.tar.gz drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.tar.bz2 drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.tar.xz drakx-a9b2bdafaf625d10aef2f476aa4014fd36c846bc.zip |
Branch for updates
Diffstat (limited to 'perl-install/wizards.pm')
-rw-r--r-- | perl-install/wizards.pm | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/perl-install/wizards.pm b/perl-install/wizards.pm new file mode 100644 index 000000000..b0f03e340 --- /dev/null +++ b/perl-install/wizards.pm @@ -0,0 +1,206 @@ +package wizards; +# $Id: wizards.pm 230802 2007-10-04 13:36:01Z tv $ + +use strict; +use c; +use common; + +=head1 NAME + +wizards - a layer on top of interactive that ensure proper stepping + +=head1 SYNOPSIS + + use wizards; + use interactive; + + my $wiz = wizards->new({ + + allow_user => "", # do we need root + defaultimage => "", # wizard icon + init => sub { }, # code run on wizard startup + name => "logdrake", # wizard title + needed_rpm => "packages list", # packages to install before running the wizard + pages => { + { + name => "welcome", # first step + next => "step1", # which step should be displayed after the current one + pre => sub { }, # code executing when stepping backward + post => sub { }, # code executing when stepping forward; + # returned value is next step name (it overrides "next" field) + end => , # is it the last step ? + default => , # default answer for yes/no or when data does not conatains any fields + no_cancel => , # do not display the cancel button (eg for first step) + no_back => , # do not display the back button (eg for first step) + ignore => , # do not stack this step for back stepping (eg for warnings and the like steps) + interactive_help_id => , # help id (for installer only) + data => [], # the actual data passed to interactive + }, + { + name => "step1", + data => [ + { + # usual interactive fields: + label => N("Banner:"), + val => \$o->{var}{wiz_banner}, + list => [] , + # wizard layer variables: + boolean_list => "", # provide default status for booleans list + }, + ], + }, + }, + }); + my $in = 'interactive'->vnew; + $wiz->process($in); + +=head1 DESCRIPTION + +wizards is a layer built on top of the interactive layer that do proper +backward/forward stepping for us. + +A step is made up of a name/description, a list of interactive fields (see +interactive documentation), a "complete", "pre" and "post" callbacks, an help +id, ... + +The "pre" callback is run first. Its only argument is the actual step hash. + +Then, if the "name" fiels is a code reference, that callback is run and its +actual result is used as the description of the step. + +At this stage, the interactive layer is used to display the actual step. + +The "post" callback is only run if the user has steped forward. + + +Alternatively, you can call safe_process() rather than process(). +safe_process() will handle for you the "wizcancel" exception while running the +wizard. Actually, it should be used everywhere but where the wizard is not the +main path (eg "mail alert wizard" in logdrake, ...), ie when you may need to do +extra exception managment such as destroying the wizard window and the like. + +=cut + + +sub new { + my ($class, $o) = @_; + bless $o, $class; +} + + +sub check_rpm { + my ($in, $rpms) = @_; + foreach my $rpm (@$rpms) { + next if $in->do_pkgs->is_installed($rpm); + if ($in->ask_okcancel(N("Error"), N("%s is not installed\nClick \"Next\" to install or \"Cancel\" to quit", $rpm))) { + $::testing and next; + if (!$in->do_pkgs->install($rpm)) { + local $::Wizard_finished = 1; + $in->ask_okcancel(N("Error"), N("Installation failed")); + $in->exit; + } + } else { $in->exit } + } +} + + +# sync me with interactive::ask_from_normalize() if needed: +my %default_callback = (complete => sub { 0 }); + + +sub process { + my ($o, $in) = @_; + local $::isWizard = 1; + local $::Wizard_title = $o->{name} || $::Wizard_title; + local $::Wizard_pix_up = $o->{defaultimage} || $::Wizard_pix_up; + #require_root_capability() if $> && !$o->{allow_user} && !$::testing; + check_rpm($in, $o->{needed_rpm}) if ref($o->{needed_rpm}); + if (defined $o->{init}) { + my ($res, $msg) = &{$o->{init}}; + if (!$res) { + $in->ask_okcancel(N("Error"), $msg); + die "wizard failed" if !$::testing; + } + } + + my @steps; # steps stack + + # initial step: + my $next = 'welcome'; + my $page = $o->{pages}{welcome}; + while ($next) { + local $::Wizard_no_previous = $page->{no_back}; + local $::Wizard_no_cancel = $page->{no_cancel} || $page->{end}; + local $::Wizard_finished = $page->{end}; + defined $page->{pre} and $page->{pre}($page); + die qq(inexistant "$next" wizard step) if is_empty_hash_ref($page); + + # FIXME or the displaying fails + my $data = defined $page->{data} ? (ref($page->{data}) eq 'CODE' ? $page->{data}->() : $page->{data}) : []; + my $data2; + foreach my $d (@$data) { + $d->{val} = ${$d->{val_ref}} if $d->{val_ref}; + $d->{list} = $d->{list_ref} if $d->{list_ref}; + #$d->{val} = ref($d->{val}) eq 'CODE' ? $d->{val}->() : $d->{val}; + if ($d->{boolean_list}) { + my $i; + foreach (@{$d->{boolean_list}}) { + push @$data2, { text => $_, type => 'bool', val => \${$d->{val}}->[$i], disabled => $d->{disabled} }; + $i++; + } + } else { + push @$data2, $d; + } + } + my $name = ref($page->{name}) ? $page->{name}->() : $page->{name}; + my %yesno = (yes => N("Yes"), no => N("No")); + my $yes = ref($page->{default}) eq 'CODE' ? $page->{default}->() : $page->{default}; + $data2 = [ { val => \$yes, type => 'list', list => [ keys %yesno ], format => sub { $yesno{$_[0]} }, + gtk => { use_boxradio => 1 } } ] if $page->{type} eq "yesorno"; + my $a; + if (ref $data2 eq 'ARRAY' && @$data2) { + $a = $in->ask_from_({ title => $o->{name}, + messages => $name, + (map { $_ => $page->{$_} || $default_callback{$_} } qw(complete)), + if_($page->{interactive_help_id}, interactive_help_id => $page->{interactive_help_id}), + }, $data2); + } else { + $a = $in->ask_okcancel($o->{name}, $name, $yes || 'ok'); + } + # interactive->ask_yesorno does not support stepping forward or backward: + $a = $yes if $a && $page->{type} eq "yesorno"; + if ($a) { + # step forward: + push @steps, $next if !$page->{ignore} && $steps[-1] ne $next; + my $current = $next; + $next = defined $page->{post} ? $page->{post}($page->{type} eq "yesorno" ? $yes eq 'yes' : $a) : 0; + return if $page->{end}; + if (!$next) { + if (!defined $o->{pages}{$next}) { + $next = $page->{next}; + } else { + die qq(the "$next" page (from previous wizard step) is undefined) if !$next; + } + } + die qq(Step "$current": inexistant "$next" page) if !exists $o->{pages}{$next}; + } else { + # step back: + $next = pop @steps; + } + $page = $o->{pages}{$next}; + } +} + + +sub safe_process { + my ($o, $in) = @_; + eval { $o->process($in) }; + my $err = $@; + if ($err =~ /wizcancel/) { + $in->exit(0); + } else { + die $err if $err; + } +} + +1; |