#************************************************************** # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #************************************************************** package installer::windows::feature; use installer::existence; use installer::exiter; use installer::files; use installer::globals; use installer::sorter; use installer::worker; use installer::windows::idtglobal; use installer::windows::language; ############################################################## # Returning the gid for a feature. # Attention: Maximum length ############################################################## sub get_feature_gid { my ($onefeature) = @_; my $gid = ""; if ( $onefeature->{'gid'} ) { $gid = $onefeature->{'gid'}; } # Attention: Maximum feature length is 38! installer::windows::idtglobal::shorten_feature_gid(\$gid); return $gid } ############################################################## # Returning the gid of the parent. # Attention: Maximum length ############################################################## sub get_feature_parent { my ($onefeature) = @_; my $parentgid = ""; if ( $onefeature->{'ParentID'} ) { $parentgid = $onefeature->{'ParentID'}; } # The modules, hanging directly below the root, have to be root modules. # Only then it is possible to make the "real" root module invisible by # setting the display to "0". if ( $parentgid eq $installer::globals::rootmodulegid ) { $parentgid = ""; } # Attention: Maximum feature length is 38! installer::windows::idtglobal::shorten_feature_gid(\$parentgid); return $parentgid } ############################################################## # Returning the display for a feature. # 0: Feature is not shown # odd: subfeatures are shown # even: subfeatures are not shown ############################################################## sub get_feature_display { my ($onefeature) = @_; my $display; my $parentid = ""; if ( $onefeature->{'ParentID'} ) { $parentid = $onefeature->{'ParentID'}; } if ( $parentid eq "" ) { $display = "0"; # root module is not visible } elsif ( $onefeature->{'gid'} eq "gid_Module_Prg") # program module shows subfeatures { $display = "1"; # root module shows subfeatures } else { $display = "2"; # all other modules do not show subfeatures } # special case: Feature has flag "HIDDEN_ROOT" -> $display is 0 my $styles = ""; if ( $onefeature->{'Styles'} ) { $styles = $onefeature->{'Styles'}; } if ( $styles =~ /\bHIDDEN_ROOT\b/ ) { $display = "0"; } # Special handling for language modules. Only visible in multilingual installation set if (( $styles =~ /\bSHOW_MULTILINGUAL_ONLY\b/ ) && ( ! $installer::globals::ismultilingual )) { $display = "0"; } # Special handling for c05office. No program module visible. if (( $onefeature->{'gid'} eq "gid_Module_Prg" ) && ( $installer::globals::product =~ /c05office/i )) { $display = "0"; } # making all feature invisible in Language packs! if ( $installer::globals::languagepack ) { $display = "0"; } return $display } ############################################################## # Returning the level for a feature. ############################################################## sub get_feature_level { my ($onefeature) = @_; my $level = "20"; # the default my $localdefault = ""; if ( $onefeature->{'Default'} ) { $localdefault = $onefeature->{'Default'}; } if ( $localdefault eq "NO" ) # explicitely set Default = "NO" { $level = "200"; # deselected in default installation, base is 100 if ( $installer::globals::patch ) { $level = "20"; } } # special handling for Java and Ada if ( $onefeature->{'Name'} ) { if ( $onefeature->{'Name'} =~ /java/i ) { $level = $level + 40; } } # if FeatureLevel is defined in scp, this will be used if ( $onefeature->{'FeatureLevel'} ) { $level = $onefeature->{'FeatureLevel'}; } return $level } ############################################################## # Returning the directory for a feature. ############################################################## sub get_feature_directory { my ($onefeature) = @_; my $directory; $directory = "INSTALLLOCATION"; return $directory } ############################################################## # Returning the directory for a feature. ############################################################## sub get_feature_attributes { my ($onefeature) = @_; my $attributes; # No advertising of features and no leaving on network. # Feature without parent must not have the "2" my $parentgid = ""; if ( $onefeature->{'ParentID'} ) { $parentgid = $onefeature->{'ParentID'}; } if (( $parentgid eq "" ) || ( $parentgid eq $installer::globals::rootmodulegid )) { $attributes = "8"; } else { $attributes = "10"; } return $attributes } ################################################################################# # Replacing one variable in one files ################################################################################# sub replace_one_variable { my ($translationfile, $variable, $searchstring) = @_; for ( my $i = 0; $i <= $#{$translationfile}; $i++ ) { ${$translationfile}[$i] =~ s/\%$searchstring/$variable/g; } } ################################################################################# # Replacing the variables in the feature names and descriptions ################################################################################# sub replace_variables { my ($translationfile, $variableshashref) = @_; foreach $key (keys %{$variableshashref}) { my $value = $variableshashref->{$key}; replace_one_variable($translationfile, $value, $key); } } ################################################################################# # Collecting the feature recursively. ################################################################################# sub collect_modules_recursive { my ($modulesref, $parentid, $feature, $directaccess, $directgid, $directparent, $directsortkey, $sorted) = @_; my @allchildren = (); my $childrenexist = 0; # Collecting children from Module $parentid my $modulegid; foreach $modulegid ( keys %{$directparent}) { if ( $directparent->{$modulegid} eq $parentid ) { my %childhash = ( "gid" => "$modulegid", "Sortkey" => "$directsortkey->{$modulegid}"); push(@allchildren, \%childhash); $childrenexist = 1; } } # Sorting children if ( $childrenexist ) { # Sort children installer::sorter::sort_array_of_hashes_numerically(\@allchildren, "Sortkey"); # Adding children to new array my $childhashref; foreach $childhashref ( @allchildren ) { my $gid = $childhashref->{'gid'}; # Saving all lines, that have this 'gid' my $unique; foreach $unique ( keys %{$directgid} ) { if ( $directgid->{$unique} eq $gid ) { push(@{$feature}, ${$modulesref}[$directaccess->{$unique}]); if ( $sorted->{$unique} == 1 ) { installer::exiter::exit_program("ERROR: Sorting feature failed! \"$unique\" already sorted.", "sort_feature"); } $sorted->{$unique} = 1; } } collect_modules_recursive($modulesref, $gid, $feature, $directaccess, $directgid, $directparent, $directsortkey, $sorted); } } } ################################################################################# # Sorting the feature in specified order. Evaluated is the key "Sortkey", that # is set in scp2 projects. # The display order of modules in Windows Installer is dependent from the order # in the idt file. Therefore the order of the modules array has to be adapted # to the Sortkey order, before the idt file is created. ################################################################################# sub sort_feature { my ($modulesref) = @_; my @feature = (); my %directaccess = (); my %directparent = (); my %directgid = (); my %directsortkey = (); my %sorted = (); for ( my $i = 0; $i <= $#{$modulesref}; $i++ ) { my $onefeature = ${$modulesref}[$i]; my $uniquekey = $onefeature->{'uniquekey'}; my $modulegid = $onefeature->{'gid'}; $directaccess{$uniquekey} = $i; $directgid{$uniquekey} = $onefeature->{'gid'}; # ParentID and Sortkey are not saved for the 'uniquekey', but only for the 'gid' if ( $onefeature->{'ParentID'} ) { $directparent{$modulegid} = $onefeature->{'ParentID'}; } else { $directparent{$modulegid} = ""; } if ( $onefeature->{'Sortkey'} ) { $directsortkey{$modulegid} = $onefeature->{'Sortkey'}; } else { $directsortkey{$modulegid} = "9999"; } # Bookkeeping: $sorted{$uniquekey} = 0; } # Searching all feature recursively, beginning with ParentID = "" my $parentid = ""; collect_modules_recursive($modulesref, $parentid, \@feature, \%directaccess, \%directgid, \%directparent, \%directsortkey, \%sorted); # Bookkeeping my $modulekey; foreach $modulekey ( keys %sorted ) { if ( $sorted{$modulekey} == 0 ) { my $infoline = "Warning: Module \"$modulekey\" could not be sorted. Added to the end of the module array.\n"; push(@installer::globals::logfileinfo, $infoline); push(@feature, ${$modulesref}[$directaccess{$modulekey}]); } } return \@feature; } ################################################################################# # Adding a unique key to the modules array. The gid is not unique for # multilingual modules. Only the combination from gid and specific language # is unique. Uniqueness is required for sorting mechanism. ################################################################################# sub add_uniquekey { my ( $modulesref ) = @_; for ( my $i = 0; $i <= $#{$modulesref}; $i++ ) { my $uniquekey = ${$modulesref}[$i]->{'gid'}; if ( ${$modulesref}[$i]->{'specificlanguage'} ) { $uniquekey = $uniquekey . "_" . ${$modulesref}[$i]->{'specificlanguage'}; } ${$modulesref}[$i]->{'uniquekey'} = $uniquekey; } } ################################################################################# # Creating the file Feature.idt dynamically # Content: # Feature Feature_Parent Title Description Display Level Directory_ Attributes ################################################################################# sub create_feature_table { my ($modulesref, $basedir, $languagesarrayref, $allvariableshashref) = @_; for ( my $m = 0; $m <= $#{$languagesarrayref}; $m++ ) { my $onelanguage = ${$languagesarrayref}[$m]; my $infoline; my @featuretable = (); installer::windows::idtglobal::write_idt_header(\@featuretable, "feature"); for ( my $i = 0; $i <= $#{$modulesref}; $i++ ) { my $onefeature = ${$modulesref}[$i]; # Java and Ada only, if the correct settings are set my $styles = ""; if ( $onefeature->{'Styles'} ) { $styles = $onefeature->{'Styles'}; } if (( $styles =~ /\bJAVAMODULE\b/ ) && ( ! ($allvariableshashref->{'JAVAPRODUCT'} ))) { next; } if (( $styles =~ /\bADAMODULE\b/ ) && ( ! ($allvariableshashref->{'ADAPRODUCT'} ))) { next; } # Controlling the language! # Only language independent feature or feature with the correct language will be included into the table if (! (!(( $onefeature->{'ismultilingual'} )) || ( $onefeature->{'specificlanguage'} eq $onelanguage )) ) { next; } my %feature = (); $feature{'feature'} = get_feature_gid($onefeature); $feature{'feature_parent'} = get_feature_parent($onefeature); # if ( $onefeature->{'ParentID'} eq "" ) { $feature{'feature_parent'} = ""; } # Root has no parent $feature{'Title'} = $onefeature->{'Name'}; $feature{'Description'} = $onefeature->{'Description'}; $feature{'Display'} = get_feature_display($onefeature); $feature{'Level'} = get_feature_level($onefeature); $feature{'Directory_'} = get_feature_directory($onefeature); $feature{'Attributes'} = get_feature_attributes($onefeature); my $oneline = $feature{'feature'} . "\t" . $feature{'feature_parent'} . "\t" . $feature{'Title'} . "\t" . $feature{'Description'} . "\t" . $feature{'Display'} . "\t" . $feature{'Level'} . "\t" . $feature{'Directory_'} . "\t" . $feature{'Attributes'} . "\n"; push(@featuretable, $oneline); # collecting all feature in global feature collector (so that properties can be set in property table) if ( ! installer::existence::exists_in_array($feature{'feature'}, \@installer::globals::featurecollector) ) { push(@installer::globals::featurecollector, $feature{'feature'}); } # collecting all language feature in feature collector for check of language selection if (( $styles =~ /\bSHOW_MULTILINGUAL_ONLY\b/ ) && ( $onefeature->{'ParentID'} ne $installer::globals::rootmodulegid )) { $installer::globals::multilingual_only_modules{$feature{'feature'}} = 1; } # collecting all application feature in global feature collector for check of application selection if ( $styles =~ /\bAPPLICATIONMODULE\b/ ) { $installer::globals::application_modules{$feature{'feature'}} = 1; } } # Saving the file my $featuretablename = $basedir . $installer::globals::separator . "Feature.idt" . "." . $onelanguage; installer::files::save_file($featuretablename ,\@featuretable); $infoline = "Created idt file: $featuretablename\n"; push(@installer::globals::logfileinfo, $infoline); } } 1;