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 
31 #include "CachedDataSequence.hxx"
32 #include "macros.hxx"
33 #include "PropertyHelper.hxx"
34 #include "ContainerHelper.hxx"
35 #include "CommonFunctors.hxx"
36 #include "ModifyListenerHelper.hxx"
37 
38 #include <comphelper/sequenceashashmap.hxx>
39 
40 #include <algorithm>
41 #include <com/sun/star/beans/PropertyAttribute.hpp>
42 #include <rtl/math.hxx>
43 
44 using namespace ::com::sun::star;
45 using namespace ::chart::ContainerHelper;
46 
47 using ::com::sun::star::uno::Sequence;
48 using ::com::sun::star::uno::Reference;
49 using ::com::sun::star::uno::Any;
50 using ::rtl::OUString;
51 using ::osl::MutexGuard;
52 
53 // necessary for MS compiler
54 using ::comphelper::OPropertyContainer;
55 using ::comphelper::OMutexAndBroadcastHelper;
56 using ::comphelper::OPropertyArrayUsageHelper;
57 using ::chart::impl::CachedDataSequence_Base;
58 
59 namespace
60 {
61 static const OUString lcl_aServiceName(
62     RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.chart.CachedDataSequence" ));
63 
64 enum
65 {
66 //     PROP_SOURCE_IDENTIFIER,
67     PROP_NUMBERFORMAT_KEY,
68     PROP_PROPOSED_ROLE
69 };
70 }  // anonymous namespace
71 
72 
73 // ____________________
74 namespace chart
75 {
76 
77 CachedDataSequence::CachedDataSequence()
78         : OPropertyContainer( GetBroadcastHelper()),
79           CachedDataSequence_Base( GetMutex()),
80           m_eCurrentDataType( NUMERICAL ),
81           m_xModifyEventForwarder( ModifyListenerHelper::createModifyEventForwarder())
82 {
83     registerProperties();
84 }
85 CachedDataSequence::CachedDataSequence( const Reference< uno::XComponentContext > & /*xContext*/ )
86         : OPropertyContainer( GetBroadcastHelper()),
87           CachedDataSequence_Base( GetMutex()),
88           m_eCurrentDataType( MIXED ),
89           m_xModifyEventForwarder( ModifyListenerHelper::createModifyEventForwarder( ))
90 {
91     registerProperties();
92 }
93 
94 CachedDataSequence::CachedDataSequence( const OUString & rSingleText )
95         : OPropertyContainer( GetBroadcastHelper()),
96           CachedDataSequence_Base( GetMutex()),
97           m_eCurrentDataType( TEXTUAL ),
98           m_xModifyEventForwarder( ModifyListenerHelper::createModifyEventForwarder())
99 {
100     m_aTextualSequence.realloc(1);
101     m_aTextualSequence[0] = rSingleText;
102     registerProperties();
103 }
104 
105 CachedDataSequence::CachedDataSequence( const CachedDataSequence & rSource )
106         : OMutexAndBroadcastHelper(),
107           OPropertyContainer( GetBroadcastHelper()),
108           OPropertyArrayUsageHelper< CachedDataSequence >(),
109           CachedDataSequence_Base( GetMutex()),
110           m_nNumberFormatKey( rSource.m_nNumberFormatKey ),
111           m_sRole( rSource.m_sRole ),
112           m_eCurrentDataType( rSource.m_eCurrentDataType ),
113           m_xModifyEventForwarder( ModifyListenerHelper::createModifyEventForwarder())
114 {
115     switch( m_eCurrentDataType )
116     {
117         case TEXTUAL:
118             m_aTextualSequence = rSource.m_aTextualSequence;
119             break;
120         case NUMERICAL:
121             m_aNumericalSequence = rSource.m_aNumericalSequence;
122             break;
123         case MIXED:
124             m_aMixedSequence = rSource.m_aMixedSequence;
125             break;
126     }
127 
128     registerProperties();
129 }
130 
131 CachedDataSequence::~CachedDataSequence()
132 {}
133 
134 void CachedDataSequence::registerProperties()
135 {
136     registerProperty( C2U( "NumberFormatKey" ),
137                       PROP_NUMBERFORMAT_KEY,
138                       0,   // PropertyAttributes
139                       & m_nNumberFormatKey,
140                       ::getCppuType( & m_nNumberFormatKey ) );
141 
142     registerProperty( C2U( "Role" ),
143                       PROP_PROPOSED_ROLE,
144                       0,   // PropertyAttributes
145                       & m_sRole,
146                       ::getCppuType( & m_sRole ) );
147 }
148 
149 Sequence< double > CachedDataSequence::Impl_getNumericalData() const
150 {
151     if( m_eCurrentDataType == NUMERICAL )
152         return m_aNumericalSequence;
153 
154     sal_Int32 nSize = ( m_eCurrentDataType == TEXTUAL )
155         ? m_aTextualSequence.getLength()
156         : m_aMixedSequence.getLength();
157 
158     Sequence< double > aResult( nSize );
159     double * pResultArray = aResult.getArray();
160 
161     if( m_eCurrentDataType == TEXTUAL )
162     {
163         const OUString * pTextArray = m_aTextualSequence.getConstArray();
164         ::std::transform( pTextArray, pTextArray + nSize,
165                           pResultArray,
166                           CommonFunctors::OUStringToDouble() );
167     }
168     else
169     {
170         OSL_ASSERT( m_eCurrentDataType == MIXED );
171         const Any * pMixedArray = m_aMixedSequence.getConstArray();
172         ::std::transform( pMixedArray, pMixedArray + nSize,
173                           pResultArray,
174                           CommonFunctors::AnyToDouble() );
175     }
176     return aResult;
177 }
178 
179 Sequence< OUString > CachedDataSequence::Impl_getTextualData() const
180 {
181     if( m_eCurrentDataType == TEXTUAL )
182         return m_aTextualSequence;
183 
184     sal_Int32 nSize = ( m_eCurrentDataType == NUMERICAL )
185         ? m_aNumericalSequence.getLength()
186         : m_aMixedSequence.getLength();
187 
188     Sequence< OUString > aResult( nSize );
189     OUString * pResultArray = aResult.getArray();
190 
191     if( m_eCurrentDataType == NUMERICAL )
192     {
193         const double * pTextArray = m_aNumericalSequence.getConstArray();
194         ::std::transform( pTextArray, pTextArray + nSize,
195                           pResultArray,
196                           CommonFunctors::DoubleToOUString() );
197     }
198     else
199     {
200         OSL_ASSERT( m_eCurrentDataType == MIXED );
201         const Any * pMixedArray = m_aMixedSequence.getConstArray();
202         ::std::transform( pMixedArray, pMixedArray + nSize,
203                           pResultArray,
204                           CommonFunctors::AnyToString() );
205     }
206 
207     return aResult;
208 }
209 
210 Sequence< Any > CachedDataSequence::Impl_getMixedData() const
211 {
212     if( m_eCurrentDataType == MIXED )
213         return m_aMixedSequence;
214 
215     sal_Int32 nSize = ( m_eCurrentDataType == NUMERICAL )
216         ? m_aNumericalSequence.getLength()
217         : m_aTextualSequence.getLength();
218 
219     Sequence< Any > aResult( nSize );
220     Any * pResultArray = aResult.getArray();
221 
222     if( m_eCurrentDataType == NUMERICAL )
223     {
224         const double * pTextArray = m_aNumericalSequence.getConstArray();
225         ::std::transform( pTextArray, pTextArray + nSize,
226                           pResultArray,
227                           CommonFunctors::makeAny< double >() );
228     }
229     else
230     {
231         OSL_ASSERT( m_eCurrentDataType == TEXTUAL );
232         const OUString * pMixedArray = m_aTextualSequence.getConstArray();
233         ::std::transform( pMixedArray, pMixedArray + nSize,
234                           pResultArray,
235                           CommonFunctors::makeAny< OUString >() );
236     }
237 
238     return aResult;
239 }
240 
241 // ================================================================================
242 
243 Sequence< OUString > CachedDataSequence::getSupportedServiceNames_Static()
244 {
245     Sequence< OUString > aServices( 4 );
246     aServices[ 0 ] = lcl_aServiceName;
247     aServices[ 1 ] = C2U( "com.sun.star.chart2.data.DataSequence" );
248     aServices[ 2 ] = C2U( "com.sun.star.chart2.data.NumericalDataSequence" );
249     aServices[ 3 ] = C2U( "com.sun.star.chart2.data.TextualDataSequence" );
250     return aServices;
251 }
252 
253 IMPLEMENT_FORWARD_XINTERFACE2( CachedDataSequence, CachedDataSequence_Base, OPropertyContainer )
254 IMPLEMENT_FORWARD_XTYPEPROVIDER2( CachedDataSequence, CachedDataSequence_Base, OPropertyContainer )
255 
256 // ____ XPropertySet ____
257 Reference< beans::XPropertySetInfo > SAL_CALL CachedDataSequence::getPropertySetInfo()
258     throw(uno::RuntimeException)
259 {
260     return Reference< beans::XPropertySetInfo >( createPropertySetInfo( getInfoHelper() ) );
261 }
262 
263 // ____ ::comphelper::OPropertySetHelper ____
264 // __________________________________________
265 ::cppu::IPropertyArrayHelper& CachedDataSequence::getInfoHelper()
266 {
267 	return *getArrayHelper();
268 }
269 
270 // ____ ::comphelper::OPropertyArrayHelper ____
271 // ____________________________________________
272 ::cppu::IPropertyArrayHelper* CachedDataSequence::createArrayHelper() const
273 {
274 	Sequence< beans::Property > aProps;
275     // describes all properties which have been registered in the ctor
276 	describeProperties( aProps );
277 
278 	return new ::cppu::OPropertyArrayHelper( aProps );
279 }
280 
281 // implement XServiceInfo methods basing upon getSupportedServiceNames_Static
282 APPHELPER_XSERVICEINFO_IMPL( CachedDataSequence, lcl_aServiceName )
283 
284 // ================================================================================
285 
286 // ________ XNumericalDataSequence ________
287 Sequence< double > SAL_CALL CachedDataSequence::getNumericalData()
288     throw (uno::RuntimeException)
289 {
290     // /--
291     MutexGuard aGuard( GetMutex() );
292 
293     if( m_eCurrentDataType == NUMERICAL )
294         return m_aNumericalSequence;
295     else
296         return Impl_getNumericalData();
297     // \--
298 }
299 
300 // ________ XTextualDataSequence ________
301 Sequence< OUString > SAL_CALL CachedDataSequence::getTextualData()
302     throw (uno::RuntimeException)
303 {
304     // /--
305     MutexGuard aGuard( GetMutex() );
306 
307     if( m_eCurrentDataType == TEXTUAL )
308         return m_aTextualSequence;
309     else
310         return Impl_getTextualData();
311     // \--
312 }
313 
314 // void SAL_CALL CachedDataSequence::setTextualData( const Sequence< OUString >& aData )
315 //     throw (uno::RuntimeException)
316 // {
317 //     // /--
318 //     MutexGuard aGuard( GetMutex() );
319 //     Impl_setTextualData( aData );
320 //     // \--
321 // }
322 
323 // ________ XDataSequence  ________
324 Sequence< Any > SAL_CALL CachedDataSequence::getData()
325     throw (uno::RuntimeException)
326 {
327     // /--
328     MutexGuard aGuard( GetMutex() );
329     return Impl_getMixedData();
330     // \--
331 }
332 
333 OUString SAL_CALL CachedDataSequence::getSourceRangeRepresentation()
334     throw (uno::RuntimeException)
335 {
336     return m_sRole;
337 }
338 
339 Sequence< OUString > SAL_CALL CachedDataSequence::generateLabel( chart2::data::LabelOrigin  /*eLabelOrigin*/ )
340     throw (uno::RuntimeException)
341 {
342     // return empty label, as we have no range representaions to determine something useful
343     return Sequence< OUString >();
344 }
345 
346 ::sal_Int32 SAL_CALL CachedDataSequence::getNumberFormatKeyByIndex( ::sal_Int32 /*nIndex*/ )
347     throw (lang::IndexOutOfBoundsException,
348            uno::RuntimeException)
349 {
350     return 0;
351 }
352 
353 Reference< util::XCloneable > SAL_CALL CachedDataSequence::createClone()
354     throw (uno::RuntimeException)
355 {
356     CachedDataSequence * pNewSeq = new CachedDataSequence( *this );
357 
358     return Reference< util::XCloneable >( pNewSeq );
359 }
360 
361 void SAL_CALL CachedDataSequence::addModifyListener( const Reference< util::XModifyListener >& aListener )
362     throw (uno::RuntimeException)
363 {
364     try
365     {
366         Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
367         xBroadcaster->addModifyListener( aListener );
368     }
369     catch( const uno::Exception & ex )
370     {
371         ASSERT_EXCEPTION( ex );
372     }
373 }
374 
375 void SAL_CALL CachedDataSequence::removeModifyListener( const Reference< util::XModifyListener >& aListener )
376     throw (uno::RuntimeException)
377 {
378     try
379     {
380         Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
381         xBroadcaster->removeModifyListener( aListener );
382     }
383     catch( const uno::Exception & ex )
384     {
385         ASSERT_EXCEPTION( ex );
386     }
387 }
388 
389 // lang::XInitialization:
390 void SAL_CALL CachedDataSequence::initialize(const uno::Sequence< uno::Any > & _aArguments) throw (uno::RuntimeException, uno::Exception)
391 {
392     ::comphelper::SequenceAsHashMap aMap(_aArguments);
393     m_aNumericalSequence = aMap.getUnpackedValueOrDefault(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DataSequence")),m_aNumericalSequence);
394     if ( m_aNumericalSequence.getLength() )
395         m_eCurrentDataType = NUMERICAL;
396     else
397     {
398         m_aTextualSequence = aMap.getUnpackedValueOrDefault(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DataSequence")),m_aTextualSequence);
399         if ( m_aTextualSequence.getLength() )
400             m_eCurrentDataType = TEXTUAL;
401         else
402         {
403             m_aMixedSequence = aMap.getUnpackedValueOrDefault(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DataSequence")),m_aMixedSequence);
404             if ( m_aMixedSequence.getLength() )
405                 m_eCurrentDataType = MIXED;
406         }
407     }
408 }
409 }  // namespace chart
410