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