1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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
63 using namespace ::com::sun::star
;
64 using namespace ::com::sun::star::uno
;
66 class StringRepresentation
:
67 public ::cppu::WeakImplHelper3
<
69 inspection::XStringRepresentation
,
70 lang::XInitialization
>,
71 private boost::noncopyable
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
;
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
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
110 if and only if the value could be converted
112 static bool convertStringToGenericValue(
113 const OUString
& _rStringRep
,
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
) :
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
)
164 if ( !convertGenericValueToString( PropertyValue
, sReturn
) )
166 sReturn
= convertSimpleToString( PropertyValue
);
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() );
181 uno::Any SAL_CALL
StringRepresentation::convertToPropertyValue(const OUString
& ControlValue
, const uno::Type
& ControlValueType
) throw (uno::RuntimeException
, uno::Exception
, std::exception
)
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
& ) { }
206 #if OSL_DEBUG_LEVEL > 0
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() );
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
{
232 css::uno::Reference
< css::reflection::XConstantTypeDescription
> const &
234 css::uno::Reference
< css::reflection::XConstantTypeDescription
> 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();
250 const uno::Any
* pIter
= aArguments
.getConstArray();
251 m_xTypeConverter
.set(*pIter
++,uno::UNO_QUERY
);
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
);
266 uno::Reference
< reflection::XConstantTypeDescription
> >
267 cs(m_xTypeDescription
->getConstants());
268 std::sort(cs
.begin(), cs
.end(), CompareConstants());
275 OUString
StringRepresentation::convertSimpleToString( const uno::Any
& _rValue
)
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
];
301 if ( sReturn
.isEmpty() )
302 m_xTypeConverter
->convertToSimpleType( _rValue
, uno::TypeClass_STRING
) >>= sReturn
;
304 catch( const script::CannotConvertException
& ) { }
305 catch( const lang::IllegalArgumentException
& ) { }
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
333 template < class ElementType
, class Transformer
>
334 OUString
composeSequenceElements( const Sequence
< ElementType
>& _rElements
, const Transformer
& _rTransformer
)
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
)
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() )
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
;
379 case uno::TypeClass_BOOLEAN
:
381 ::std::vector
< OUString
> aListEntries
;
382 tools::StringListResource
aRes(PcrRes(RID_RSC_ENUM_YESNO
),aListEntries
);
385 _rStringRep
= bValue
? aListEntries
[1] : aListEntries
[0];
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
;
400 if ( _rValue
>>= aStringValues
)
402 _rStringRep
= composeSequenceElements( aStringValues
, StringIdentity() );
405 else if ( _rValue
>>= aInt8Values
)
407 _rStringRep
= composeSequenceElements( aInt8Values
, ConvertIntegerFromAndToString() );
410 else if ( _rValue
>>= aUInt16Values
)
412 _rStringRep
= composeSequenceElements( aUInt16Values
, ConvertIntegerFromAndToString() );
415 else if ( _rValue
>>= aInt16Values
)
417 _rStringRep
= composeSequenceElements( aInt16Values
, ConvertIntegerFromAndToString() );
420 else if ( _rValue
>>= aUInt32Values
)
422 _rStringRep
= composeSequenceElements( aUInt32Values
, ConvertIntegerFromAndToString() );
425 else if ( _rValue
>>= aInt32Values
)
427 _rStringRep
= composeSequenceElements( aInt32Values
, ConvertIntegerFromAndToString() );
433 case uno::TypeClass_CONSTANT
:
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,
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)
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
);
477 uno::Any
StringRepresentation::convertStringToSimple( const OUString
& _rValue
,const uno::TypeClass
& _ePropertyType
)
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();
499 if ( !aReturn
.hasValue() )
500 aReturn
= m_xTypeConverter
->convertToSimpleType( makeAny( _rValue
), _ePropertyType
);
502 catch( const script::CannotConvertException
& ) { }
503 catch( const lang::IllegalArgumentException
& ) { }
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
;
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
;
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
;
540 case uno::TypeClass_SHORT
:
542 Sequence
< sal_Int16
> aElements
;
543 splitComposedStringToSequence( aStr
, aElements
, ConvertIntegerFromAndToString() );
544 _rValue
<<= aElements
;
547 case uno::TypeClass_UNSIGNED_SHORT
:
549 Sequence
< sal_uInt16
> aElements
;
550 splitComposedStringToSequence( aStr
, aElements
, ConvertIntegerFromAndToString() );
551 _rValue
<<= aElements
;
554 case uno::TypeClass_LONG
:
556 Sequence
< sal_Int32
> aElements
;
557 splitComposedStringToSequence( aStr
, aElements
, ConvertIntegerFromAndToString() );
558 _rValue
<<= aElements
;
561 case uno::TypeClass_UNSIGNED_LONG
:
563 Sequence
< sal_uInt32
> aElements
;
564 splitComposedStringToSequence( aStr
, aElements
, ConvertIntegerFromAndToString() );
565 _rValue
<<= aElements
;
568 case uno::TypeClass_BYTE
:
570 Sequence
< sal_Int8
> aElements
;
571 splitComposedStringToSequence( aStr
, aElements
, ConvertIntegerFromAndToString() );
572 _rValue
<<= aElements
;
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,
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
);
618 // component helper namespace
619 namespace comp_StringRepresentation
{
621 OUString SAL_CALL
_getImplementationName() {
623 "StringRepresentation");
626 uno::Sequence
< OUString
> SAL_CALL
_getSupportedServiceNames()
628 uno::Sequence
< OUString
> s(1);
629 s
[0] = "com.sun.star.inspection.StringRepresentation";
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: */