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 <cppuhelper/factory.hxx>
23 #include <cppuhelper/implementationentry.hxx>
24 #include <cppuhelper/implbase.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <com/sun/star/lang/XServiceInfo.hpp>
27 #include <com/sun/star/inspection/XStringRepresentation.hpp>
28 #include <com/sun/star/lang/XInitialization.hpp>
29 #include <com/sun/star/script/CannotConvertException.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 <com/sun/star/uno/XComponentContext.hpp>
38 #include <connectivity/dbconversion.hxx>
39 #include <osl/diagnose.h>
40 #include <rtl/ustrbuf.hxx>
41 #include <sal/log.hxx>
42 #include <strings.hrc>
44 #include "pcrservices.hxx"
45 #include <comphelper/types.hxx>
46 #include "modulepcr.hxx"
51 // component helper namespace
52 namespace comp_StringRepresentation
{
54 using namespace ::com::sun::star
;
56 // component and service helper functions:
57 static OUString
_getImplementationName();
58 static uno::Sequence
< OUString
> _getSupportedServiceNames();
59 static uno::Reference
< uno::XInterface
> _create( uno::Reference
< uno::XComponentContext
> const & context
);
61 } // closing component helper namespace
66 using namespace ::com::sun::star
;
67 using namespace ::com::sun::star::uno
;
69 class StringRepresentation
:
70 public ::cppu::WeakImplHelper
<
72 inspection::XStringRepresentation
,
73 lang::XInitialization
>
76 explicit StringRepresentation(uno::Reference
< uno::XComponentContext
> const & context
);
77 StringRepresentation (const StringRepresentation
&) = delete;
78 StringRepresentation
& operator=(const StringRepresentation
&) = delete;
80 // lang::XServiceInfo:
81 virtual OUString SAL_CALL
getImplementationName() override
;
82 virtual sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) override
;
83 virtual uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
85 // inspection::XStringRepresentation:
86 virtual OUString SAL_CALL
convertToControlValue(const uno::Any
& PropertyValue
) override
;
87 virtual uno::Any SAL_CALL
convertToPropertyValue(const OUString
& ControlValue
, const uno::Type
& ControlValueType
) override
;
89 // lang::XInitialization:
90 virtual void SAL_CALL
initialize(const uno::Sequence
< uno::Any
> & aArguments
) override
;
93 virtual ~StringRepresentation() override
{}
95 /** converts a generic value into a string representation
97 If you want to convert values whose string representation does not depend
98 on a concrete property, use this version
101 if and only if the value could be converted
103 static bool convertGenericValueToString(
104 const uno::Any
& _rValue
,
105 OUString
& _rStringRep
108 /** converts string representation into generic value
110 If you want to convert values whose string representation does not depend
111 on a concrete property, use this version
114 if and only if the value could be converted
116 static bool convertStringToGenericValue(
117 const OUString
& _rStringRep
,
119 const uno::Type
& _rTargetType
122 /** uses the simple convert method from the type converter
124 * \param _rValue the value to be converted
125 * \return the converted string.
127 OUString
convertSimpleToString( const uno::Any
& _rValue
);
129 /** converts a string into his constant value if it exists, otherwise the type converter is used.
130 * \param _rValue the value to be converted
131 * \param _ePropertyType the type of the property to be converted into
132 * \return the converted value
134 uno::Any
convertStringToSimple( const OUString
& _rValue
,const uno::TypeClass
& _ePropertyType
);
136 uno::Reference
< uno::XComponentContext
> m_xContext
;
137 uno::Reference
< script::XTypeConverter
> m_xTypeConverter
;
138 uno::Reference
< reflection::XConstantsTypeDescription
> m_xTypeDescription
;
139 uno::Sequence
< OUString
> m_aValues
;
140 uno::Sequence
< uno::Reference
< reflection::XConstantTypeDescription
> > m_aConstants
;
144 StringRepresentation::StringRepresentation(uno::Reference
< uno::XComponentContext
> const & context
) :
148 // com.sun.star.uno.XServiceInfo:
149 OUString SAL_CALL
StringRepresentation::getImplementationName()
151 return comp_StringRepresentation::_getImplementationName();
154 sal_Bool SAL_CALL
StringRepresentation::supportsService(OUString
const & serviceName
)
156 return cppu::supportsService(this, serviceName
);
159 uno::Sequence
< OUString
> SAL_CALL
StringRepresentation::getSupportedServiceNames()
161 return comp_StringRepresentation::_getSupportedServiceNames();
164 // inspection::XStringRepresentation:
165 OUString SAL_CALL
StringRepresentation::convertToControlValue(const uno::Any
& PropertyValue
)
168 if ( !convertGenericValueToString( PropertyValue
, sReturn
) )
170 sReturn
= convertSimpleToString( PropertyValue
);
172 if ( sReturn
.isEmpty() && PropertyValue
.hasValue() )
174 SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertPropertyValueToStringRepresentation: cannot convert values of type '"
175 << PropertyValue
.getValueType().getTypeName()
184 uno::Any SAL_CALL
StringRepresentation::convertToPropertyValue(const OUString
& ControlValue
, const uno::Type
& ControlValueType
)
188 uno::TypeClass ePropertyType
= ControlValueType
.getTypeClass();
189 switch ( ePropertyType
)
191 case uno::TypeClass_FLOAT
:
192 case uno::TypeClass_DOUBLE
:
193 case uno::TypeClass_BYTE
:
194 case uno::TypeClass_SHORT
:
195 case uno::TypeClass_LONG
:
196 case uno::TypeClass_HYPER
:
197 case uno::TypeClass_UNSIGNED_SHORT
:
198 case uno::TypeClass_UNSIGNED_LONG
:
199 case uno::TypeClass_UNSIGNED_HYPER
:
202 aReturn
= convertStringToSimple(ControlValue
, ePropertyType
);
204 catch( const script::CannotConvertException
& ) { }
205 catch( const lang::IllegalArgumentException
& ) { }
209 #if OSL_DEBUG_LEVEL > 0
212 convertStringToGenericValue( ControlValue
, aReturn
, ControlValueType
);
214 #if OSL_DEBUG_LEVEL > 0
215 // could not convert ...
216 if ( !bCanConvert
&& !ControlValue
.isEmpty() )
218 SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertStringRepresentationToPropertyValue: cannot convert into values of type '"
219 << ControlValueType
.getTypeName() << "'!" );
229 // This comparison functor assumes an underlying set of constants with pairwise
230 // unequal values that are all of UNO SHORT or LONG type:
231 struct CompareConstants
{
233 css::uno::Reference
< css::reflection::XConstantTypeDescription
> const &
235 css::uno::Reference
< css::reflection::XConstantTypeDescription
> const &
238 return c1
->getConstantValue().get
<sal_Int32
>()
239 < c2
->getConstantValue().get
<sal_Int32
>();
245 // lang::XInitialization:
246 void SAL_CALL
StringRepresentation::initialize(const uno::Sequence
< uno::Any
> & aArguments
)
248 sal_Int32 nLength
= aArguments
.getLength();
251 const uno::Any
* pIter
= aArguments
.getConstArray();
252 m_xTypeConverter
.set(*pIter
++,uno::UNO_QUERY
);
255 OUString sConstantName
;
256 *pIter
++ >>= sConstantName
;
257 *pIter
>>= m_aValues
;
259 if ( m_xContext
.is() )
261 uno::Reference
< container::XHierarchicalNameAccess
> xTypeDescProv(
262 m_xContext
->getValueByName("/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
263 uno::UNO_QUERY_THROW
);
265 m_xTypeDescription
.set( xTypeDescProv
->getByHierarchicalName( sConstantName
), uno::UNO_QUERY_THROW
);
267 uno::Reference
< reflection::XConstantTypeDescription
> >
268 cs(m_xTypeDescription
->getConstants());
269 std::sort(cs
.begin(), cs
.end(), CompareConstants());
276 OUString
StringRepresentation::convertSimpleToString( const uno::Any
& _rValue
)
279 if ( m_xTypeConverter
.is() && _rValue
.hasValue() )
283 if ( m_aConstants
.hasElements() )
285 sal_Int16 nConstantValue
= 0;
286 if ( _rValue
>>= nConstantValue
)
288 const uno::Reference
< reflection::XConstantTypeDescription
>* pIter
= m_aConstants
.getConstArray();
289 const uno::Reference
< reflection::XConstantTypeDescription
>* pEnd
= pIter
+ m_aConstants
.getLength();
290 for(sal_Int32 i
= 0;pIter
!= pEnd
;++pIter
,++i
)
292 if ( (*pIter
)->getConstantValue() == _rValue
)
294 OSL_ENSURE(i
< m_aValues
.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
295 sReturn
= m_aValues
[i
];
302 if ( sReturn
.isEmpty() )
303 m_xTypeConverter
->convertToSimpleType( _rValue
, uno::TypeClass_STRING
) >>= sReturn
;
305 catch( const script::CannotConvertException
& ) { }
306 catch( const lang::IllegalArgumentException
& ) { }
314 struct ConvertIntegerFromAndToString
316 OUString
operator()( sal_Int32 _rIntValue
) const
318 return OUString::number( _rIntValue
);
320 sal_Int32
operator()( const OUString
& _rStringValue
) const
322 return _rStringValue
.toInt32();
326 struct StringIdentity
328 OUString
operator()( const OUString
& _rValue
) const
334 template < class ElementType
, class Transformer
>
335 OUString
composeSequenceElements( const Sequence
< ElementType
>& _rElements
, const Transformer
& _rTransformer
)
337 OUStringBuffer sCompose
;
339 // loop through the elements and concatenate the string representations of the integers
340 // (separated by a line break)
341 for (const auto& rElement
: _rElements
)
343 sCompose
.append(OUString(_rTransformer(rElement
)));
344 sCompose
.append("\n");
346 sCompose
.stripEnd('\n');
348 return sCompose
.makeStringAndClear();
351 template < class ElementType
, class Transformer
>
352 void splitComposedStringToSequence( const OUString
& _rComposed
, Sequence
< ElementType
>& _out_SplitUp
, const Transformer
& _rTransformer
)
354 _out_SplitUp
.realloc( 0 );
355 if ( _rComposed
.isEmpty() )
357 sal_Int32 tokenPos
= 0;
360 _out_SplitUp
.realloc( _out_SplitUp
.getLength() + 1 );
361 _out_SplitUp
[ _out_SplitUp
.getLength() - 1 ] = static_cast<ElementType
>(_rTransformer( _rComposed
.getToken( 0, '\n', tokenPos
) ));
363 while ( tokenPos
!= -1 );
368 bool StringRepresentation::convertGenericValueToString( const uno::Any
& _rValue
, OUString
& _rStringRep
)
370 bool bCanConvert
= true;
372 switch ( _rValue
.getValueTypeClass() )
374 case uno::TypeClass_STRING
:
375 _rValue
>>= _rStringRep
;
378 case uno::TypeClass_BOOLEAN
:
382 _rStringRep
= bValue
? PcrRes(RID_RSC_ENUM_YESNO
[1])
383 : PcrRes(RID_RSC_ENUM_YESNO
[0]);
387 // some sequence types
388 case uno::TypeClass_SEQUENCE
:
390 Sequence
< OUString
> aStringValues
;
391 Sequence
< sal_Int8
> aInt8Values
;
392 Sequence
< sal_uInt16
> aUInt16Values
;
393 Sequence
< sal_Int16
> aInt16Values
;
394 Sequence
< sal_uInt32
> aUInt32Values
;
395 Sequence
< sal_Int32
> aInt32Values
;
398 if ( _rValue
>>= aStringValues
)
400 _rStringRep
= composeSequenceElements( aStringValues
, StringIdentity() );
403 else if ( _rValue
>>= aInt8Values
)
405 _rStringRep
= composeSequenceElements( aInt8Values
, ConvertIntegerFromAndToString() );
408 else if ( _rValue
>>= aUInt16Values
)
410 _rStringRep
= composeSequenceElements( aUInt16Values
, ConvertIntegerFromAndToString() );
413 else if ( _rValue
>>= aInt16Values
)
415 _rStringRep
= composeSequenceElements( aInt16Values
, ConvertIntegerFromAndToString() );
418 else if ( _rValue
>>= aUInt32Values
)
420 _rStringRep
= composeSequenceElements( aUInt32Values
, ConvertIntegerFromAndToString() );
423 else if ( _rValue
>>= aInt32Values
)
425 _rStringRep
= composeSequenceElements( aInt32Values
, ConvertIntegerFromAndToString() );
431 case uno::TypeClass_CONSTANT
:
439 case uno::TypeClass_STRUCT
:
440 OSL_FAIL( "StringRepresentation::convertGenericValueToString(STRUCT): this is dead code - isn't it?" );
441 if ( _rValue
.getValueType().equals( cppu::UnoType
< util::Date
>::get() ))
443 // weird enough, the string representation of dates, as used
444 // by the control displaying dates, and thus as passed through the layers,
447 _rValue
>>= aUnoDate
;
448 _rStringRep
= ::dbtools::DBTypeConversion::toDateString(aUnoDate
);
450 else if ( _rValue
.getValueType().equals( cppu::UnoType
< util::Time
>::get() ))
452 // similar for time (HHMMSSHH)
454 _rValue
>>= aUnoTime
;
455 _rStringRep
= ::dbtools::DBTypeConversion::toTimeString(aUnoTime
);
457 else if ( _rValue
.getValueType().equals( cppu::UnoType
< util::DateTime
>::get() ))
459 util::DateTime aUnoDateTime
;
460 _rValue
>>= aUnoDateTime
;
461 _rStringRep
= ::dbtools::DBTypeConversion::toDateTimeString(aUnoDateTime
);
475 uno::Any
StringRepresentation::convertStringToSimple( const OUString
& _rValue
,const uno::TypeClass
& _ePropertyType
)
478 if ( m_xTypeConverter
.is() && !_rValue
.isEmpty() )
482 if ( m_aConstants
.hasElements() && m_aValues
.hasElements() )
484 const OUString
* pIter
= m_aValues
.getConstArray();
485 const OUString
* pEnd
= pIter
+ m_aValues
.getLength();
486 for(sal_Int32 i
= 0;pIter
!= pEnd
;++pIter
,++i
)
488 if ( *pIter
== _rValue
)
490 OSL_ENSURE(i
< m_aConstants
.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
491 aReturn
= m_aConstants
[i
]->getConstantValue();
497 if ( !aReturn
.hasValue() )
498 aReturn
= m_xTypeConverter
->convertToSimpleType( makeAny( _rValue
), _ePropertyType
);
500 catch( const script::CannotConvertException
& ) { }
501 catch( const lang::IllegalArgumentException
& ) { }
506 bool StringRepresentation::convertStringToGenericValue( const OUString
& _rStringRep
, uno::Any
& _rValue
, const uno::Type
& _rTargetType
)
508 bool bCanConvert
= true;
510 switch ( _rTargetType
.getTypeClass() )
512 case uno::TypeClass_STRING
:
513 _rValue
<<= _rStringRep
;
516 case uno::TypeClass_BOOLEAN
:
518 _rValue
<<= PcrRes(RID_RSC_ENUM_YESNO
[0]) != _rStringRep
;
522 case uno::TypeClass_SEQUENCE
:
524 uno::Type aElementType
= ::comphelper::getSequenceElementType( _rTargetType
);
526 switch ( aElementType
.getTypeClass() )
528 case uno::TypeClass_STRING
:
530 Sequence
< OUString
> aElements
;
531 splitComposedStringToSequence( _rStringRep
, aElements
, StringIdentity() );
532 _rValue
<<= aElements
;
535 case uno::TypeClass_SHORT
:
537 Sequence
< sal_Int16
> aElements
;
538 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
539 _rValue
<<= aElements
;
542 case uno::TypeClass_UNSIGNED_SHORT
:
544 Sequence
< sal_uInt16
> aElements
;
545 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
546 _rValue
<<= aElements
;
549 case uno::TypeClass_LONG
:
551 Sequence
< sal_Int32
> aElements
;
552 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
553 _rValue
<<= aElements
;
556 case uno::TypeClass_UNSIGNED_LONG
:
558 Sequence
< sal_uInt32
> aElements
;
559 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
560 _rValue
<<= aElements
;
563 case uno::TypeClass_BYTE
:
565 Sequence
< sal_Int8
> aElements
;
566 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
567 _rValue
<<= aElements
;
577 case uno::TypeClass_STRUCT
:
578 OSL_FAIL( "StringRepresentation::convertStringToGenericValue(STRUCT): this is dead code - isn't it?" );
579 if ( _rTargetType
.equals( cppu::UnoType
< util::Date
>::get() ))
581 // weird enough, the string representation of dates, as used
582 // by the control displaying dates, and thus as passed through the layers,
585 _rValue
<<= ::dbtools::DBTypeConversion::toDate(_rStringRep
);
587 else if ( _rTargetType
.equals( cppu::UnoType
< util::Time
>::get() ))
589 // similar for time (HHMMSSHH)
590 _rValue
<<= ::dbtools::DBTypeConversion::toTime(_rStringRep
);
592 else if ( _rTargetType
.equals( cppu::UnoType
< util::DateTime
>::get() ))
594 _rValue
<<= ::dbtools::DBTypeConversion::toDateTime(_rStringRep
);
612 // component helper namespace
613 namespace comp_StringRepresentation
{
615 OUString
_getImplementationName() {
617 "StringRepresentation";
620 uno::Sequence
< OUString
> _getSupportedServiceNames()
622 uno::Sequence
< OUString
> s
{ "com.sun.star.inspection.StringRepresentation" };
626 uno::Reference
< uno::XInterface
> _create(
627 const uno::Reference
< uno::XComponentContext
> & context
)
629 return static_cast< ::cppu::OWeakObject
* >(new pcr::StringRepresentation(context
));
632 } // closing component helper namespace
635 extern "C" void createRegistryInfo_StringRepresentation()
637 ::pcr::PcrModule::getInstance().registerImplementation(
638 comp_StringRepresentation::_getImplementationName(),
639 comp_StringRepresentation::_getSupportedServiceNames(),
640 comp_StringRepresentation::_create
644 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */