bump product version to 5.0.4.1
[LibreOffice.git] / extensions / source / propctrlr / stringrepresentation.cxx
blob3a658a1c391beca7a9539607febee5b46f05acd4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sal/config.h"
22 #include "boost/noncopyable.hpp"
23 #include "cppuhelper/factory.hxx"
24 #include "cppuhelper/implementationentry.hxx"
25 #include "cppuhelper/implbase3.hxx"
26 #include <cppuhelper/supportsservice.hxx>
27 #include "com/sun/star/lang/XServiceInfo.hpp"
28 #include "com/sun/star/inspection/XStringRepresentation.hpp"
29 #include "com/sun/star/lang/XInitialization.hpp"
30 #include "com/sun/star/script/XTypeConverter.hpp"
31 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
32 #include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
33 #include <com/sun/star/beans/XIntrospection.hpp>
34 #include <com/sun/star/util/DateTime.hpp>
35 #include <com/sun/star/util/Date.hpp>
36 #include <com/sun/star/util/Time.hpp>
37 #include <comphelper/sequence.hxx>
38 #include <connectivity/dbconversion.hxx>
39 #include "formresid.hrc"
40 #include "pcrservices.hxx"
41 #include <tools/StringListResource.hxx>
42 #include <comphelper/types.hxx>
43 #include "modulepcr.hxx"
45 #include <functional>
46 #include <algorithm>
48 // component helper namespace
49 namespace comp_StringRepresentation {
51 using namespace ::com::sun::star;
53 // component and service helper functions:
54 OUString SAL_CALL _getImplementationName();
55 uno::Sequence< OUString > SAL_CALL _getSupportedServiceNames();
56 uno::Reference< uno::XInterface > SAL_CALL _create( uno::Reference< uno::XComponentContext > const & context );
58 } // closing component helper namespace
61 namespace pcr{
63 using namespace ::com::sun::star;
64 using namespace ::com::sun::star::uno;
66 class StringRepresentation:
67 public ::cppu::WeakImplHelper3<
68 lang::XServiceInfo,
69 inspection::XStringRepresentation,
70 lang::XInitialization>,
71 private boost::noncopyable
73 public:
74 explicit StringRepresentation(uno::Reference< uno::XComponentContext > const & context);
76 // lang::XServiceInfo:
77 virtual OUString SAL_CALL getImplementationName() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
78 virtual sal_Bool SAL_CALL supportsService(const OUString & ServiceName) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
79 virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
81 // inspection::XStringRepresentation:
82 virtual OUString SAL_CALL convertToControlValue(const uno::Any & PropertyValue) throw (uno::RuntimeException, uno::Exception, std::exception) SAL_OVERRIDE;
83 virtual uno::Any SAL_CALL convertToPropertyValue(const OUString & ControlValue, const uno::Type & ControlValueType) throw (uno::RuntimeException, uno::Exception, std::exception) SAL_OVERRIDE;
85 // lang::XInitialization:
86 virtual void SAL_CALL initialize(const uno::Sequence< uno::Any > & aArguments) throw (uno::RuntimeException, uno::Exception, std::exception) SAL_OVERRIDE;
88 private:
89 virtual ~StringRepresentation() {}
91 /** converts a generic value into a string representation
93 If you want to convert values whose string representation does not depend
94 on a concrete property, use this version
96 @return <TRUE/>
97 if and only if the value could be converted
99 static bool convertGenericValueToString(
100 const uno::Any& _rValue,
101 OUString& _rStringRep
104 /** converts string representation into generic value
106 If you want to convert values whose string representation does not depend
107 on a concrete property, use this version
109 @return <TRUE/>
110 if and only if the value could be converted
112 static bool convertStringToGenericValue(
113 const OUString& _rStringRep,
114 uno::Any& _rValue,
115 const uno::Type& _rTargetType
118 /** uses the simple convert method from the type converter
120 * \param _rValue the value to be converted
121 * \return the converted string.
123 OUString convertSimpleToString( const uno::Any& _rValue );
125 /** converts a string into his constant value if it exists, otherwise the type converter is used.
126 * \param _rValue the value to be converted
127 * \param _ePropertyType the type of the propery to be converted into
128 * \return the converted value
130 uno::Any convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType );
132 uno::Reference< uno::XComponentContext > m_xContext;
133 uno::Reference< script::XTypeConverter > m_xTypeConverter;
134 uno::Reference< reflection::XConstantsTypeDescription > m_xTypeDescription;
135 uno::Sequence< OUString > m_aValues;
136 uno::Sequence< uno::Reference< reflection::XConstantTypeDescription> > m_aConstants;
140 StringRepresentation::StringRepresentation(uno::Reference< uno::XComponentContext > const & context) :
141 m_xContext(context)
144 // com.sun.star.uno.XServiceInfo:
145 OUString SAL_CALL StringRepresentation::getImplementationName() throw (uno::RuntimeException, std::exception)
147 return comp_StringRepresentation::_getImplementationName();
150 sal_Bool SAL_CALL StringRepresentation::supportsService(OUString const & serviceName) throw (uno::RuntimeException, std::exception)
152 return cppu::supportsService(this, serviceName);
155 uno::Sequence< OUString > SAL_CALL StringRepresentation::getSupportedServiceNames() throw (uno::RuntimeException, std::exception)
157 return comp_StringRepresentation::_getSupportedServiceNames();
160 // inspection::XStringRepresentation:
161 OUString SAL_CALL StringRepresentation::convertToControlValue(const uno::Any & PropertyValue) throw (uno::RuntimeException, uno::Exception, std::exception)
163 OUString sReturn;
164 if ( !convertGenericValueToString( PropertyValue, sReturn ) )
166 sReturn = convertSimpleToString( PropertyValue );
167 #ifdef DBG_UTIL
168 if ( sReturn.isEmpty() && PropertyValue.hasValue() )
170 OString sMessage( "StringRepresentation::convertPropertyValueToStringRepresentation: cannot convert values of type '" );
171 sMessage += OString( PropertyValue.getValueType().getTypeName().getStr(), PropertyValue.getValueType().getTypeName().getLength(), RTL_TEXTENCODING_ASCII_US );
172 sMessage += OString( "'!" );
173 OSL_FAIL( sMessage.getStr() );
175 #endif
178 return sReturn;
181 uno::Any SAL_CALL StringRepresentation::convertToPropertyValue(const OUString & ControlValue, const uno::Type & ControlValueType) throw (uno::RuntimeException, uno::Exception, std::exception)
183 uno::Any aReturn;
185 uno::TypeClass ePropertyType = ControlValueType.getTypeClass();
186 switch ( ePropertyType )
188 case uno::TypeClass_FLOAT:
189 case uno::TypeClass_DOUBLE:
190 case uno::TypeClass_BYTE:
191 case uno::TypeClass_SHORT:
192 case uno::TypeClass_LONG:
193 case uno::TypeClass_HYPER:
194 case uno::TypeClass_UNSIGNED_SHORT:
195 case uno::TypeClass_UNSIGNED_LONG:
196 case uno::TypeClass_UNSIGNED_HYPER:
199 aReturn = convertStringToSimple(ControlValue, ePropertyType);
201 catch( const script::CannotConvertException& ) { }
202 catch( const lang::IllegalArgumentException& ) { }
203 break;
205 default:
206 #if OSL_DEBUG_LEVEL > 0
207 bool bCanConvert =
208 #endif
209 convertStringToGenericValue( ControlValue, aReturn, ControlValueType );
211 #if OSL_DEBUG_LEVEL > 0
212 // could not convert ...
213 if ( !bCanConvert && !ControlValue.isEmpty() )
215 OString sMessage( "StringRepresentation::convertStringRepresentationToPropertyValue: cannot convert into values of type '" );
216 sMessage += OString( ControlValueType.getTypeName().getStr(), ControlValueType.getTypeName().getLength(), RTL_TEXTENCODING_ASCII_US );
217 sMessage += OString( "'!" );
218 OSL_FAIL( sMessage.getStr() );
220 #endif
223 return aReturn;
226 namespace {
228 // This comparison functor assumes an underlying set of constants with pairwise
229 // unequal values that are all of UNO SHORT or LONG type:
230 struct CompareConstants {
231 bool operator ()(
232 css::uno::Reference< css::reflection::XConstantTypeDescription > const &
234 css::uno::Reference< css::reflection::XConstantTypeDescription > const &
235 c2) const
237 return c1->getConstantValue().get<sal_Int32>()
238 < c2->getConstantValue().get<sal_Int32>();
244 // lang::XInitialization:
245 void SAL_CALL StringRepresentation::initialize(const uno::Sequence< uno::Any > & aArguments) throw (uno::RuntimeException, uno::Exception, std::exception)
247 sal_Int32 nLength = aArguments.getLength();
248 if ( nLength )
250 const uno::Any* pIter = aArguments.getConstArray();
251 m_xTypeConverter.set(*pIter++,uno::UNO_QUERY);
252 if ( nLength == 3 )
254 OUString sConstantName;
255 *pIter++ >>= sConstantName;
256 *pIter >>= m_aValues;
258 if ( m_xContext.is() )
260 uno::Reference< container::XHierarchicalNameAccess > xTypeDescProv(
261 m_xContext->getValueByName("/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
262 uno::UNO_QUERY_THROW );
264 m_xTypeDescription.set( xTypeDescProv->getByHierarchicalName( sConstantName ), uno::UNO_QUERY_THROW );
265 uno::Sequence<
266 uno::Reference< reflection::XConstantTypeDescription > >
267 cs(m_xTypeDescription->getConstants());
268 std::sort(cs.begin(), cs.end(), CompareConstants());
269 m_aConstants = cs;
275 OUString StringRepresentation::convertSimpleToString( const uno::Any& _rValue )
277 OUString sReturn;
278 if ( m_xTypeConverter.is() && _rValue.hasValue() )
282 if ( m_aConstants.getLength() )
284 sal_Int16 nConstantValue = 0;
285 if ( _rValue >>= nConstantValue )
287 const uno::Reference< reflection::XConstantTypeDescription>* pIter = m_aConstants.getConstArray();
288 const uno::Reference< reflection::XConstantTypeDescription>* pEnd = pIter + m_aConstants.getLength();
289 for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i)
291 if ( (*pIter)->getConstantValue() == _rValue )
293 OSL_ENSURE(i < m_aValues.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
294 sReturn = m_aValues[i];
295 break;
301 if ( sReturn.isEmpty() )
302 m_xTypeConverter->convertToSimpleType( _rValue, uno::TypeClass_STRING ) >>= sReturn;
304 catch( const script::CannotConvertException& ) { }
305 catch( const lang::IllegalArgumentException& ) { }
307 return sReturn;
311 namespace
313 struct ConvertIntegerFromAndToString
315 OUString operator()( sal_Int32 _rIntValue ) const
317 return OUString::number( _rIntValue );
319 sal_Int32 operator()( const OUString& _rStringValue ) const
321 return _rStringValue.toInt32();
325 struct StringIdentity
327 OUString operator()( const OUString& _rValue ) const
329 return _rValue;
333 template < class ElementType, class Transformer >
334 OUString composeSequenceElements( const Sequence< ElementType >& _rElements, const Transformer& _rTransformer )
336 OUString sCompose;
338 // loop through the elements and concatenate the string representations of the integers
339 // (separated by a line break)
340 const ElementType* pElements = _rElements.getConstArray();
341 const ElementType* pElementsEnd = pElements + _rElements.getLength();
342 for ( ; pElements != pElementsEnd; ++pElements )
344 sCompose += OUString( _rTransformer( *pElements ) );
345 if ( pElements != pElementsEnd )
346 sCompose += "\n";
349 return sCompose;
352 template < class ElementType, class Transformer >
353 void splitComposedStringToSequence( const OUString& _rComposed, Sequence< ElementType >& _out_SplitUp, const Transformer& _rTransformer )
355 _out_SplitUp.realloc( 0 );
356 if ( _rComposed.isEmpty() )
357 return;
358 sal_Int32 tokenPos = 0;
361 _out_SplitUp.realloc( _out_SplitUp.getLength() + 1 );
362 _out_SplitUp[ _out_SplitUp.getLength() - 1 ] = static_cast<ElementType>(_rTransformer( _rComposed.getToken( 0, '\n', tokenPos ) ));
364 while ( tokenPos != -1 );
369 bool StringRepresentation::convertGenericValueToString( const uno::Any& _rValue, OUString& _rStringRep )
371 bool bCanConvert = true;
373 switch ( _rValue.getValueTypeClass() )
375 case uno::TypeClass_STRING:
376 _rValue >>= _rStringRep;
377 break;
379 case uno::TypeClass_BOOLEAN:
381 ::std::vector< OUString > aListEntries;
382 tools::StringListResource aRes(PcrRes(RID_RSC_ENUM_YESNO),aListEntries);
383 bool bValue = false;
384 _rValue >>= bValue;
385 _rStringRep = bValue ? aListEntries[1] : aListEntries[0];
387 break;
389 // some sequence types
390 case uno::TypeClass_SEQUENCE:
392 Sequence< OUString > aStringValues;
393 Sequence< sal_Int8 > aInt8Values;
394 Sequence< sal_uInt16 > aUInt16Values;
395 Sequence< sal_Int16 > aInt16Values;
396 Sequence< sal_uInt32 > aUInt32Values;
397 Sequence< sal_Int32 > aInt32Values;
399 // string sequences
400 if ( _rValue >>= aStringValues )
402 _rStringRep = composeSequenceElements( aStringValues, StringIdentity() );
404 // byte sequences
405 else if ( _rValue >>= aInt8Values )
407 _rStringRep = composeSequenceElements( aInt8Values, ConvertIntegerFromAndToString() );
409 // uInt16 sequences
410 else if ( _rValue >>= aUInt16Values )
412 _rStringRep = composeSequenceElements( aUInt16Values, ConvertIntegerFromAndToString() );
414 // Int16 sequences
415 else if ( _rValue >>= aInt16Values )
417 _rStringRep = composeSequenceElements( aInt16Values, ConvertIntegerFromAndToString() );
419 // uInt32 sequences
420 else if ( _rValue >>= aUInt32Values )
422 _rStringRep = composeSequenceElements( aUInt32Values, ConvertIntegerFromAndToString() );
424 // Int32 sequences
425 else if ( _rValue >>= aInt32Values )
427 _rStringRep = composeSequenceElements( aInt32Values, ConvertIntegerFromAndToString() );
429 else
430 bCanConvert = false;
432 break;
433 case uno::TypeClass_CONSTANT:
435 int i = 0;
436 ++i;
438 break;
440 // some structs
441 case uno::TypeClass_STRUCT:
442 OSL_FAIL( "StringRepresentation::convertGenericValueToString(STRUCT): this is dead code - isn't it?" );
443 if ( _rValue.getValueType().equals( cppu::UnoType< util::Date >::get() ))
445 // weird enough, the string representation of dates, as used
446 // by the control displaying dates, and thus as passed through the layers,
447 // is YYYYMMDD.
448 util::Date aUnoDate;
449 _rValue >>= aUnoDate;
450 _rStringRep = ::dbtools::DBTypeConversion::toDateString(aUnoDate);
452 else if ( _rValue.getValueType().equals( cppu::UnoType< util::Time >::get() ))
454 // similar for time (HHMMSSHH)
455 util::Time aUnoTime;
456 _rValue >>= aUnoTime;
457 _rStringRep = ::dbtools::DBTypeConversion::toTimeString(aUnoTime);
459 else if ( _rValue.getValueType().equals( cppu::UnoType< util::DateTime >::get() ))
461 util::DateTime aUnoDateTime;
462 _rValue >>= aUnoDateTime;
463 _rStringRep = ::dbtools::DBTypeConversion::toDateTimeString(aUnoDateTime);
465 else
466 bCanConvert = false;
467 break;
469 default:
470 bCanConvert = false;
471 break;
474 return bCanConvert;
477 uno::Any StringRepresentation::convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType )
479 uno::Any aReturn;
480 if ( m_xTypeConverter.is() && !_rValue.isEmpty() )
484 if ( m_aConstants.getLength() && m_aValues.getLength() )
486 const OUString* pIter = m_aValues.getConstArray();
487 const OUString* pEnd = pIter + m_aValues.getLength();
488 for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i)
490 if ( *pIter == _rValue )
492 OSL_ENSURE(i < m_aConstants.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
493 aReturn <<= m_aConstants[i]->getConstantValue();
494 break;
499 if ( !aReturn.hasValue() )
500 aReturn = m_xTypeConverter->convertToSimpleType( makeAny( _rValue ), _ePropertyType );
502 catch( const script::CannotConvertException& ) { }
503 catch( const lang::IllegalArgumentException& ) { }
505 return aReturn;
508 bool StringRepresentation::convertStringToGenericValue( const OUString& _rStringRep, uno::Any& _rValue, const uno::Type& _rTargetType )
510 bool bCanConvert = true;
512 switch ( _rTargetType.getTypeClass() )
514 case uno::TypeClass_STRING:
515 _rValue <<= _rStringRep;
516 break;
518 case uno::TypeClass_BOOLEAN:
520 ::std::vector< OUString > aListEntries;
521 tools::StringListResource aRes(PcrRes(RID_RSC_ENUM_YESNO),aListEntries);
522 _rValue <<= aListEntries[0] != _rStringRep;
524 break;
526 case uno::TypeClass_SEQUENCE:
528 uno::Type aElementType = ::comphelper::getSequenceElementType( _rTargetType );
530 OUString aStr( _rStringRep );
531 switch ( aElementType.getTypeClass() )
533 case uno::TypeClass_STRING:
535 Sequence< OUString > aElements;
536 splitComposedStringToSequence( aStr, aElements, StringIdentity() );
537 _rValue <<= aElements;
539 break;
540 case uno::TypeClass_SHORT:
542 Sequence< sal_Int16 > aElements;
543 splitComposedStringToSequence( aStr, aElements, ConvertIntegerFromAndToString() );
544 _rValue <<= aElements;
546 break;
547 case uno::TypeClass_UNSIGNED_SHORT:
549 Sequence< sal_uInt16 > aElements;
550 splitComposedStringToSequence( aStr, aElements, ConvertIntegerFromAndToString() );
551 _rValue <<= aElements;
553 break;
554 case uno::TypeClass_LONG:
556 Sequence< sal_Int32 > aElements;
557 splitComposedStringToSequence( aStr, aElements, ConvertIntegerFromAndToString() );
558 _rValue <<= aElements;
560 break;
561 case uno::TypeClass_UNSIGNED_LONG:
563 Sequence< sal_uInt32 > aElements;
564 splitComposedStringToSequence( aStr, aElements, ConvertIntegerFromAndToString() );
565 _rValue <<= aElements;
567 break;
568 case uno::TypeClass_BYTE:
570 Sequence< sal_Int8 > aElements;
571 splitComposedStringToSequence( aStr, aElements, ConvertIntegerFromAndToString() );
572 _rValue <<= aElements;
574 break;
575 default:
576 bCanConvert = false;
577 break;
580 break;
582 case uno::TypeClass_STRUCT:
583 OSL_FAIL( "StringRepresentation::convertStringToGenericValue(STRUCT): this is dead code - isn't it?" );
584 if ( _rTargetType.equals( cppu::UnoType< util::Date >::get() ))
586 // weird enough, the string representation of dates, as used
587 // by the control displaying dates, and thus as passed through the layers,
588 // is YYYYMMDD.
590 _rValue <<= ::dbtools::DBTypeConversion::toDate(_rStringRep);
592 else if ( _rTargetType.equals( cppu::UnoType< util::Time >::get() ))
594 // similar for time (HHMMSSHH)
595 _rValue <<= ::dbtools::DBTypeConversion::toTime(_rStringRep);
597 else if ( _rTargetType.equals( cppu::UnoType< util::DateTime >::get() ))
599 _rValue <<= ::dbtools::DBTypeConversion::toDateTime(_rStringRep);
601 else
602 bCanConvert = false;
603 break;
605 default:
606 bCanConvert = false;
607 break;
610 return bCanConvert;
614 } // pcr
618 // component helper namespace
619 namespace comp_StringRepresentation {
621 OUString SAL_CALL _getImplementationName() {
622 return OUString(
623 "StringRepresentation");
626 uno::Sequence< OUString > SAL_CALL _getSupportedServiceNames()
628 uno::Sequence< OUString > s(1);
629 s[0] = "com.sun.star.inspection.StringRepresentation";
630 return s;
633 uno::Reference< uno::XInterface > SAL_CALL _create(
634 const uno::Reference< uno::XComponentContext > & context)
636 return static_cast< ::cppu::OWeakObject * >(new pcr::StringRepresentation(context));
639 } // closing component helper namespace
642 extern "C" void SAL_CALL createRegistryInfo_StringRepresentation()
644 ::pcr::PcrModule::getInstance().registerImplementation(
645 comp_StringRepresentation::_getImplementationName(),
646 comp_StringRepresentation::_getSupportedServiceNames(),
647 comp_StringRepresentation::_create
651 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */