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