1#************************************************************** 2# 3# Licensed to the Apache Software Foundation (ASF) under one 4# or more contributor license agreements. See the NOTICE file 5# distributed with this work for additional information 6# regarding copyright ownership. The ASF licenses this file 7# to you under the Apache License, Version 2.0 (the 8# "License"); you may not use this file except in compliance 9# with the License. You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, 14# software distributed under the License is distributed on an 15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16# KIND, either express or implied. See the License for the 17# specific language governing permissions and limitations 18# under the License. 19# 20#************************************************************** 21 22 23 24package installer::windows::feature; 25 26use installer::existence; 27use installer::exiter; 28use installer::files; 29use installer::globals; 30use installer::sorter; 31use installer::worker; 32use installer::windows::idtglobal; 33use installer::windows::language; 34 35############################################################## 36# Returning the gid for a feature. 37# Attention: Maximum length 38############################################################## 39 40sub get_feature_gid 41{ 42 my ($onefeature) = @_; 43 44 my $gid = ""; 45 46 if ( $onefeature->{'gid'} ) { $gid = $onefeature->{'gid'}; } 47 48 # Attention: Maximum feature length is 38! 49 installer::windows::idtglobal::shorten_feature_gid(\$gid); 50 51 return $gid 52} 53 54############################################################## 55# Returning the gid of the parent. 56# Attention: Maximum length 57############################################################## 58 59sub get_feature_parent 60{ 61 my ($onefeature) = @_; 62 63 my $parentgid = ""; 64 65 if ( $onefeature->{'ParentID'} ) { $parentgid = $onefeature->{'ParentID'}; } 66 67 # The modules, hanging directly below the root, have to be root modules. 68 # Only then it is possible to make the "real" root module invisible by 69 # setting the display to "0". 70 71 if ( $parentgid eq $installer::globals::rootmodulegid ) { $parentgid = ""; } 72 73 # Attention: Maximum feature length is 38! 74 installer::windows::idtglobal::shorten_feature_gid(\$parentgid); 75 76 return $parentgid 77} 78 79############################################################## 80# Returning the display for a feature. 81# 0: Feature is not shown 82# odd: subfeatures are shown 83# even: subfeatures are not shown 84############################################################## 85 86sub get_feature_display 87{ 88 my ($onefeature) = @_; 89 90 my $display; 91 my $parentid = ""; 92 93 if ( $onefeature->{'ParentID'} ) { $parentid = $onefeature->{'ParentID'}; } 94 95 if ( $parentid eq "" ) 96 { 97 $display = "0"; # root module is not visible 98 } 99 elsif ( $onefeature->{'gid'} eq "gid_Module_Prg") # program module shows subfeatures 100 { 101 $display = "1"; # root module shows subfeatures 102 } 103 else 104 { 105 $display = "2"; # all other modules do not show subfeatures 106 } 107 108 # special case: Feature has flag "HIDDEN_ROOT" -> $display is 0 109 my $styles = ""; 110 if ( $onefeature->{'Styles'} ) { $styles = $onefeature->{'Styles'}; } 111 if ( $styles =~ /\bHIDDEN_ROOT\b/ ) { $display = "0"; } 112 113 # Special handling for language modules. Only visible in multilingual installation set 114 if (( $styles =~ /\bSHOW_MULTILINGUAL_ONLY\b/ ) && ( ! $installer::globals::ismultilingual )) { $display = "0"; } 115 116 # Special handling for c05office. No program module visible. 117 if (( $onefeature->{'gid'} eq "gid_Module_Prg" ) && ( $installer::globals::product =~ /c05office/i )) { $display = "0"; } 118 119 # making all feature invisible in Language packs! 120 if ( $installer::globals::languagepack ) { $display = "0"; } 121 122 return $display 123} 124 125############################################################## 126# Returning the level for a feature. 127############################################################## 128 129sub get_feature_level 130{ 131 my ($onefeature) = @_; 132 133 my $level = "20"; # the default 134 135 my $localdefault = ""; 136 137 if ( $onefeature->{'Default'} ) { $localdefault = $onefeature->{'Default'}; } 138 139 if ( $localdefault eq "NO" ) # explicitely set Default = "NO" 140 { 141 $level = "200"; # deselected in default installation, base is 100 142 if ( $installer::globals::patch ) { $level = "20"; } 143 } 144 145 # special handling for Java and Ada 146 if ( $onefeature->{'Name'} ) 147 { 148 if ( $onefeature->{'Name'} =~ /java/i ) { $level = $level + 40; } 149 } 150 151 # if FeatureLevel is defined in scp, this will be used 152 153 if ( $onefeature->{'FeatureLevel'} ) { $level = $onefeature->{'FeatureLevel'}; } 154 155 return $level 156} 157 158############################################################## 159# Returning the directory for a feature. 160############################################################## 161 162sub get_feature_directory 163{ 164 my ($onefeature) = @_; 165 166 my $directory; 167 168 $directory = "INSTALLLOCATION"; 169 170 return $directory 171} 172 173############################################################## 174# Returning the directory for a feature. 175############################################################## 176 177sub get_feature_attributes 178{ 179 my ($onefeature) = @_; 180 181 my $attributes; 182 183 # No advertising of features and no leaving on network. 184 # Feature without parent must not have the "2" 185 186 my $parentgid = ""; 187 if ( $onefeature->{'ParentID'} ) { $parentgid = $onefeature->{'ParentID'}; } 188 189 if (( $parentgid eq "" ) || ( $parentgid eq $installer::globals::rootmodulegid )) { $attributes = "8"; } 190 else { $attributes = "10"; } 191 192 return $attributes 193} 194 195################################################################################# 196# Replacing one variable in one files 197################################################################################# 198 199sub replace_one_variable 200{ 201 my ($translationfile, $variable, $searchstring) = @_; 202 203 for ( my $i = 0; $i <= $#{$translationfile}; $i++ ) 204 { 205 ${$translationfile}[$i] =~ s/\%$searchstring/$variable/g; 206 } 207} 208 209################################################################################# 210# Replacing the variables in the feature names and descriptions 211################################################################################# 212 213sub replace_variables 214{ 215 my ($translationfile, $variableshashref) = @_; 216 217 foreach $key (keys %{$variableshashref}) 218 { 219 my $value = $variableshashref->{$key}; 220 replace_one_variable($translationfile, $value, $key); 221 } 222} 223 224################################################################################# 225# Collecting the feature recursively. 226################################################################################# 227 228sub collect_modules_recursive 229{ 230 my ($modulesref, $parentid, $feature, $directaccess, $directgid, $directparent, $directsortkey, $sorted) = @_; 231 232 my @allchildren = (); 233 my $childrenexist = 0; 234 235 # Collecting children from Module $parentid 236 237 my $modulegid; 238 foreach $modulegid ( keys %{$directparent}) 239 { 240 if ( $directparent->{$modulegid} eq $parentid ) 241 { 242 my %childhash = ( "gid" => "$modulegid", "Sortkey" => "$directsortkey->{$modulegid}"); 243 push(@allchildren, \%childhash); 244 $childrenexist = 1; 245 } 246 } 247 248 # Sorting children 249 250 if ( $childrenexist ) 251 { 252 # Sort children 253 installer::sorter::sort_array_of_hashes_numerically(\@allchildren, "Sortkey"); 254 255 # Adding children to new array 256 my $childhashref; 257 foreach $childhashref ( @allchildren ) 258 { 259 my $gid = $childhashref->{'gid'}; 260 261 # Saving all lines, that have this 'gid' 262 263 my $unique; 264 foreach $unique ( keys %{$directgid} ) 265 { 266 if ( $directgid->{$unique} eq $gid ) 267 { 268 push(@{$feature}, ${$modulesref}[$directaccess->{$unique}]); 269 if ( $sorted->{$unique} == 1 ) { installer::exiter::exit_program("ERROR: Sorting feature failed! \"$unique\" already sorted.", "sort_feature"); } 270 $sorted->{$unique} = 1; 271 } 272 } 273 274 collect_modules_recursive($modulesref, $gid, $feature, $directaccess, $directgid, $directparent, $directsortkey, $sorted); 275 } 276 } 277} 278 279################################################################################# 280# Sorting the feature in specified order. Evaluated is the key "Sortkey", that 281# is set in scp2 projects. 282# The display order of modules in Windows Installer is dependent from the order 283# in the idt file. Therefore the order of the modules array has to be adapted 284# to the Sortkey order, before the idt file is created. 285################################################################################# 286 287sub sort_feature 288{ 289 my ($modulesref) = @_; 290 291 my @feature = (); 292 293 my %directaccess = (); 294 my %directparent = (); 295 my %directgid = (); 296 my %directsortkey = (); 297 my %sorted = (); 298 299 for ( my $i = 0; $i <= $#{$modulesref}; $i++ ) 300 { 301 my $onefeature = ${$modulesref}[$i]; 302 303 my $uniquekey = $onefeature->{'uniquekey'}; 304 my $modulegid = $onefeature->{'gid'}; 305 306 $directaccess{$uniquekey} = $i; 307 308 $directgid{$uniquekey} = $onefeature->{'gid'}; 309 310 # ParentID and Sortkey are not saved for the 'uniquekey', but only for the 'gid' 311 312 if ( $onefeature->{'ParentID'} ) { $directparent{$modulegid} = $onefeature->{'ParentID'}; } 313 else { $directparent{$modulegid} = ""; } 314 315 if ( $onefeature->{'Sortkey'} ) { $directsortkey{$modulegid} = $onefeature->{'Sortkey'}; } 316 else { $directsortkey{$modulegid} = "9999"; } 317 318 # Bookkeeping: 319 $sorted{$uniquekey} = 0; 320 } 321 322 # Searching all feature recursively, beginning with ParentID = "" 323 my $parentid = ""; 324 collect_modules_recursive($modulesref, $parentid, \@feature, \%directaccess, \%directgid, \%directparent, \%directsortkey, \%sorted); 325 326 # Bookkeeping 327 my $modulekey; 328 foreach $modulekey ( keys %sorted ) 329 { 330 if ( $sorted{$modulekey} == 0 ) 331 { 332 $installer::logger::Lang->printf( 333 "Warning: Module \"%s\" could not be sorted. Added to the end of the module array.\n", 334 $modulekey); 335 push(@feature, ${$modulesref}[$directaccess{$modulekey}]); 336 } 337 } 338 339 return \@feature; 340} 341 342################################################################################# 343# Adding a unique key to the modules array. The gid is not unique for 344# multilingual modules. Only the combination from gid and specific language 345# is unique. Uniqueness is required for sorting mechanism. 346################################################################################# 347 348sub add_uniquekey 349{ 350 my ( $modulesref ) = @_; 351 352 for ( my $i = 0; $i <= $#{$modulesref}; $i++ ) 353 { 354 my $uniquekey = ${$modulesref}[$i]->{'gid'}; 355 if ( ${$modulesref}[$i]->{'specificlanguage'} ) { $uniquekey = $uniquekey . "_" . ${$modulesref}[$i]->{'specificlanguage'}; } 356 ${$modulesref}[$i]->{'uniquekey'} = $uniquekey; 357 } 358} 359 360################################################################################# 361# Creating the file Feature.idt dynamically 362# Content: 363# Feature Feature_Parent Title Description Display Level Directory_ Attributes 364################################################################################# 365 366sub create_feature_table 367{ 368 my ($modulesref, $basedir, $languagesarrayref, $allvariableshashref) = @_; 369 370 for ( my $m = 0; $m <= $#{$languagesarrayref}; $m++ ) 371 { 372 my $onelanguage = ${$languagesarrayref}[$m]; 373 374 my $infoline; 375 376 my @featuretable = (); 377 378 installer::windows::idtglobal::write_idt_header(\@featuretable, "feature"); 379 380 for ( my $i = 0; $i <= $#{$modulesref}; $i++ ) 381 { 382 my $onefeature = ${$modulesref}[$i]; 383 384 # Java and Ada only, if the correct settings are set 385 my $styles = ""; 386 if ( $onefeature->{'Styles'} ) { $styles = $onefeature->{'Styles'}; } 387 if (( $styles =~ /\bJAVAMODULE\b/ ) && ( ! ($allvariableshashref->{'JAVAPRODUCT'} ))) { next; } 388 if (( $styles =~ /\bADAMODULE\b/ ) && ( ! ($allvariableshashref->{'ADAPRODUCT'} ))) { next; } 389 390 # Controlling the language! 391 # Only language independent feature or feature with the correct language will be included into the table 392 393 if (! (!(( $onefeature->{'ismultilingual'} )) || ( $onefeature->{'specificlanguage'} eq $onelanguage )) ) { next; } 394 395 my %feature = (); 396 397 $feature{'feature'} = get_feature_gid($onefeature); 398 $feature{'feature_parent'} = get_feature_parent($onefeature); 399 # if ( $onefeature->{'ParentID'} eq "" ) { $feature{'feature_parent'} = ""; } # Root has no parent 400 $feature{'Title'} = $onefeature->{'Name'}; 401 $feature{'Description'} = $onefeature->{'Description'}; 402 $feature{'Display'} = get_feature_display($onefeature); 403 $feature{'Level'} = get_feature_level($onefeature); 404 $feature{'Directory_'} = get_feature_directory($onefeature); 405 $feature{'Attributes'} = get_feature_attributes($onefeature); 406 407 my $oneline = $feature{'feature'} . "\t" . $feature{'feature_parent'} . "\t" . $feature{'Title'} . "\t" 408 . $feature{'Description'} . "\t" . $feature{'Display'} . "\t" . $feature{'Level'} . "\t" 409 . $feature{'Directory_'} . "\t" . $feature{'Attributes'} . "\n"; 410 411 push(@featuretable, $oneline); 412 413 # collecting all feature in global feature collector (so that properties can be set in property table) 414 if ( ! installer::existence::exists_in_array($feature{'feature'}, \@installer::globals::featurecollector) ) 415 { 416 push(@installer::globals::featurecollector, $feature{'feature'}); 417 } 418 419 # collecting all language feature in feature collector for check of language selection 420 if (( $styles =~ /\bSHOW_MULTILINGUAL_ONLY\b/ ) && ( $onefeature->{'ParentID'} ne $installer::globals::rootmodulegid )) 421 { 422 $installer::globals::multilingual_only_modules{$feature{'feature'}} = 1; 423 } 424 425 # collecting all application feature in global feature collector for check of application selection 426 if ( $styles =~ /\bAPPLICATIONMODULE\b/ ) 427 { 428 $installer::globals::application_modules{$feature{'feature'}} = 1; 429 } 430 } 431 432 # Saving the file 433 434 my $featuretablename = $basedir . $installer::globals::separator . "Feature.idt" . "." . $onelanguage; 435 installer::files::save_file($featuretablename ,\@featuretable); 436 $installer::logger::Lang->printf("Created idt file: %s\n", $featuretablename); 437 } 438} 439 4401; 441