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
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_chartcontroller.hxx"
26 #include "CharacterPropertyItemConverter.hxx"
27 #include "SchWhichPairs.hxx"
28 #include "macros.hxx"
29 #include "ItemPropertyMap.hxx"
30 #include "RelativeSizeHelper.hxx"
31 #include <editeng/memberids.hrc>
32 #include <editeng/eeitem.hxx>
33 #include <editeng/udlnitem.hxx>
34 #include <editeng/fontitem.hxx>
35 #include <editeng/crsditem.hxx>
36 #include <editeng/postitem.hxx>
37 #include <editeng/wghtitem.hxx>
38 #include <editeng/fhgtitem.hxx>
39 #include <svl/stritem.hxx>
40
41 #include <com/sun/star/beans/XPropertyState.hpp>
42 #include <com/sun/star/chart2/XFormattedString.hpp>
43
44 using namespace ::com::sun::star;
45
46 namespace
47 {
lcl_GetCharacterPropertyPropertyMap()48 ::comphelper::ItemPropertyMapType & lcl_GetCharacterPropertyPropertyMap()
49 {
50 static ::comphelper::ItemPropertyMapType aCharacterPropertyMap(
51 ::comphelper::MakeItemPropertyMap
52 IPM_MAP_ENTRY( EE_CHAR_COLOR, "CharColor", 0 )
53 IPM_MAP_ENTRY( EE_CHAR_LANGUAGE, "CharLocale", MID_LANG_LOCALE )
54 IPM_MAP_ENTRY( EE_CHAR_LANGUAGE_CJK, "CharLocaleAsian", MID_LANG_LOCALE )
55 IPM_MAP_ENTRY( EE_CHAR_LANGUAGE_CTL, "CharLocaleComplex", MID_LANG_LOCALE )
56 // IPM_MAP_ENTRY( EE_CHAR_FONTHEIGHT, "CharHeight", 0 )
57 // IPM_MAP_ENTRY( EE_CHAR_ITALIC, "CharPosture", 0 )
58 // IPM_MAP_ENTRY( EE_CHAR_WEIGHT, "CharWeight", 0 )
59
60 IPM_MAP_ENTRY( EE_CHAR_STRIKEOUT, "CharStrikeout", MID_CROSS_OUT )
61 IPM_MAP_ENTRY( EE_CHAR_WLM, "CharWordMode", 0 )
62 IPM_MAP_ENTRY( EE_CHAR_SHADOW, "CharShadowed", 0 )
63 IPM_MAP_ENTRY( EE_CHAR_RELIEF, "CharRelief", 0 )
64 IPM_MAP_ENTRY( EE_CHAR_OUTLINE, "CharContoured", 0 )
65 IPM_MAP_ENTRY( EE_CHAR_EMPHASISMARK, "CharEmphasis", 0 )
66
67 IPM_MAP_ENTRY( EE_PARA_WRITINGDIR, "WritingMode", 0 )
68
69 // IPM_MAP_ENTRY( EE_CHAR_FONTHEIGHT_CJK, "CharHeightAsian", 0 )
70 // IPM_MAP_ENTRY( EE_CHAR_FONTHEIGHT_CTL, "CharHeightComplex", 0 )
71 // IPM_MAP_ENTRY( EE_CHAR_WEIGHT_CJK, "CharWeightAsian", 0 )
72 // IPM_MAP_ENTRY( EE_CHAR_WEIGHT_CTL, "CharWeightComplex", 0 )
73 // IPM_MAP_ENTRY( EE_CHAR_ITALIC_CJK, "CharPostureAsian", 0 )
74 // IPM_MAP_ENTRY( EE_CHAR_ITALIC_CTL, "CharPostureComplex", 0 )
75 IPM_MAP_ENTRY( EE_PARA_ASIANCJKSPACING, "ParaIsCharacterDistance", 0 )
76 );
77
78 return aCharacterPropertyMap;
79 }
80 } // anonymous namespace
81
82 // ========================================
83
84 namespace chart
85 {
86 namespace wrapper
87 {
88
CharacterPropertyItemConverter(const uno::Reference<beans::XPropertySet> & rPropertySet,SfxItemPool & rItemPool)89 CharacterPropertyItemConverter::CharacterPropertyItemConverter(
90 const uno::Reference< beans::XPropertySet > & rPropertySet,
91 SfxItemPool& rItemPool ) :
92 ItemConverter( rPropertySet, rItemPool )
93 {}
94
CharacterPropertyItemConverter(const uno::Reference<beans::XPropertySet> & rPropertySet,SfxItemPool & rItemPool,::std::auto_ptr<awt::Size> pRefSize,const::rtl::OUString & rRefSizePropertyName,const uno::Reference<beans::XPropertySet> & rRefSizePropSet)95 CharacterPropertyItemConverter::CharacterPropertyItemConverter(
96 const uno::Reference< beans::XPropertySet > & rPropertySet,
97 SfxItemPool& rItemPool,
98 ::std::auto_ptr< awt::Size > pRefSize,
99 const ::rtl::OUString & rRefSizePropertyName,
100 const uno::Reference< beans::XPropertySet > & rRefSizePropSet ) :
101 ItemConverter( rPropertySet, rItemPool ),
102 m_pRefSize( pRefSize ),
103 m_aRefSizePropertyName( rRefSizePropertyName ),
104 m_xRefSizePropSet( rRefSizePropSet.is() ? rRefSizePropSet : rPropertySet )
105 {}
106
~CharacterPropertyItemConverter()107 CharacterPropertyItemConverter::~CharacterPropertyItemConverter()
108 {}
109
GetWhichPairs() const110 const sal_uInt16 * CharacterPropertyItemConverter::GetWhichPairs() const
111 {
112 return nCharacterPropertyWhichPairs;
113 }
114
GetItemProperty(tWhichIdType nWhichId,tPropertyNameWithMemberId & rOutProperty) const115 bool CharacterPropertyItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const
116 {
117 ::comphelper::ItemPropertyMapType & rMap( lcl_GetCharacterPropertyPropertyMap());
118 ::comphelper::ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId ));
119
120 if( aIt == rMap.end())
121 return false;
122
123 rOutProperty =(*aIt).second;
124 return true;
125 }
126
FillSpecialItem(sal_uInt16 nWhichId,SfxItemSet & rOutItemSet) const127 void CharacterPropertyItemConverter::FillSpecialItem(
128 sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const
129 {
130 switch( nWhichId )
131 {
132 case EE_CHAR_FONTINFO:
133 case EE_CHAR_FONTINFO_CJK:
134 case EE_CHAR_FONTINFO_CTL:
135 {
136 ::rtl::OUString aPostfix;
137 if( nWhichId == EE_CHAR_FONTINFO_CJK )
138 aPostfix = C2U( "Asian" );
139 else if( nWhichId == EE_CHAR_FONTINFO_CTL )
140 aPostfix = C2U( "Complex" );
141
142 SvxFontItem aItem( nWhichId );
143
144 aItem.PutValue( GetPropertySet()->getPropertyValue( C2U( "CharFontName" ) + aPostfix),
145 MID_FONT_FAMILY_NAME );
146 aItem.PutValue( GetPropertySet()->getPropertyValue( C2U( "CharFontFamily" ) + aPostfix),
147 MID_FONT_FAMILY );
148 aItem.PutValue( GetPropertySet()->getPropertyValue( C2U( "CharFontStyleName" ) + aPostfix),
149 MID_FONT_STYLE_NAME );
150 aItem.PutValue( GetPropertySet()->getPropertyValue( C2U( "CharFontCharSet" ) + aPostfix),
151 MID_FONT_CHAR_SET );
152 aItem.PutValue( GetPropertySet()->getPropertyValue( C2U( "CharFontPitch" ) + aPostfix),
153 MID_FONT_PITCH );
154
155 rOutItemSet.Put( aItem );
156 }
157 break;
158
159 case EE_CHAR_UNDERLINE:
160 {
161 SvxUnderlineItem aItem(UNDERLINE_NONE, EE_CHAR_UNDERLINE);
162 bool bModified = false;
163
164 uno::Any aValue( GetPropertySet()->getPropertyValue( C2U( "CharUnderline" )));
165 if( aValue.hasValue())
166 {
167 aItem.PutValue( aValue, MID_TL_STYLE );
168 bModified = true;
169 }
170
171 aValue = GetPropertySet()->getPropertyValue( C2U( "CharUnderlineHasColor" ));
172 if( aValue.hasValue() &&
173 ( *reinterpret_cast< const sal_Bool * >( aValue.getValue()) != sal_False ))
174 {
175 aItem.PutValue( aValue, MID_TL_HASCOLOR );
176 bModified = true;
177 }
178
179 aValue = GetPropertySet()->getPropertyValue( C2U( "CharUnderlineColor" ));
180 if( aValue.hasValue())
181 {
182 aItem.PutValue( aValue, MID_TL_COLOR );
183 bModified = true;
184 }
185
186 if( bModified )
187 rOutItemSet.Put( aItem );
188 }
189 break;
190
191 case EE_CHAR_OVERLINE:
192 {
193 SvxOverlineItem aItem( UNDERLINE_NONE, EE_CHAR_OVERLINE );
194 bool bModified = false;
195
196 uno::Any aValue( GetPropertySet()->getPropertyValue( C2U( "CharOverline" ) ) );
197 if ( aValue.hasValue() )
198 {
199 aItem.PutValue( aValue, MID_TL_STYLE );
200 bModified = true;
201 }
202
203 aValue = GetPropertySet()->getPropertyValue( C2U( "CharOverlineHasColor" ) );
204 if ( aValue.hasValue() &&
205 ( *reinterpret_cast< const sal_Bool* >( aValue.getValue() ) != sal_False ) )
206 {
207 aItem.PutValue( aValue, MID_TL_HASCOLOR );
208 bModified = true;
209 }
210
211 aValue = GetPropertySet()->getPropertyValue( C2U( "CharOverlineColor" ) );
212 if ( aValue.hasValue() )
213 {
214 aItem.PutValue( aValue, MID_TL_COLOR );
215 bModified = true;
216 }
217
218 if ( bModified )
219 {
220 rOutItemSet.Put( aItem );
221 }
222 }
223 break;
224
225 case EE_CHAR_ITALIC:
226 case EE_CHAR_ITALIC_CJK:
227 case EE_CHAR_ITALIC_CTL:
228 {
229 ::rtl::OUString aPostfix;
230 if( nWhichId == EE_CHAR_ITALIC_CJK )
231 aPostfix = C2U( "Asian" );
232 else if( nWhichId == EE_CHAR_ITALIC_CTL )
233 aPostfix = C2U( "Complex" );
234
235 SvxPostureItem aItem( ITALIC_NONE, nWhichId );
236
237 uno::Any aValue( GetPropertySet()->getPropertyValue( C2U( "CharPosture" ) + aPostfix));
238 if( aValue.hasValue())
239 {
240 aItem.PutValue( aValue, MID_POSTURE );
241 rOutItemSet.Put( aItem );
242 }
243 }
244 break;
245
246 case EE_CHAR_WEIGHT:
247 case EE_CHAR_WEIGHT_CJK:
248 case EE_CHAR_WEIGHT_CTL:
249 {
250 ::rtl::OUString aPostfix;
251 if( nWhichId == EE_CHAR_WEIGHT_CJK )
252 aPostfix = C2U( "Asian" );
253 else if( nWhichId == EE_CHAR_WEIGHT_CTL )
254 aPostfix = C2U( "Complex" );
255
256 SvxWeightItem aItem( WEIGHT_NORMAL, nWhichId );
257
258 uno::Any aValue( GetPropertySet()->getPropertyValue( C2U( "CharWeight" ) + aPostfix));
259 if( aValue.hasValue())
260 {
261 aItem.PutValue( aValue, MID_WEIGHT );
262 rOutItemSet.Put( aItem );
263 }
264 }
265 break;
266
267 case EE_CHAR_FONTHEIGHT:
268 case EE_CHAR_FONTHEIGHT_CJK:
269 case EE_CHAR_FONTHEIGHT_CTL:
270 {
271 ::rtl::OUString aPostfix;
272 if( nWhichId == EE_CHAR_FONTHEIGHT_CJK )
273 aPostfix = C2U( "Asian" );
274 else if( nWhichId == EE_CHAR_FONTHEIGHT_CTL )
275 aPostfix = C2U( "Complex" );
276
277 SvxFontHeightItem aItem( 240, 100, nWhichId );
278
279 try
280 {
281 uno::Any aValue( GetPropertySet()->getPropertyValue( C2U( "CharHeight" ) + aPostfix ));
282 float fHeight;
283 if( aValue >>= fHeight )
284 {
285 if( m_pRefSize.get())
286 {
287 awt::Size aOldRefSize;
288 if( GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ) >>= aOldRefSize )
289 {
290 // calculate font height in view
291 fHeight = static_cast< float >(
292 RelativeSizeHelper::calculate( fHeight, aOldRefSize, *m_pRefSize ));
293 aValue <<= fHeight;
294 }
295 }
296
297 aItem.PutValue( aValue, MID_FONTHEIGHT );
298 rOutItemSet.Put( aItem );
299 }
300 }
301 catch( uno::Exception & ex )
302 {
303 ASSERT_EXCEPTION( ex );
304 }
305 }
306 break;
307
308 case SID_CHAR_DLG_PREVIEW_STRING:
309 {
310 uno::Reference< chart2::XFormattedString > xFormattedString( GetPropertySet(), uno::UNO_QUERY );
311 if( xFormattedString.is() )
312 {
313 ::rtl::OUString aString = xFormattedString->getString();
314 rOutItemSet.Put( SfxStringItem( nWhichId, aString ) );
315 }
316 else
317 rOutItemSet.Put( SfxStringItem( nWhichId, C2U( "" ) ) );
318 }
319 break;
320
321 case EE_PARA_FORBIDDENRULES:
322 case EE_PARA_HANGINGPUNCTUATION:
323 rOutItemSet.DisableItem( nWhichId );
324 break;
325 }
326 }
327
ApplySpecialItem(sal_uInt16 nWhichId,const SfxItemSet & rItemSet)328 bool CharacterPropertyItemConverter::ApplySpecialItem(
329 sal_uInt16 nWhichId, const SfxItemSet & rItemSet )
330 {
331 bool bChanged = false;
332 uno::Any aValue;
333
334 switch( nWhichId )
335 {
336 case EE_CHAR_FONTINFO:
337 case EE_CHAR_FONTINFO_CJK:
338 case EE_CHAR_FONTINFO_CTL:
339 {
340 ::rtl::OUString aPostfix;
341 if( nWhichId == EE_CHAR_FONTINFO_CJK )
342 aPostfix = C2U( "Asian" );
343 else if( nWhichId == EE_CHAR_FONTINFO_CTL )
344 aPostfix = C2U( "Complex" );
345
346 const SvxFontItem & rItem =
347 static_cast< const SvxFontItem & >(
348 rItemSet.Get( nWhichId ));
349
350 if( rItem.QueryValue( aValue, MID_FONT_FAMILY_NAME ))
351 {
352 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharFontName" ) + aPostfix ))
353 {
354 GetPropertySet()->setPropertyValue( C2U( "CharFontName" ) + aPostfix, aValue );
355 bChanged = true;
356 }
357 }
358 if( rItem.QueryValue( aValue, MID_FONT_FAMILY ))
359 {
360 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharFontFamily" ) + aPostfix ))
361 {
362 GetPropertySet()->setPropertyValue( C2U( "CharFontFamily" ) + aPostfix, aValue );
363 bChanged = true;
364 }
365 }
366 if( rItem.QueryValue( aValue, MID_FONT_STYLE_NAME ))
367 {
368 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharFontStyleName" ) + aPostfix ))
369 {
370 GetPropertySet()->setPropertyValue( C2U( "CharFontStyleName" ) + aPostfix, aValue );
371 bChanged = true;
372 }
373 }
374 if( rItem.QueryValue( aValue, MID_FONT_CHAR_SET ))
375 {
376 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharFontCharSet" ) + aPostfix ))
377 {
378 GetPropertySet()->setPropertyValue( C2U( "CharFontCharSet" ) + aPostfix, aValue );
379 bChanged = true;
380 }
381 }
382 if( rItem.QueryValue( aValue, MID_FONT_PITCH ))
383 {
384 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharFontPitch" ) + aPostfix ))
385 {
386 GetPropertySet()->setPropertyValue( C2U( "CharFontPitch" ) + aPostfix, aValue );
387 bChanged = true;
388 }
389 }
390 }
391 break;
392
393 case EE_CHAR_UNDERLINE:
394 {
395 const SvxUnderlineItem & rItem =
396 static_cast< const SvxUnderlineItem & >(
397 rItemSet.Get( nWhichId ));
398
399 if( rItem.QueryValue( aValue, MID_TL_STYLE ))
400 {
401 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharUnderline" ) ))
402 {
403 GetPropertySet()->setPropertyValue( C2U( "CharUnderline" ), aValue );
404 bChanged = true;
405 }
406 }
407
408 if( rItem.QueryValue( aValue, MID_TL_COLOR ))
409 {
410 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharUnderlineColor" ) ))
411 {
412 GetPropertySet()->setPropertyValue( C2U( "CharUnderlineColor" ), aValue );
413 bChanged = true;
414 }
415 }
416
417 if( rItem.QueryValue( aValue, MID_TL_HASCOLOR ))
418 {
419 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharUnderlineHasColor" ) ))
420 {
421 GetPropertySet()->setPropertyValue( C2U( "CharUnderlineHasColor" ), aValue );
422 bChanged = true;
423 }
424 }
425 }
426 break;
427
428 case EE_CHAR_OVERLINE:
429 {
430 const SvxOverlineItem& rItem = static_cast< const SvxOverlineItem & >( rItemSet.Get( nWhichId ) );
431
432 if ( rItem.QueryValue( aValue, MID_TL_STYLE ) )
433 {
434 if ( aValue != GetPropertySet()->getPropertyValue( C2U( "CharOverline" ) ) )
435 {
436 GetPropertySet()->setPropertyValue( C2U( "CharOverline" ), aValue );
437 bChanged = true;
438 }
439 }
440
441 if ( rItem.QueryValue( aValue, MID_TL_COLOR ) )
442 {
443 if ( aValue != GetPropertySet()->getPropertyValue( C2U( "CharOverlineColor" ) ) )
444 {
445 GetPropertySet()->setPropertyValue( C2U( "CharOverlineColor" ), aValue );
446 bChanged = true;
447 }
448 }
449
450 if ( rItem.QueryValue( aValue, MID_TL_HASCOLOR ) )
451 {
452 if ( aValue != GetPropertySet()->getPropertyValue( C2U( "CharOverlineHasColor" ) ) )
453 {
454 GetPropertySet()->setPropertyValue( C2U( "CharOverlineHasColor" ), aValue );
455 bChanged = true;
456 }
457 }
458 }
459 break;
460
461 case EE_CHAR_ITALIC:
462 case EE_CHAR_ITALIC_CJK:
463 case EE_CHAR_ITALIC_CTL:
464 {
465 ::rtl::OUString aPostfix;
466 if( nWhichId == EE_CHAR_ITALIC_CJK )
467 aPostfix = C2U( "Asian" );
468 else if( nWhichId == EE_CHAR_ITALIC_CTL )
469 aPostfix = C2U( "Complex" );
470
471 const SvxPostureItem & rItem =
472 static_cast< const SvxPostureItem & >(
473 rItemSet.Get( nWhichId ));
474
475 if( rItem.QueryValue( aValue, MID_POSTURE ))
476 {
477 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharPosture" ) + aPostfix))
478 {
479 GetPropertySet()->setPropertyValue( C2U( "CharPosture" ) + aPostfix, aValue );
480 bChanged = true;
481 }
482 }
483 }
484 break;
485
486 case EE_CHAR_WEIGHT:
487 case EE_CHAR_WEIGHT_CJK:
488 case EE_CHAR_WEIGHT_CTL:
489 {
490 ::rtl::OUString aPostfix;
491 if( nWhichId == EE_CHAR_WEIGHT_CJK )
492 aPostfix = C2U( "Asian" );
493 else if( nWhichId == EE_CHAR_WEIGHT_CTL )
494 aPostfix = C2U( "Complex" );
495
496 const SvxWeightItem & rItem =
497 static_cast< const SvxWeightItem & >(
498 rItemSet.Get( nWhichId ));
499
500 if( rItem.QueryValue( aValue, MID_WEIGHT ))
501 {
502 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharWeight" ) + aPostfix))
503 {
504 GetPropertySet()->setPropertyValue( C2U( "CharWeight" ) + aPostfix, aValue );
505 bChanged = true;
506 }
507 }
508 }
509 break;
510
511 case EE_CHAR_FONTHEIGHT:
512 case EE_CHAR_FONTHEIGHT_CJK:
513 case EE_CHAR_FONTHEIGHT_CTL:
514 {
515 ::rtl::OUString aPostfix;
516 if( nWhichId == EE_CHAR_FONTHEIGHT_CJK )
517 aPostfix = C2U( "Asian" );
518 else if( nWhichId == EE_CHAR_FONTHEIGHT_CTL )
519 aPostfix = C2U( "Complex" );
520
521 const SvxFontHeightItem & rItem =
522 static_cast< const SvxFontHeightItem & >(
523 rItemSet.Get( nWhichId ));
524
525 try
526 {
527 if( rItem.QueryValue( aValue, MID_FONTHEIGHT ) )
528 {
529 bool bSetValue = false;
530 if( aValue != GetPropertySet()->getPropertyValue( C2U( "CharHeight" ) + aPostfix ))
531 bSetValue = true;
532 else
533 {
534 if( m_pRefSize.get() )
535 {
536 awt::Size aNewRefSize = *m_pRefSize;
537 awt::Size aOldRefSize;
538 if( GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ) >>= aOldRefSize )
539 {
540 if( aNewRefSize.Width != aOldRefSize.Width
541 || aNewRefSize.Height != aOldRefSize.Height )
542 bSetValue = true;
543 }
544 }
545 }
546 if( bSetValue )
547 {
548 // set new reference size only if there was a reference size before (auto-scaling on)
549 if( m_pRefSize.get() &&
550 GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ).hasValue())
551 {
552 GetRefSizePropertySet()->setPropertyValue( m_aRefSizePropertyName,
553 uno::makeAny( *m_pRefSize ));
554 }
555
556 GetPropertySet()->setPropertyValue( C2U( "CharHeight" ) + aPostfix, aValue );
557 bChanged = true;
558 }
559 }
560 }
561 catch( uno::Exception & ex )
562 {
563 ASSERT_EXCEPTION( ex );
564 }
565 }
566 break;
567 }
568
569 return bChanged;
570 }
571
572 uno::Reference< beans::XPropertySet >
GetRefSizePropertySet() const573 CharacterPropertyItemConverter::GetRefSizePropertySet() const
574 {
575 return m_xRefSizePropSet;
576 }
577
578 } // namespace wrapper
579 } // namespace chart
580