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_chart2.hxx"
26 #include "ErrorBarItemConverter.hxx"
27 #include "SchWhichPairs.hxx"
28 #include "macros.hxx"
29 #include "ItemPropertyMap.hxx"
30 #include "ErrorBar.hxx"
31 #include "PropertyHelper.hxx"
32 #include "ChartModelHelper.hxx"
33 #include "ChartTypeHelper.hxx"
34 #include "StatisticsHelper.hxx"
35 
36 #include "GraphicPropertyItemConverter.hxx"
37 
38 #include <svl/stritem.hxx>
39 #include <svx/chrtitem.hxx>
40 #include <svl/intitem.hxx>
41 #include <rtl/math.hxx>
42 
43 #include <com/sun/star/chart2/DataPointLabel.hpp>
44 #include <com/sun/star/chart2/XInternalDataProvider.hpp>
45 #include <com/sun/star/chart/ErrorBarStyle.hpp>
46 #include <com/sun/star/lang/XServiceName.hpp>
47 
48 #include <functional>
49 #include <algorithm>
50 #include <vector>
51 
52 using namespace ::com::sun::star;
53 
54 namespace
55 {
56 
57 void lcl_getErrorValues( const uno::Reference< beans::XPropertySet > & xErrorBarProp,
58                     double & rOutPosError, double & rOutNegError )
59 {
60     if( ! xErrorBarProp.is())
61         return;
62 
63     try
64     {
65         xErrorBarProp->getPropertyValue( C2U( "PositiveError" )) >>= rOutPosError;
66         xErrorBarProp->getPropertyValue( C2U( "NegativeError" )) >>= rOutNegError;
67     }
68     catch( uno::Exception & ex )
69     {
70         ASSERT_EXCEPTION( ex );
71     }
72 }
73 
74 void lcl_getErrorIndicatorValues(
75     const uno::Reference< beans::XPropertySet > & xErrorBarProp,
76     bool & rOutShowPosError, bool & rOutShowNegError )
77 {
78     if( ! xErrorBarProp.is())
79         return;
80 
81     try
82     {
83         xErrorBarProp->getPropertyValue( C2U( "ShowPositiveError" )) >>= rOutShowPosError;
84         xErrorBarProp->getPropertyValue( C2U( "ShowNegativeError" )) >>= rOutShowNegError;
85     }
86     catch( uno::Exception & ex )
87     {
88         ASSERT_EXCEPTION( ex );
89     }
90 }
91 
92 } // anonymous namespace
93 
94 namespace chart
95 {
96 namespace wrapper
97 {
98 
99 ErrorBarItemConverter::ErrorBarItemConverter(
100     const uno::Reference< frame::XModel > & xModel,
101     const uno::Reference< beans::XPropertySet > & rPropertySet,
102     SfxItemPool& rItemPool,
103     SdrModel& rDrawModel,
104     const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) :
105         ItemConverter( rPropertySet, rItemPool ),
106         m_spGraphicConverter( new GraphicPropertyItemConverter(
107                                   rPropertySet, rItemPool, rDrawModel,
108                                   xNamedPropertyContainerFactory,
109                                   GraphicPropertyItemConverter::LINE_PROPERTIES )),
110         m_xModel( xModel )
111 {}
112 
113 ErrorBarItemConverter::~ErrorBarItemConverter()
114 {}
115 
116 void ErrorBarItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const
117 {
118     m_spGraphicConverter->FillItemSet( rOutItemSet );
119 
120     // own items
121     ItemConverter::FillItemSet( rOutItemSet );
122 }
123 
124 bool ErrorBarItemConverter::ApplyItemSet( const SfxItemSet & rItemSet )
125 {
126     bool bResult = m_spGraphicConverter->ApplyItemSet( rItemSet );
127 
128     // own items
129     return ItemConverter::ApplyItemSet( rItemSet ) || bResult;
130 }
131 
132 const sal_uInt16 * ErrorBarItemConverter::GetWhichPairs() const
133 {
134     // must span all used items!
135     return nErrorBarWhichPairs;
136 }
137 
138 bool ErrorBarItemConverter::GetItemProperty(
139     tWhichIdType /* nWhichId */,
140     tPropertyNameWithMemberId & /* rOutProperty */ ) const
141 {
142     return false;
143 }
144 
145 bool ErrorBarItemConverter::ApplySpecialItem(
146     sal_uInt16 nWhichId, const SfxItemSet & rItemSet )
147     throw( uno::Exception )
148 {
149     bool bChanged = false;
150     uno::Any aValue;
151 
152     switch( nWhichId )
153     {
154         // Attention !!! This case must be passed before SCHATTR_STAT_PERCENT,
155         // SCHATTR_STAT_BIGERROR, SCHATTR_STAT_CONSTPLUS,
156         // SCHATTR_STAT_CONSTMINUS and SCHATTR_STAT_INDICATE
157         case SCHATTR_STAT_KIND_ERROR:
158         {
159             uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet());
160 
161             SvxChartKindError eErrorKind =
162                 static_cast< const SvxChartKindErrorItem & >(
163                     rItemSet.Get( nWhichId )).GetValue();
164 
165             if( !xErrorBarProp.is() && eErrorKind == CHERROR_NONE)
166             {
167                 //nothing to do
168             }
169             else
170             {
171                 sal_Int32 nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE;
172 
173                 switch( eErrorKind )
174                 {
175                     case CHERROR_NONE:
176                         nStyle = ::com::sun::star::chart::ErrorBarStyle::NONE; break;
177                     case CHERROR_VARIANT:
178                         nStyle = ::com::sun::star::chart::ErrorBarStyle::VARIANCE; break;
179                     case CHERROR_SIGMA:
180                         nStyle = ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION; break;
181                     case CHERROR_PERCENT:
182                         nStyle = ::com::sun::star::chart::ErrorBarStyle::RELATIVE; break;
183                     case CHERROR_BIGERROR:
184                         nStyle = ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN; break;
185                     case CHERROR_CONST:
186                         nStyle = ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE; break;
187                     case CHERROR_STDERROR:
188                         nStyle = ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR; break;
189                     case CHERROR_RANGE:
190                         nStyle = ::com::sun::star::chart::ErrorBarStyle::FROM_DATA; break;
191                 }
192 
193                 xErrorBarProp->setPropertyValue( C2U( "ErrorBarStyle" ),
194                                                     uno::makeAny( nStyle ));
195                 bChanged = true;
196             }
197         }
198         break;
199 
200         case SCHATTR_STAT_PERCENT:
201         case SCHATTR_STAT_BIGERROR:
202         {
203             OSL_ENSURE( false, "Deprectaed item" );
204             uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet());
205 
206             double fValue =
207                 static_cast< const SvxDoubleItem & >(
208                     rItemSet.Get( nWhichId )).GetValue();
209             double fPos, fNeg;
210             lcl_getErrorValues( xErrorBarProp, fPos, fNeg );
211 
212             if( ! ( ::rtl::math::approxEqual( fPos, fValue ) &&
213                     ::rtl::math::approxEqual( fNeg, fValue )))
214             {
215                 xErrorBarProp->setPropertyValue( C2U( "PositiveError" ),
216                                                     uno::makeAny( fValue ));
217                 xErrorBarProp->setPropertyValue( C2U( "NegativeError" ),
218                                                     uno::makeAny( fValue ));
219                 bChanged = true;
220             }
221         }
222         break;
223 
224         case SCHATTR_STAT_CONSTPLUS:
225         {
226             double fValue =
227                 static_cast< const SvxDoubleItem & >(
228                     rItemSet.Get( nWhichId )).GetValue();
229             double fPos, fNeg;
230             lcl_getErrorValues( GetPropertySet(), fPos, fNeg );
231 
232             if( ! ::rtl::math::approxEqual( fPos, fValue ))
233             {
234                 GetPropertySet()->setPropertyValue( C2U( "PositiveError" ), uno::makeAny( fValue ));
235                 bChanged = true;
236             }
237         }
238         break;
239 
240         case SCHATTR_STAT_CONSTMINUS:
241         {
242             uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet());
243 
244             double fValue =
245                 static_cast< const SvxDoubleItem & >(
246                     rItemSet.Get( nWhichId )).GetValue();
247             double fPos, fNeg;
248             lcl_getErrorValues( xErrorBarProp, fPos, fNeg );
249 
250             if( ! ::rtl::math::approxEqual( fNeg, fValue ))
251             {
252                 xErrorBarProp->setPropertyValue( C2U( "NegativeError" ), uno::makeAny( fValue ));
253                 bChanged = true;
254             }
255         }
256         break;
257 
258         case SCHATTR_STAT_INDICATE:
259         {
260             uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet());
261 
262             SvxChartIndicate eIndicate =
263                 static_cast< const SvxChartIndicateItem & >(
264                     rItemSet.Get( nWhichId )).GetValue();
265 
266             bool bNewIndPos = (eIndicate == CHINDICATE_BOTH || eIndicate == CHINDICATE_UP );
267             bool bNewIndNeg = (eIndicate == CHINDICATE_BOTH || eIndicate == CHINDICATE_DOWN );
268 
269             bool bShowPos, bShowNeg;
270             lcl_getErrorIndicatorValues( xErrorBarProp, bShowPos, bShowNeg );
271 
272             if( ( bShowPos != bNewIndPos ||
273                   bShowNeg != bNewIndNeg ))
274             {
275                 xErrorBarProp->setPropertyValue( C2U( "ShowPositiveError" ), uno::makeAny( bNewIndPos ));
276                 xErrorBarProp->setPropertyValue( C2U( "ShowNegativeError" ), uno::makeAny( bNewIndNeg ));
277                 bChanged = true;
278             }
279         }
280         break;
281 
282         case SCHATTR_STAT_RANGE_POS:
283         case SCHATTR_STAT_RANGE_NEG:
284         {
285             // @todo: also be able to deal with x-error bars
286             const bool bYError = true;
287             uno::Reference< chart2::data::XDataSource > xErrorBarSource( GetPropertySet(), uno::UNO_QUERY );
288             uno::Reference< chart2::XChartDocument > xChartDoc( m_xModel, uno::UNO_QUERY );
289             uno::Reference< chart2::data::XDataProvider > xDataProvider;
290 
291             if( xChartDoc.is())
292                 xDataProvider.set( xChartDoc->getDataProvider());
293             if( xErrorBarSource.is() && xDataProvider.is())
294             {
295                 ::rtl::OUString aNewRange( static_cast< const SfxStringItem & >( rItemSet.Get( nWhichId )).GetValue());
296                 bool bApplyNewRange = false;
297 
298                 bool bIsPositiveValue( nWhichId == SCHATTR_STAT_RANGE_POS );
299                 if( xChartDoc->hasInternalDataProvider())
300                 {
301                     if( aNewRange.getLength())
302                     {
303                         uno::Reference< chart2::data::XDataSequence > xSeq(
304                             StatisticsHelper::getErrorDataSequenceFromDataSource(
305                                 xErrorBarSource, bIsPositiveValue, bYError ));
306                         if( ! xSeq.is())
307                         {
308                             // no data range for error bars yet => create
309                             uno::Reference< chart2::XInternalDataProvider > xIntDataProvider( xDataProvider, uno::UNO_QUERY );
310                             OSL_ASSERT( xIntDataProvider.is());
311                             if( xIntDataProvider.is())
312                             {
313                                 xIntDataProvider->appendSequence();
314                                 aNewRange = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("last"));
315                                 bApplyNewRange = true;
316                             }
317                         }
318                     }
319                 }
320                 else
321                 {
322                     uno::Reference< chart2::data::XDataSequence > xSeq(
323                         StatisticsHelper::getErrorDataSequenceFromDataSource(
324                             xErrorBarSource, bIsPositiveValue, bYError ));
325                     bApplyNewRange =
326                         ! ( xSeq.is() && aNewRange.equals( xSeq->getSourceRangeRepresentation()));
327                 }
328 
329                 if( bApplyNewRange )
330                     StatisticsHelper::setErrorDataSequence(
331                         xErrorBarSource, xDataProvider, aNewRange, bIsPositiveValue, bYError );
332             }
333         }
334         break;
335     }
336 
337     return bChanged;
338 }
339 
340 void ErrorBarItemConverter::FillSpecialItem(
341     sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const
342     throw( uno::Exception )
343 {
344     switch( nWhichId )
345     {
346         case SCHATTR_STAT_KIND_ERROR:
347         {
348             SvxChartKindError eErrorKind = CHERROR_NONE;
349             uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet());
350 
351             sal_Int32 nStyle = 0;
352             if( xErrorBarProp->getPropertyValue( C2U( "ErrorBarStyle" )) >>= nStyle )
353             {
354                 switch( nStyle )
355                 {
356                     case ::com::sun::star::chart::ErrorBarStyle::NONE:
357                         break;
358                     case ::com::sun::star::chart::ErrorBarStyle::VARIANCE:
359                         eErrorKind = CHERROR_VARIANT; break;
360                     case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION:
361                         eErrorKind = CHERROR_SIGMA; break;
362                     case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE:
363                         eErrorKind = CHERROR_CONST; break;
364                     case ::com::sun::star::chart::ErrorBarStyle::RELATIVE:
365                         eErrorKind = CHERROR_PERCENT; break;
366                     case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN:
367                         eErrorKind = CHERROR_BIGERROR; break;
368                     case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR:
369                         eErrorKind = CHERROR_STDERROR; break;
370                     case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA:
371                         eErrorKind = CHERROR_RANGE; break;
372                 }
373             }
374             rOutItemSet.Put( SvxChartKindErrorItem( eErrorKind, SCHATTR_STAT_KIND_ERROR ));
375         }
376         break;
377 
378         case SCHATTR_STAT_PERCENT:
379         {
380             double fPos, fNeg;
381             lcl_getErrorValues( GetPropertySet(), fPos, fNeg );
382             rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, nWhichId ));
383         }
384         break;
385 
386         case SCHATTR_STAT_BIGERROR:
387         {
388             double fPos, fNeg;
389             lcl_getErrorValues( GetPropertySet(), fPos, fNeg );
390             rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, nWhichId ));
391         }
392         break;
393 
394         case SCHATTR_STAT_CONSTPLUS:
395         {
396             double fPos, fNeg;
397             lcl_getErrorValues( GetPropertySet(), fPos, fNeg );
398             rOutItemSet.Put( SvxDoubleItem( fPos, nWhichId ));
399         }
400         break;
401 
402         case SCHATTR_STAT_CONSTMINUS:
403         {
404             double fPos, fNeg;
405             lcl_getErrorValues( GetPropertySet(), fPos, fNeg );
406             rOutItemSet.Put( SvxDoubleItem( fNeg, nWhichId ));
407         }
408         break;
409 
410         case SCHATTR_STAT_INDICATE:
411         {
412             SvxChartIndicate eIndicate = CHINDICATE_BOTH;
413             bool bShowPos, bShowNeg;
414             lcl_getErrorIndicatorValues( GetPropertySet(), bShowPos, bShowNeg );
415 
416             if( bShowPos )
417             {
418                 if( bShowNeg )
419                     eIndicate = CHINDICATE_BOTH;
420                 else
421                     eIndicate = CHINDICATE_UP;
422             }
423             else
424             {
425                 if( bShowNeg )
426                     eIndicate = CHINDICATE_DOWN;
427                 else
428                     eIndicate = CHINDICATE_NONE;
429             }
430             rOutItemSet.Put( SvxChartIndicateItem( eIndicate, SCHATTR_STAT_INDICATE ));
431         }
432         break;
433 
434         case SCHATTR_STAT_RANGE_POS:
435         case SCHATTR_STAT_RANGE_NEG:
436         {
437             uno::Reference< chart2::data::XDataSource > xErrorBarSource( GetPropertySet(), uno::UNO_QUERY );
438             if( xErrorBarSource.is())
439             {
440                 uno::Reference< chart2::data::XDataSequence > xSeq(
441                     StatisticsHelper::getErrorDataSequenceFromDataSource(
442                         xErrorBarSource, (nWhichId == SCHATTR_STAT_RANGE_POS) /*, true */ /* y */ ));
443                 if( xSeq.is())
444                     rOutItemSet.Put( SfxStringItem( nWhichId, String( xSeq->getSourceRangeRepresentation())));
445             }
446         }
447         break;
448    }
449 }
450 
451 } //  namespace wrapper
452 } //  namespace chart
453