Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "PropertyMapper.hxx"
21 : #include "ContainerHelper.hxx"
22 : #include "macros.hxx"
23 :
24 : #include <com/sun/star/beans/XMultiPropertySet.hpp>
25 : #include <com/sun/star/drawing/LineStyle.hpp>
26 : #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
27 : #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
28 : #include <com/sun/star/drawing/LineJoint.hpp>
29 :
30 : //.............................................................................
31 : namespace chart
32 : {
33 : //.............................................................................
34 : using namespace ::com::sun::star;
35 :
36 : namespace
37 : {
38 :
39 104 : void lcl_overwriteOrAppendValues(
40 : tPropertyNameValueMap &rMap, const tPropertyNameValueMap& rOverwriteMap )
41 : {
42 104 : tPropertyNameValueMap::const_iterator aIt( rOverwriteMap.begin() );
43 104 : tPropertyNameValueMap::const_iterator aEnd( rOverwriteMap.end() );
44 :
45 208 : for( ; aIt != aEnd; ++aIt )
46 104 : rMap[ aIt->first ] = aIt->second;
47 104 : }
48 :
49 : } // anonymous namespace
50 :
51 7622 : void PropertyMapper::setMappedProperties(
52 : const uno::Reference< beans::XPropertySet >& xTarget
53 : , const uno::Reference< beans::XPropertySet >& xSource
54 : , const tPropertyNameMap& rMap
55 : , tPropertyNameValueMap* pOverwriteMap )
56 : {
57 7622 : if( !xTarget.is() || !xSource.is() )
58 7622 : return;
59 :
60 7622 : tNameSequence aNames;
61 15244 : tAnySequence aValues;
62 7622 : getMultiPropertyLists(aNames, aValues, xSource, rMap );
63 7622 : if(pOverwriteMap && (aNames.getLength() == aValues.getLength()))
64 : {
65 104 : tPropertyNameValueMap aNewMap;
66 1872 : for( sal_Int32 nI=0; nI<aNames.getLength(); ++nI )
67 1768 : aNewMap[ aNames[nI] ] = aValues[nI];
68 104 : lcl_overwriteOrAppendValues( aNewMap, *pOverwriteMap );
69 104 : aNames = ContainerHelper::MapKeysToSequence( aNewMap );
70 104 : aValues = ContainerHelper::MapValuesToSequence( aNewMap );
71 : }
72 :
73 15244 : PropertyMapper::setMultiProperties( aNames, aValues, xTarget );
74 : }
75 :
76 13477 : void PropertyMapper::getValueMap(
77 : tPropertyNameValueMap& rValueMap
78 : , const tPropertyNameMap& rNameMap
79 : , const uno::Reference< beans::XPropertySet >& xSourceProp
80 : )
81 : {
82 13477 : tPropertyNameMap::const_iterator aIt( rNameMap.begin() );
83 13477 : tPropertyNameMap::const_iterator aEnd( rNameMap.end() );
84 :
85 381287 : for( ; aIt != aEnd; ++aIt )
86 : {
87 367810 : OUString aTarget = aIt->first;
88 735620 : OUString aSource = aIt->second;
89 : try
90 : {
91 367810 : uno::Any aAny( xSourceProp->getPropertyValue(aSource) );
92 367810 : if( aAny.hasValue() )
93 312596 : rValueMap.insert( tPropertyNameValueMap::value_type( aTarget, aAny ) );
94 : }
95 0 : catch( const uno::Exception& e )
96 : {
97 : ASSERT_EXCEPTION( e );
98 : }
99 367810 : }
100 13477 : }
101 :
102 7622 : void PropertyMapper::getMultiPropertyLists(
103 : tNameSequence& rNames
104 : , tAnySequence& rValues
105 : , const uno::Reference< beans::XPropertySet >& xSourceProp
106 : , const tPropertyNameMap& rNameMap
107 : )
108 : {
109 7622 : tPropertyNameValueMap aValueMap;
110 7622 : getValueMap( aValueMap, rNameMap, xSourceProp );
111 7622 : getMultiPropertyListsFromValueMap( rNames, rValues, aValueMap );
112 7622 : }
113 :
114 13477 : void PropertyMapper::getMultiPropertyListsFromValueMap(
115 : tNameSequence& rNames
116 : , tAnySequence& rValues
117 : , const tPropertyNameValueMap& rValueMap
118 : )
119 : {
120 13477 : sal_Int32 nPropertyCount = rValueMap.size();
121 13477 : rNames.realloc(nPropertyCount);
122 13477 : rValues.realloc(nPropertyCount);
123 :
124 : //fill sequences
125 13477 : tPropertyNameValueMap::const_iterator aValueIt( rValueMap.begin() );
126 13477 : tPropertyNameValueMap::const_iterator aValueEnd( rValueMap.end() );
127 13477 : sal_Int32 nN=0;
128 341589 : for( ; aValueIt != aValueEnd; ++aValueIt )
129 : {
130 328112 : const uno::Any& rAny = aValueIt->second;
131 328112 : if( rAny.hasValue() )
132 : {
133 : //do not set empty anys because of performance (otherwise SdrAttrObj::ItemChange will take much longer)
134 328112 : rNames[nN] = aValueIt->first;
135 328112 : rValues[nN] = rAny;
136 328112 : ++nN;
137 : }
138 : }
139 : //reduce to real property count
140 13477 : rNames.realloc(nN);
141 13477 : rValues.realloc(nN);
142 13477 : }
143 :
144 11614 : uno::Any* PropertyMapper::getValuePointer( tAnySequence& rPropValues
145 : , const tNameSequence& rPropNames
146 : , const OUString& rPropName )
147 : {
148 11614 : sal_Int32 nCount = rPropNames.getLength();
149 408314 : for( sal_Int32 nN = 0; nN < nCount; nN++ )
150 : {
151 406469 : if(rPropNames[nN].equals(rPropName))
152 9769 : return &rPropValues[nN];
153 : }
154 1845 : return NULL;
155 : }
156 :
157 1890 : uno::Any* PropertyMapper::getValuePointerForLimitedSpace( tAnySequence& rPropValues
158 : , const tNameSequence& rPropNames
159 : , bool bLimitedHeight)
160 : {
161 : return PropertyMapper::getValuePointer( rPropValues, rPropNames
162 1890 : , bLimitedHeight ? OUString("TextMaximumFrameHeight") : OUString("TextMaximumFrameWidth") );
163 : }
164 :
165 3038 : const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForCharacterProperties()
166 : {
167 : //shape property -- chart model object property
168 : static tMakePropertyNameMap m_aShapePropertyMapForCharacterProperties =
169 : tMakePropertyNameMap
170 : ( "CharColor", "CharColor" )
171 18 : ( "CharContoured", "CharContoured" )
172 27 : ( "CharEmphasis", "CharEmphasis" )//the service style::CharacterProperties describes a property called 'CharEmphasize' which is nowhere implemented
173 :
174 27 : ( "CharFontFamily", "CharFontFamily" )
175 27 : ( "CharFontFamilyAsian", "CharFontFamilyAsian" )
176 27 : ( "CharFontFamilyComplex", "CharFontFamilyComplex" )
177 27 : ( "CharFontCharSet", "CharFontCharSet" )
178 27 : ( "CharFontCharSetAsian", "CharFontCharSetAsian" )
179 27 : ( "CharFontCharSetComplex", "CharFontCharSetComplex" )
180 27 : ( "CharFontName", "CharFontName" )
181 27 : ( "CharFontNameAsian", "CharFontNameAsian" )
182 27 : ( "CharFontNameComplex", "CharFontNameComplex" )
183 27 : ( "CharFontPitch", "CharFontPitch" )
184 27 : ( "CharFontPitchAsian", "CharFontPitchAsian" )
185 27 : ( "CharFontPitchComplex", "CharFontPitchComplex" )
186 27 : ( "CharFontStyleName", "CharFontStyleName" )
187 27 : ( "CharFontStyleNameAsian", "CharFontStyleNameAsian" )
188 27 : ( "CharFontStyleNameComplex", "CharFontStyleNameComplex" )
189 :
190 27 : ( "CharHeight", "CharHeight" )
191 27 : ( "CharHeightAsian", "CharHeightAsian" )
192 27 : ( "CharHeightComplex", "CharHeightComplex" )
193 27 : ( "CharKerning", "CharKerning" )
194 27 : ( "CharLocale", "CharLocale" )
195 27 : ( "CharLocaleAsian", "CharLocaleAsian" )
196 27 : ( "CharLocaleComplex", "CharLocaleComplex" )
197 27 : ( "CharPosture", "CharPosture" )
198 27 : ( "CharPostureAsian", "CharPostureAsian" )
199 27 : ( "CharPostureComplex", "CharPostureComplex" )
200 27 : ( "CharRelief", "CharRelief" )
201 27 : ( "CharShadowed", "CharShadowed" )
202 27 : ( "CharStrikeout", "CharStrikeout" )
203 27 : ( "CharUnderline", "CharUnderline" )
204 27 : ( "CharUnderlineColor", "CharUnderlineColor" )
205 27 : ( "CharUnderlineHasColor", "CharUnderlineHasColor" )
206 27 : ( "CharOverline", "CharOverline" )
207 27 : ( "CharOverlineColor", "CharOverlineColor" )
208 27 : ( "CharOverlineHasColor", "CharOverlineHasColor" )
209 27 : ( "CharWeight", "CharWeight" )
210 27 : ( "CharWeightAsian", "CharWeightAsian" )
211 27 : ( "CharWeightComplex", "CharWeightComplex" )
212 27 : ( "CharWordMode", "CharWordMode" )
213 :
214 27 : ( "WritingMode", "WritingMode" )
215 :
216 3056 : ( "ParaIsCharacterDistance", "ParaIsCharacterDistance" )
217 : ;
218 3038 : return m_aShapePropertyMapForCharacterProperties;
219 : }
220 :
221 445 : const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForParagraphProperties()
222 : {
223 : //shape property -- chart model object property
224 : static tMakePropertyNameMap m_aShapePropertyMapForParagraphProperties =
225 : tMakePropertyNameMap
226 : ( "ParaAdjust", "ParaAdjust" )
227 6 : ( "ParaBottomMargin", "ParaBottomMargin" )
228 9 : ( "ParaIsHyphenation", "ParaIsHyphenation" )
229 9 : ( "ParaLastLineAdjust", "ParaLastLineAdjust" )
230 9 : ( "ParaLeftMargin", "ParaLeftMargin" )
231 9 : ( "ParaRightMargin", "ParaRightMargin" )
232 451 : ( "ParaTopMargin", "ParaTopMargin" )
233 : ;
234 445 : return m_aShapePropertyMapForParagraphProperties;
235 : }
236 :
237 1735 : const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFillProperties()
238 : {
239 : //shape property -- chart model object property
240 : static tMakePropertyNameMap m_aShapePropertyMapForFillProperties =
241 : tMakePropertyNameMap
242 : ( "FillBackground", "FillBackground" )
243 18 : ( "FillBitmapName", "FillBitmapName" )
244 27 : ( "FillColor", "FillColor" )
245 27 : ( "FillGradientName", "FillGradientName" )
246 27 : ( "FillGradientStepCount", "FillGradientStepCount" )
247 27 : ( "FillHatchName", "FillHatchName" )
248 27 : ( "FillStyle", "FillStyle" )
249 27 : ( "FillTransparence", "FillTransparence" )
250 27 : ( "FillTransparenceGradientName", "FillTransparenceGradientName" )
251 : //bitmap properties
252 27 : ( "FillBitmapMode", "FillBitmapMode" )
253 27 : ( "FillBitmapSizeX", "FillBitmapSizeX" )
254 27 : ( "FillBitmapSizeY", "FillBitmapSizeY" )
255 27 : ( "FillBitmapLogicalSize", "FillBitmapLogicalSize" )
256 27 : ( "FillBitmapOffsetX", "FillBitmapOffsetX" )
257 27 : ( "FillBitmapOffsetY", "FillBitmapOffsetY" )
258 27 : ( "FillBitmapRectanglePoint", "FillBitmapRectanglePoint" )
259 27 : ( "FillBitmapPositionOffsetX", "FillBitmapPositionOffsetX" )
260 1753 : ( "FillBitmapPositionOffsetY", "FillBitmapPositionOffsetY" )
261 : ;
262 1735 : return m_aShapePropertyMapForFillProperties;
263 : }
264 :
265 1869 : const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForLineProperties()
266 : {
267 : //shape property -- chart model object property
268 : static tMakePropertyNameMap m_aShapePropertyMapForLineProperties =
269 : tMakePropertyNameMap
270 : ( "LineColor", "LineColor" )
271 18 : ( "LineDashName", "LineDashName" )
272 27 : ( "LineJoint", "LineJoint" )
273 27 : ( "LineStyle", "LineStyle" )
274 27 : ( "LineTransparence", "LineTransparence" )
275 1887 : ( "LineWidth", "LineWidth" )
276 : ;
277 1869 : return m_aShapePropertyMapForLineProperties;
278 : }
279 :
280 3815 : const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFillAndLineProperties()
281 : {
282 : static tMakePropertyNameMap m_aShapePropertyMapForFillAndLineProperties =
283 : tMakePropertyNameMap
284 9 : ( PropertyMapper::getPropertyNameMapForFillProperties() )
285 3824 : ( PropertyMapper::getPropertyNameMapForLineProperties() )
286 : ;
287 :
288 3815 : return m_aShapePropertyMapForFillAndLineProperties;
289 : }
290 :
291 0 : const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForTextShapeProperties()
292 : {
293 : static tMakePropertyNameMap m_aShapePropertyMapForTextShapeProperties =
294 : tMakePropertyNameMap
295 0 : ( PropertyMapper::getPropertyNameMapForCharacterProperties() )
296 0 : ( PropertyMapper::getPropertyNameMapForFillProperties() )
297 0 : ( PropertyMapper::getPropertyNameMapForLineProperties() );
298 :
299 0 : return m_aShapePropertyMapForTextShapeProperties;
300 : }
301 :
302 1898 : const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForLineSeriesProperties()
303 : {
304 : //shape property -- chart model object property
305 : static tMakePropertyNameMap m_aShapePropertyMapForLineSeriesProperties =
306 : tMakePropertyNameMap
307 : ( "LineColor", "Color" )
308 16 : ( "LineDashName", "LineDashName" )
309 24 : ( "LineStyle", "LineStyle" )
310 24 : ( "LineTransparence", "Transparency" )
311 1914 : ( "LineWidth", "LineWidth" )
312 :
313 : ;
314 1898 : return m_aShapePropertyMapForLineSeriesProperties;
315 : }
316 :
317 8044 : const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFilledSeriesProperties()
318 : {
319 : //shape property -- chart model object property
320 : static tMakePropertyNameMap m_aShapePropertyMapForFilledSeriesProperties =
321 : tMakePropertyNameMap
322 : ( "FillBackground", "FillBackground" )
323 16 : ( "FillBitmapName", "FillBitmapName" )
324 24 : ( "FillColor", "Color" )
325 24 : ( "FillGradientName", "GradientName" )
326 24 : ( "FillGradientStepCount", "GradientStepCount" )
327 24 : ( "FillHatchName", "HatchName" )
328 24 : ( "FillStyle", "FillStyle" )
329 24 : ( "FillTransparence", "Transparency" )
330 24 : ( "FillTransparenceGradientName", "TransparencyGradientName" )
331 : //bitmap properties
332 24 : ( "FillBitmapMode", "FillBitmapMode" )
333 24 : ( "FillBitmapSizeX", "FillBitmapSizeX" )
334 24 : ( "FillBitmapSizeY", "FillBitmapSizeY" )
335 24 : ( "FillBitmapLogicalSize", "FillBitmapLogicalSize" )
336 24 : ( "FillBitmapOffsetX", "FillBitmapOffsetX" )
337 24 : ( "FillBitmapOffsetY", "FillBitmapOffsetY" )
338 24 : ( "FillBitmapRectanglePoint", "FillBitmapRectanglePoint" )
339 24 : ( "FillBitmapPositionOffsetX", "FillBitmapPositionOffsetX" )
340 24 : ( "FillBitmapPositionOffsetY", "FillBitmapPositionOffsetY" )
341 : //line properties
342 24 : ( "LineColor", "BorderColor" )
343 24 : ( "LineDashName", "BorderDashName" )
344 24 : ( "LineStyle", "BorderStyle" )
345 24 : ( "LineTransparence", "BorderTransparency" )
346 8060 : ( "LineWidth", "BorderWidth" )
347 : ;
348 8044 : return m_aShapePropertyMapForFilledSeriesProperties;
349 : }
350 :
351 22291 : void PropertyMapper::setMultiProperties(
352 : const tNameSequence& rNames
353 : , const tAnySequence& rValues
354 : , const ::com::sun::star::uno::Reference<
355 : ::com::sun::star::beans::XPropertySet >& xTarget )
356 : {
357 22291 : bool bSuccess = false;
358 : try
359 : {
360 22291 : uno::Reference< beans::XMultiPropertySet > xShapeMultiProp( xTarget, uno::UNO_QUERY );
361 22291 : if( xShapeMultiProp.is() )
362 : {
363 22291 : xShapeMultiProp->setPropertyValues( rNames, rValues );
364 22291 : bSuccess = true;
365 22291 : }
366 : }
367 0 : catch( const uno::Exception& e )
368 : {
369 : ASSERT_EXCEPTION( e ); //if this occurs more often think of removing the XMultiPropertySet completely for better performance
370 : }
371 :
372 22291 : if(!bSuccess)
373 : try
374 : {
375 0 : sal_Int32 nCount = std::max( rNames.getLength(), rValues.getLength() );
376 0 : OUString aPropName;
377 0 : uno::Any aValue;
378 0 : for( sal_Int32 nN = 0; nN < nCount; nN++ )
379 : {
380 0 : aPropName = rNames[nN];
381 0 : aValue = rValues[nN];
382 :
383 : try
384 : {
385 0 : xTarget->setPropertyValue( aPropName, aValue );
386 : }
387 0 : catch( const uno::Exception& e )
388 : {
389 : ASSERT_EXCEPTION( e );
390 : }
391 0 : }
392 : }
393 0 : catch( const uno::Exception& e )
394 : {
395 : ASSERT_EXCEPTION( e );
396 : }
397 22291 : }
398 :
399 2075 : void PropertyMapper::getTextLabelMultiPropertyLists(
400 : const uno::Reference< beans::XPropertySet >& xSourceProp
401 : , tNameSequence& rPropNames, tAnySequence& rPropValues
402 : , bool bName
403 : , sal_Int32 nLimitedSpace
404 : , bool bLimitedHeight )
405 : {
406 : //fill character properties into the ValueMap
407 2075 : tPropertyNameValueMap aValueMap;
408 : PropertyMapper::getValueMap( aValueMap
409 2075 : , PropertyMapper::getPropertyNameMapForCharacterProperties()
410 2075 : , xSourceProp );
411 :
412 : //some more shape properties apart from character properties, position-matrix and label string
413 2075 : aValueMap.insert( tPropertyNameValueMap::value_type( "LineStyle", uno::makeAny(drawing::LineStyle_NONE) ) ); // drawing::LineStyle
414 2075 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextHorizontalAdjust", uno::makeAny(drawing::TextHorizontalAdjust_CENTER) ) ); // drawing::TextHorizontalAdjust - needs to be overwritten
415 2075 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextVerticalAdjust", uno::makeAny(drawing::TextVerticalAdjust_CENTER) ) ); //drawing::TextVerticalAdjust - needs to be overwritten
416 2075 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextAutoGrowHeight", uno::makeAny(sal_True) ) ); // sal_Bool
417 2075 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextAutoGrowWidth", uno::makeAny(sal_True) ) ); // sal_Bool
418 2075 : if( bName )
419 185 : aValueMap.insert( tPropertyNameValueMap::value_type( "Name", uno::makeAny( OUString() ) ) ); //CID OUString - needs to be overwritten for each point
420 :
421 2075 : if( nLimitedSpace > 0 )
422 : {
423 45 : if(bLimitedHeight)
424 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextMaximumFrameHeight", uno::makeAny(nLimitedSpace) ) ); //sal_Int32
425 : else
426 45 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextMaximumFrameWidth", uno::makeAny(nLimitedSpace) ) ); //sal_Int32
427 45 : aValueMap.insert( tPropertyNameValueMap::value_type( "ParaIsHyphenation", uno::makeAny(sal_True) ) );
428 : }
429 :
430 2075 : PropertyMapper::getMultiPropertyListsFromValueMap( rPropNames, rPropValues, aValueMap );
431 2075 : }
432 :
433 0 : void PropertyMapper::getPreparedTextShapePropertyLists(
434 : const uno::Reference< beans::XPropertySet >& xSourceProp
435 : , tNameSequence& rPropNames, tAnySequence& rPropValues )
436 : {
437 : //fill character, line and fill properties into the ValueMap
438 0 : tPropertyNameValueMap aValueMap;
439 : PropertyMapper::getValueMap( aValueMap
440 0 : , PropertyMapper::getPropertyNameMapForTextShapeProperties()
441 0 : , xSourceProp );
442 :
443 : // auto-grow makes sure the shape has the correct size after setting text
444 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextHorizontalAdjust", uno::makeAny( drawing::TextHorizontalAdjust_CENTER )));
445 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextVerticalAdjust", uno::makeAny( drawing::TextVerticalAdjust_CENTER )));
446 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextAutoGrowHeight", uno::makeAny( true )));
447 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextAutoGrowWidth", uno::makeAny( true )));
448 :
449 : // set some distance to the border, in case it is shown
450 0 : const sal_Int32 nWidthDist = 250;
451 0 : const sal_Int32 nHeightDist = 125;
452 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextLeftDistance", uno::makeAny( nWidthDist )));
453 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextRightDistance", uno::makeAny( nWidthDist )));
454 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextUpperDistance", uno::makeAny( nHeightDist )));
455 0 : aValueMap.insert( tPropertyNameValueMap::value_type( "TextLowerDistance", uno::makeAny( nHeightDist )));
456 :
457 : // use a line-joint showing the border of thick lines like two rectangles
458 : // filled in between.
459 0 : aValueMap["LineJoint"] <<= drawing::LineJoint_ROUND;
460 :
461 0 : PropertyMapper::getMultiPropertyListsFromValueMap( rPropNames, rPropValues, aValueMap );
462 0 : }
463 :
464 : //.............................................................................
465 : } //namespace chart
466 : //.............................................................................
467 :
468 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|