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
27 #include "WrappedScaleProperty.hxx"
28 #include "macros.hxx"
29 #include "CommonConverters.hxx"
30 #include "AxisHelper.hxx"
31 #include <com/sun/star/chart2/XAxis.hpp>
32 #include <com/sun/star/chart/ChartAxisType.hpp>
33 #include <chartview/ExplicitScaleValues.hxx>
34
35 using namespace ::com::sun::star;
36 using ::com::sun::star::uno::Any;
37 using namespace ::com::sun::star::chart2;
38 using ::com::sun::star::uno::Reference;
39 using ::com::sun::star::uno::Sequence;
40 using ::rtl::OUString;
41 using ::com::sun::star::chart::TimeIncrement;
42
43 //.............................................................................
44 namespace chart
45 {
46 namespace wrapper
47 {
48
WrappedScaleProperty(tScaleProperty eScaleProperty,::boost::shared_ptr<Chart2ModelContact> spChart2ModelContact)49 WrappedScaleProperty::WrappedScaleProperty( tScaleProperty eScaleProperty
50 , ::boost::shared_ptr< Chart2ModelContact > spChart2ModelContact )
51 : WrappedProperty(OUString(),OUString())
52 , m_spChart2ModelContact( spChart2ModelContact )
53 , m_eScaleProperty( eScaleProperty )
54 {
55 switch( m_eScaleProperty )
56 {
57 case SCALE_PROP_MAX:
58 m_aOuterName = C2U("Max");
59 break;
60 case SCALE_PROP_MIN:
61 m_aOuterName = C2U("Min");
62 break;
63 case SCALE_PROP_ORIGIN:
64 m_aOuterName = C2U("Origin");
65 break;
66 case SCALE_PROP_STEPMAIN:
67 m_aOuterName = C2U("StepMain");
68 break;
69 case SCALE_PROP_STEPHELP:
70 m_aOuterName = C2U("StepHelp");
71 break;
72 case SCALE_PROP_STEPHELP_COUNT:
73 m_aOuterName = C2U("StepHelpCount");
74 break;
75 case SCALE_PROP_AUTO_MAX:
76 m_aOuterName = C2U("AutoMax");
77 break;
78 case SCALE_PROP_AUTO_MIN:
79 m_aOuterName = C2U("AutoMin");
80 break;
81 case SCALE_PROP_AUTO_ORIGIN:
82 m_aOuterName = C2U("AutoOrigin");
83 break;
84 case SCALE_PROP_AUTO_STEPMAIN:
85 m_aOuterName = C2U("AutoStepMain");
86 break;
87 case SCALE_PROP_AUTO_STEPHELP:
88 m_aOuterName = C2U("AutoStepHelp");
89 break;
90 case SCALE_PROP_AXIS_TYPE:
91 m_aOuterName = C2U("AxisType");
92 break;
93 case SCALE_PROP_DATE_INCREMENT:
94 m_aOuterName = C2U("TimeIncrement");
95 break;
96 case SCALE_PROP_EXPLICIT_DATE_INCREMENT:
97 m_aOuterName = C2U("ExplicitTimeIncrement");
98 break;
99 case SCALE_PROP_LOGARITHMIC:
100 m_aOuterName = C2U("Logarithmic");
101 break;
102 case SCALE_PROP_REVERSEDIRECTION:
103 m_aOuterName = C2U("ReverseDirection");
104 break;
105 default:
106 OSL_ENSURE(false,"unknown scale property");
107 break;
108 }
109 }
110
~WrappedScaleProperty()111 WrappedScaleProperty::~WrappedScaleProperty()
112 {
113 }
114
addWrappedProperties(std::vector<WrappedProperty * > & rList,::boost::shared_ptr<Chart2ModelContact> spChart2ModelContact)115 void WrappedScaleProperty::addWrappedProperties( std::vector< WrappedProperty* >& rList
116 , ::boost::shared_ptr< Chart2ModelContact > spChart2ModelContact )
117 {
118 rList.push_back( new WrappedScaleProperty( SCALE_PROP_MAX, spChart2ModelContact ) );
119 rList.push_back( new WrappedScaleProperty( SCALE_PROP_MIN, spChart2ModelContact ) );
120 rList.push_back( new WrappedScaleProperty( SCALE_PROP_ORIGIN, spChart2ModelContact ) );
121 rList.push_back( new WrappedScaleProperty( SCALE_PROP_STEPMAIN, spChart2ModelContact ) );
122 rList.push_back( new WrappedScaleProperty( SCALE_PROP_STEPHELP, spChart2ModelContact ) );
123 rList.push_back( new WrappedScaleProperty( SCALE_PROP_STEPHELP_COUNT, spChart2ModelContact ) );
124 rList.push_back( new WrappedScaleProperty( SCALE_PROP_AUTO_MAX, spChart2ModelContact ) );
125 rList.push_back( new WrappedScaleProperty( SCALE_PROP_AUTO_MIN, spChart2ModelContact ) );
126 rList.push_back( new WrappedScaleProperty( SCALE_PROP_AUTO_ORIGIN, spChart2ModelContact ) );
127 rList.push_back( new WrappedScaleProperty( SCALE_PROP_AUTO_STEPMAIN, spChart2ModelContact ) );
128 rList.push_back( new WrappedScaleProperty( SCALE_PROP_AUTO_STEPHELP, spChart2ModelContact ) );
129 rList.push_back( new WrappedScaleProperty( SCALE_PROP_AXIS_TYPE, spChart2ModelContact ) );
130 rList.push_back( new WrappedScaleProperty( SCALE_PROP_DATE_INCREMENT, spChart2ModelContact ) );
131 rList.push_back( new WrappedScaleProperty( SCALE_PROP_EXPLICIT_DATE_INCREMENT, spChart2ModelContact ) );
132 rList.push_back( new WrappedScaleProperty( SCALE_PROP_LOGARITHMIC, spChart2ModelContact ) );
133 rList.push_back( new WrappedScaleProperty( SCALE_PROP_REVERSEDIRECTION, spChart2ModelContact ) );
134 }
135
setPropertyValue(const Any & rOuterValue,const Reference<beans::XPropertySet> & xInnerPropertySet) const136 void WrappedScaleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const
137 {
138 setPropertyValue( m_eScaleProperty, rOuterValue, xInnerPropertySet );
139 }
140
getPropertyValue(const Reference<beans::XPropertySet> & xInnerPropertySet) const141 Any WrappedScaleProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const
142 {
143 return getPropertyValue( m_eScaleProperty, xInnerPropertySet );
144 }
145
setPropertyValue(tScaleProperty eScaleProperty,const Any & rOuterValue,const Reference<beans::XPropertySet> & xInnerPropertySet) const146 void WrappedScaleProperty::setPropertyValue( tScaleProperty eScaleProperty, const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const
147 {
148 m_aOuterValue = rOuterValue;
149
150 Reference< chart2::XAxis > xAxis( xInnerPropertySet, uno::UNO_QUERY );
151 OSL_ENSURE(xAxis.is(),"need an XAxis");
152 if(!xAxis.is())
153 return;
154
155 bool bSetScaleData = false;
156
157 chart2::ScaleData aScaleData( xAxis->getScaleData() );
158
159 sal_Bool bBool = false;
160 switch( eScaleProperty )
161 {
162 case SCALE_PROP_MAX:
163 {
164 aScaleData.Maximum = rOuterValue;
165 bSetScaleData = true;
166 break;
167 }
168 case SCALE_PROP_MIN:
169 {
170 aScaleData.Minimum = rOuterValue;
171 bSetScaleData = true;
172 break;
173 }
174 case SCALE_PROP_STEPMAIN:
175 {
176 aScaleData.IncrementData.Distance = rOuterValue;
177 bSetScaleData = true;
178 break;
179 }
180 case SCALE_PROP_STEPHELP:
181 {
182 Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements );
183 if( rSubIncrements.getLength() == 0 )
184 rSubIncrements.realloc( 1 );
185
186 double fStepMain = 0, fStepHelp = 0;
187 if( (rOuterValue >>= fStepHelp) )
188 {
189 if( AxisHelper::isLogarithmic(aScaleData.Scaling) )
190 {
191 sal_Int32 nIntervalCount = static_cast< sal_Int32 >(fStepHelp);
192 rSubIncrements[ 0 ].IntervalCount <<= nIntervalCount;
193 }
194 else if( (fStepHelp != 0.0) &&
195 (aScaleData.IncrementData.Distance >>= fStepMain) )
196 {
197 // approximate interval count
198 sal_Int32 nIntervalCount = static_cast< sal_Int32 >(fStepMain / fStepHelp);
199 rSubIncrements[ 0 ].IntervalCount <<= nIntervalCount;
200 }
201 }
202 bSetScaleData = true;
203 break;
204 }
205 case SCALE_PROP_STEPHELP_COUNT:
206 {
207 Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements );
208 if( rSubIncrements.getLength() == 0 )
209 rSubIncrements.realloc( 1 );
210 sal_Int32 nIntervalCount=0;
211 if( rOuterValue>>=nIntervalCount )
212 rSubIncrements[ 0 ].IntervalCount <<= nIntervalCount;
213 else
214 rSubIncrements[ 0 ].IntervalCount = Any();
215 bSetScaleData = true;
216 break;
217 }
218 case SCALE_PROP_AUTO_MAX:
219 {
220 if( (rOuterValue >>= bBool) && bBool )
221 aScaleData.Maximum = Any();
222 else
223 aScaleData.Maximum = getPropertyValue( SCALE_PROP_MAX, xInnerPropertySet );
224 bSetScaleData = true;
225 break;
226 }
227 case SCALE_PROP_AUTO_MIN:
228 {
229 if( (rOuterValue >>= bBool) && bBool )
230 aScaleData.Minimum = Any();
231 else
232 aScaleData.Minimum = getPropertyValue( SCALE_PROP_MIN, xInnerPropertySet );
233 bSetScaleData = true;
234 break;
235 }
236 case SCALE_PROP_AUTO_STEPMAIN:
237 {
238 if( (rOuterValue >>= bBool) && bBool )
239 aScaleData.IncrementData.Distance = Any();
240 else
241 aScaleData.IncrementData.Distance = getPropertyValue( SCALE_PROP_STEPMAIN, xInnerPropertySet );
242 bSetScaleData = true;
243 break;
244 }
245 case SCALE_PROP_AUTO_STEPHELP:
246 {
247 Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements );
248 if( rSubIncrements.getLength() == 0 )
249 rSubIncrements.realloc( 1 );
250
251 if( (rOuterValue >>= bBool) && bBool )
252 rSubIncrements[ 0 ].IntervalCount = Any();
253 else
254 rSubIncrements[ 0 ].IntervalCount = getPropertyValue( SCALE_PROP_STEPHELP_COUNT, xInnerPropertySet );
255 bSetScaleData = true;
256 break;
257 }
258 case SCALE_PROP_ORIGIN:
259 {
260 aScaleData.Origin = rOuterValue;
261 bSetScaleData = true;
262 break;
263 }
264 case SCALE_PROP_AUTO_ORIGIN:
265 {
266 if( (rOuterValue >>= bBool) && bBool )
267 aScaleData.Origin = Any();
268 else
269 aScaleData.Origin = getPropertyValue( SCALE_PROP_ORIGIN, xInnerPropertySet );
270 bSetScaleData = true;
271 break;
272 }
273 case SCALE_PROP_AXIS_TYPE:
274 {
275 sal_Int32 nType = 0;
276 if( (rOuterValue >>= nType) )
277 {
278 if( ::com::sun::star::chart::ChartAxisType::AUTOMATIC == nType )
279 {
280 aScaleData.AutoDateAxis = true;
281 if( aScaleData.AxisType == AxisType::DATE )
282 aScaleData.AxisType = AxisType::CATEGORY;
283 }
284 else if( ::com::sun::star::chart::ChartAxisType::CATEGORY == nType )
285 {
286 aScaleData.AutoDateAxis = false;
287 if( aScaleData.AxisType == AxisType::DATE )
288 aScaleData.AxisType = AxisType::CATEGORY;
289 }
290 else if( ::com::sun::star::chart::ChartAxisType::DATE == nType )
291 {
292 if( aScaleData.AxisType == AxisType::CATEGORY )
293 aScaleData.AxisType = AxisType::DATE;
294 }
295 bSetScaleData = true;
296 }
297 break;
298 }
299 case SCALE_PROP_DATE_INCREMENT:
300 {
301 TimeIncrement aTimeIncrement;
302 rOuterValue >>= aTimeIncrement;
303 aScaleData.TimeIncrement = aTimeIncrement;
304 bSetScaleData = true;
305 break;
306 }
307 case SCALE_PROP_EXPLICIT_DATE_INCREMENT:
308 //read only property
309 break;
310 case SCALE_PROP_LOGARITHMIC:
311 {
312 if( rOuterValue >>= bBool )
313 {
314 bool bWasLogarithm = AxisHelper::isLogarithmic( aScaleData.Scaling );
315
316 // safe comparison between sal_Bool and bool
317 if( (!bBool) != (!bWasLogarithm) )
318 {
319 if( bBool )
320 aScaleData.Scaling = AxisHelper::createLogarithmicScaling( 10.0 );
321 else
322 aScaleData.Scaling = 0;
323 bSetScaleData = true;
324 }
325 }
326 break;
327 }
328 case SCALE_PROP_REVERSEDIRECTION:
329 {
330 if( rOuterValue >>= bBool )
331 {
332 bool bWasReverse = ( AxisOrientation_REVERSE == aScaleData.Orientation );
333 if( (!bBool) != (!bWasReverse) ) // safe comparison between sal_Bool and bool
334 {
335 aScaleData.Orientation = bBool ? AxisOrientation_REVERSE : AxisOrientation_MATHEMATICAL;
336 bSetScaleData = true;
337 }
338 }
339 break;
340 }
341 default:
342 {
343 OSL_ENSURE(false,"unknown scale property");
344 break;
345 }
346 }
347
348 if( bSetScaleData )
349 xAxis->setScaleData( aScaleData );
350 }
351
getPropertyValue(tScaleProperty eScaleProperty,const Reference<beans::XPropertySet> & xInnerPropertySet) const352 Any WrappedScaleProperty::getPropertyValue( tScaleProperty eScaleProperty, const Reference< beans::XPropertySet >& xInnerPropertySet ) const
353 {
354 Any aRet( m_aOuterValue );
355
356 Reference< chart2::XAxis > xAxis( xInnerPropertySet, uno::UNO_QUERY );
357 OSL_ENSURE(xAxis.is(),"need an XAxis");
358 if(!xAxis.is())
359 return aRet;
360
361 chart2::ScaleData aScaleData( xAxis->getScaleData() );
362
363 ExplicitScaleData aExplicitScale;
364 ExplicitIncrementData aExplicitIncrement;
365
366 switch( eScaleProperty )
367 {
368 case SCALE_PROP_MAX:
369 {
370 aRet = aScaleData.Maximum;
371 if( !aRet.hasValue() )
372 {
373 m_spChart2ModelContact->getExplicitValuesForAxis(
374 xAxis, aExplicitScale, aExplicitIncrement );
375 aRet <<= aExplicitScale.Maximum;
376 }
377 break;
378 }
379 case SCALE_PROP_MIN:
380 {
381 aRet = aScaleData.Minimum;
382 if( !aRet.hasValue() )
383 {
384 m_spChart2ModelContact->getExplicitValuesForAxis(
385 xAxis, aExplicitScale, aExplicitIncrement );
386 aRet <<= aExplicitScale.Minimum;
387 }
388 break;
389 }
390
391 case SCALE_PROP_STEPMAIN:
392 {
393 aRet = aScaleData.IncrementData.Distance;
394 if( !aRet.hasValue() )
395 {
396 m_spChart2ModelContact->getExplicitValuesForAxis(
397 xAxis, aExplicitScale, aExplicitIncrement );
398 aRet <<= aExplicitIncrement.Distance;
399 }
400 break;
401 }
402 case SCALE_PROP_STEPHELP:
403 {
404 // todo: evaluate PostEquidistant
405 bool bNeedToCalculateExplicitValues = true;
406
407 bool bLogarithmic( AxisHelper::isLogarithmic(aScaleData.Scaling) );
408 Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements );
409 if( bLogarithmic )
410 {
411 if( rSubIncrements.getLength() > 0 )
412 {
413 sal_Int32 nIntervalCount = 0;
414 rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount;
415 aRet = uno::makeAny( double(nIntervalCount) );
416 bNeedToCalculateExplicitValues = false;
417 }
418 }
419 else if( aScaleData.IncrementData.Distance.hasValue() )
420 {
421 if( rSubIncrements.getLength() > 0 )
422 {
423 double fStepMain = 0;
424 sal_Int32 nIntervalCount = 0;
425 if( (aScaleData.IncrementData.Distance >>= fStepMain) &&
426 (rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount) &&
427 nIntervalCount > 0 )
428 {
429 aRet <<= ( fStepMain / static_cast< double >( nIntervalCount ) );
430 bNeedToCalculateExplicitValues = false;
431 }
432 }
433 else
434 {
435 aRet = aScaleData.IncrementData.Distance;
436 bNeedToCalculateExplicitValues = false;
437 }
438 }
439
440 if( bNeedToCalculateExplicitValues )
441 {
442 m_spChart2ModelContact->getExplicitValuesForAxis(
443 xAxis, aExplicitScale, aExplicitIncrement );
444
445 if( !aExplicitIncrement.SubIncrements.empty() &&
446 aExplicitIncrement.SubIncrements[ 0 ].IntervalCount > 0 )
447 {
448 if( bLogarithmic )
449 {
450 if( rSubIncrements.getLength() > 0 )
451 {
452 sal_Int32 nIntervalCount = aExplicitIncrement.SubIncrements[ 0 ].IntervalCount;
453 aRet = uno::makeAny( double(nIntervalCount) );
454 }
455 }
456 else
457 aRet <<= ( aExplicitIncrement.Distance /
458 static_cast< double >(
459 aExplicitIncrement.SubIncrements[ 0 ].IntervalCount ));
460 }
461 else
462 {
463 if( bLogarithmic )
464 aRet <<= 5.0;
465 else
466 aRet <<= aExplicitIncrement.Distance;
467 }
468 }
469 break;
470 }
471 case SCALE_PROP_STEPHELP_COUNT:
472 {
473 sal_Int32 nIntervalCount = 0;
474 bool bNeedToCalculateExplicitValues = true;
475 Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements );
476 if( rSubIncrements.getLength() > 0 )
477 {
478 if( (rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount) && (nIntervalCount > 0) )
479 bNeedToCalculateExplicitValues = false;
480 }
481 if( bNeedToCalculateExplicitValues )
482 {
483 m_spChart2ModelContact->getExplicitValuesForAxis( xAxis, aExplicitScale, aExplicitIncrement );
484 if( !aExplicitIncrement.SubIncrements.empty() )
485 nIntervalCount = aExplicitIncrement.SubIncrements[ 0 ].IntervalCount;
486 }
487 aRet = uno::makeAny( nIntervalCount );
488 break;
489 }
490 case SCALE_PROP_AUTO_MAX:
491 {
492 aRet <<= (sal_Bool)( !aScaleData.Maximum.hasValue() );
493 break;
494 }
495 case SCALE_PROP_AUTO_MIN:
496 {
497 aRet <<= (sal_Bool)( !aScaleData.Minimum.hasValue() );
498 break;
499 }
500 case SCALE_PROP_AUTO_STEPMAIN:
501 {
502 aRet <<= (sal_Bool)( !aScaleData.IncrementData.Distance.hasValue() );
503 break;
504 }
505 case SCALE_PROP_AUTO_STEPHELP:
506 {
507 Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements );
508 if( rSubIncrements.getLength() > 0 )
509 aRet <<= (sal_Bool)( !rSubIncrements[ 0 ].IntervalCount.hasValue() );
510 else
511 aRet <<= sal_True;
512 break;
513 }
514 case SCALE_PROP_ORIGIN:
515 {
516 aRet = aScaleData.Origin;
517 if( !aRet.hasValue() )
518 {
519 m_spChart2ModelContact->getExplicitValuesForAxis(
520 xAxis, aExplicitScale, aExplicitIncrement );
521 aRet <<= aExplicitScale.Origin;
522 }
523 break;
524 }
525 case SCALE_PROP_AUTO_ORIGIN:
526 {
527 aRet <<= !hasDoubleValue(aScaleData.Origin);
528 break;
529 }
530 case SCALE_PROP_AXIS_TYPE:
531 {
532 sal_Int32 nType = ::com::sun::star::chart::ChartAxisType::AUTOMATIC;
533 if( aScaleData.AxisType == AxisType::DATE )
534 {
535 nType = ::com::sun::star::chart::ChartAxisType::DATE;
536 }
537 else if( aScaleData.AxisType == AxisType::CATEGORY )
538 {
539 if( !aScaleData.AutoDateAxis )
540 nType = ::com::sun::star::chart::ChartAxisType::CATEGORY;
541 }
542 aRet = uno::makeAny( nType );
543 break;
544 }
545 case SCALE_PROP_DATE_INCREMENT:
546 {
547 if( aScaleData.AxisType == AxisType::DATE || aScaleData.AutoDateAxis )
548 aRet = uno::makeAny( aScaleData.TimeIncrement );
549 break;
550 }
551 case SCALE_PROP_EXPLICIT_DATE_INCREMENT:
552 {
553 if( aScaleData.AxisType == AxisType::DATE || aScaleData.AutoDateAxis )
554 {
555 m_spChart2ModelContact->getExplicitValuesForAxis( xAxis, aExplicitScale, aExplicitIncrement );
556 if( aExplicitScale.AxisType == AxisType::DATE )
557 {
558 TimeIncrement aTimeIncrement;
559 aTimeIncrement.MajorTimeInterval = uno::makeAny( aExplicitIncrement.MajorTimeInterval );
560 aTimeIncrement.MinorTimeInterval = uno::makeAny( aExplicitIncrement.MinorTimeInterval );
561 aTimeIncrement.TimeResolution = uno::makeAny( aExplicitScale.TimeResolution );
562 aRet = uno::makeAny(aTimeIncrement);
563 }
564 }
565
566 if( aScaleData.AxisType == AxisType::DATE || aScaleData.AutoDateAxis )
567 aRet = uno::makeAny( aScaleData.TimeIncrement );
568 break;
569 }
570 case SCALE_PROP_LOGARITHMIC:
571 {
572 aRet <<= static_cast< sal_Bool >( AxisHelper::isLogarithmic(aScaleData.Scaling) );
573 break;
574 }
575 case SCALE_PROP_REVERSEDIRECTION:
576 {
577 aRet <<= static_cast< sal_Bool >( AxisOrientation_REVERSE == aScaleData.Orientation );
578 break;
579 }
580 default:
581 {
582 OSL_ENSURE(false,"unknown scale property");
583 break;
584 }
585 }
586
587 return aRet;
588 }
589
590 } // namespace wrapper
591 } // namespace chart
592 //.............................................................................
593