package interactive; # $Id: interactive.pm 247292 2008-10-01 15:23:37Z tv $ use diagnostics; use strict; #-###################################################################################### #- misc imports #-###################################################################################### use common; use do_pkgs; #- minimal example using interactive: # #- > use lib qw(/usr/lib/libDrakX); #- > use interactive; #- > my $in = interactive->vnew; #- > $in->ask_okcancel('title', 'question'); #- > $in->exit; #- ask_from_ takes global options ($common): #- title => window title #- messages => message displayed in the upper part of the window #- ok => force the name of the "Ok"/"Next" button #- cancel => force the name of the "Cancel"/"Previous" button #- focus_cancel => force focus on the "Cancel" button #- focus_first => (deprecated) force focus on the first entry #- ok_disabled => function returning wether {ok} should be disabled (grayed) #- validate => function called when {ok} is pressed. If it returns false, the first entry is focused, otherwise it quits #- advanced => (deprecated) function called when the "advanced" expander is toggled #- advanced_messages => (deprecated) message displayed when "Advanced" is pressed #- advanced_label => (deprecated) force the name of the "Advanced" button #- advanced_label_close => (deprecated) force the name of the "Basic" button #- advanced_state => (deprecated) if set to 1, force the "Advanced" part of the dialog to be opened initially #- callbacks => (deprecated) functions called when something happen: complete advanced ok_disabled #- ask_from_ takes a list of entries with fields: #- val => reference to the value #- label => description #- title => a boolean: whether the label should be displayed as a title (see GNOME's HIG) #- icon => icon to put before the description #- help => tooltip #- advanced => (deprecated) wether it is shown in by default or only in advanced mode #- focus_out => function called when the entry is focused out #- changed => function called when the entry is modified #- validate => function called when "Ok" is pressed. If it returns false, this entry is focused, otherwise it quits #- disabled => function returning wether it should be disabled (grayed) #- focus => function returning wether it should be focused #- alignment => preferred alignment #- do_not_expand => do not eat all horizontal space #- install_button => if possible, use improved graphical style #- gtk => gtk preferences #- type => #- button => (with clicked or clicked_may_quit) #- (type defaults to button if clicked or clicked_may_quit is there) #- (val need not be a reference) (if clicked_may_quit return true, it's as if "Ok" was pressed) #- label => (val need not be a reference) (type defaults to label if val is not a reference) #- bool (with "text" or "image" (which overrides text) giving an image filename) #- range (with min, max, SpinButton) #- combo (with list, not_edit, format) #- list (with list, icon2f (aka icon), separator (aka tree), format (aka pre_format function), #- help can be a hash or a function, #- tree_expanded boolean telling wether the tree should be wide open by default #- quit_if_double_click boolean #- allow_empty_list disables the special cases for 0 and 1 element lists #- image2f is a subroutine which takes a value of the list as parameter, and returns image_file_name #- entry (the default) (with hidden) #- expander (with text, expanded, message, children(a list of sub entries)) # #- heritate from this class and you'll get all made interactivity for same steps. #- for this you need to provide #- - ask_from_listW(o, title, messages, arrayref, default) returns one string of arrayref #- #- where #- - o is the object #- - title is a string #- - messages is an refarray of strings #- - default is an optional string (default is in arrayref) #- - arrayref is an arrayref of strings #- - arrayref2 contains booleans telling the default state, #- #- ask_from_list and ask_from_list_ are wrappers around ask_from_biglist and ask_from_smalllist #- #- ask_from_list_ just translate arrayref before calling ask_from_list and untranslate the result #- #- ask_from_listW should handle differently small lists and big ones. #- #-###################################################################################### #- OO Stuff #-###################################################################################### our @ISA = qw(do_pkgs); sub new($) { my ($type) = @_; bless {}, ref($type) || $type; } sub vnew { my ($_type, $o_su, $o_icon) = @_; my $su = $o_su eq "su"; if ($ENV{INTERACTIVE_HTTP}) { require interactive::http; return interactive::http->new; } require c; if ($su) { $ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}"; $su = '' if $::testing || $ENV{TESTING}; } require_root_capability() if $su; if (check_for_xserver()) { eval { require interactive::gtk }; if (!$@) { my $o = interactive::gtk->new; if ($o_icon && $o_icon ne 'default' && !$::isWizard) { $o->{icon} = $o_icon } else { undef $o->{icon} } return $o; } elsif ($::testing) { die; } } require interactive::curses; interactive::curses->new; } sub ok { N_("Ok") } sub cancel { N_("Cancel") } sub markup_parse { my ($s) = @_; my @l; my @attrs; while ($s) { if ($s =~ s!^<(\w+)(\s+[^>]*?)?>!!s) { push @attrs, [ $1, $2 ]; } elsif ($s =~ s!^(\w+)>!!) { my $previous = pop @attrs; $previous->[0] eq $1 or return; } elsif ($s =~ s!^(&(amp|lt|gt);)!!) { push @l, [ $1, @attrs ]; } elsif ($s =~ s!^([^<>&]+)!!s) { push @l, [ $1, @attrs ]; } else { return; } } markup_simplify(\@l); \@l; } sub markup_simplify { my ($l) = @_; foreach (@$l) { my ($s, @attrs) = @$_; my %attrs = map { my ($tag, $attrs) = @$_; my $long = { b => { weight => "bold" }, i => { style => "italic" }, big => { size => 'larger' }, }->{$tag}; $long ? %$long : map { /^(.*?)=['"]?(.*?)['"]?$/ } split(' ', $attrs); } @attrs; $s = +{ '&' => '&', '<' => '<', '>' => '>' }->{$s} || $s; @$_ = ($s, if_(%attrs, \%attrs)); } } sub markup_remove { my ($s) = @_; if (my $l = markup_parse($s)) { join('', map { $_->[0] } @$l); } else { $s; } } #- drop markup as fallback sub adapt_markup { my ($_o, $s) = @_; markup_remove($s); } sub enter_console {} sub leave_console {} sub suspend {} sub resume {} sub end {} sub exit { if ($::isStandalone) { require standalone; standalone::exit($_[0]); } else { exit($_[0]); } } #-################################################################PHPBB3-11688