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/implbase.hxx>
23 #include <cppuhelper/supportsservice.hxx>
24 #include <com/sun/star/lang/IllegalArgumentException.hpp>
25 #include <com/sun/star/lang/XServiceInfo.hpp>
26 #include <com/sun/star/inspection/XStringRepresentation.hpp>
27 #include <com/sun/star/lang/XInitialization.hpp>
28 #include <com/sun/star/script/CannotConvertException.hpp>
29 #include <com/sun/star/script/XTypeConverter.hpp>
30 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
31 #include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
32 #include <com/sun/star/util/DateTime.hpp>
33 #include <com/sun/star/util/Date.hpp>
34 #include <com/sun/star/util/Time.hpp>
35 #include <com/sun/star/uno/XComponentContext.hpp>
36 #include <connectivity/dbconversion.hxx>
37 #include <osl/diagnose.h>
38 #include <rtl/ustrbuf.hxx>
39 #include <sal/log.hxx>
42 #include <comphelper/types.hxx>
43 #include <o3tl/string_view.hxx>
44 #include "modulepcr.hxx"
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::uno
;
55 class StringRepresentation
:
56 public ::cppu::WeakImplHelper
<
58 inspection::XStringRepresentation
,
59 lang::XInitialization
>
62 explicit StringRepresentation(uno::Reference
< uno::XComponentContext
> context
);
63 StringRepresentation (const StringRepresentation
&) = delete;
64 StringRepresentation
& operator=(const StringRepresentation
&) = delete;
66 // lang::XServiceInfo:
67 virtual OUString SAL_CALL
getImplementationName() override
;
68 virtual sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) override
;
69 virtual uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
71 // inspection::XStringRepresentation:
72 virtual OUString SAL_CALL
convertToControlValue(const uno::Any
& PropertyValue
) override
;
73 virtual uno::Any SAL_CALL
convertToPropertyValue(const OUString
& ControlValue
, const uno::Type
& ControlValueType
) override
;
75 // lang::XInitialization:
76 virtual void SAL_CALL
initialize(const uno::Sequence
< uno::Any
> & aArguments
) override
;
79 virtual ~StringRepresentation() override
{}
81 /** converts a generic value into a string representation
83 If you want to convert values whose string representation does not depend
84 on a concrete property, use this version
87 if and only if the value could be converted
89 static bool convertGenericValueToString(
90 const uno::Any
& _rValue
,
94 /** converts string representation into generic value
96 If you want to convert values whose string representation does not depend
97 on a concrete property, use this version
100 if and only if the value could be converted
102 static bool convertStringToGenericValue(
103 const OUString
& _rStringRep
,
105 const uno::Type
& _rTargetType
108 /** uses the simple convert method from the type converter
110 * \param _rValue the value to be converted
111 * \return the converted string.
113 OUString
convertSimpleToString( const uno::Any
& _rValue
);
115 /** converts a string into his constant value if it exists, otherwise the type converter is used.
116 * \param _rValue the value to be converted
117 * \param _ePropertyType the type of the property to be converted into
118 * \return the converted value
120 uno::Any
convertStringToSimple( const OUString
& _rValue
,const uno::TypeClass
& _ePropertyType
);
122 uno::Reference
< uno::XComponentContext
> m_xContext
;
123 uno::Reference
< script::XTypeConverter
> m_xTypeConverter
;
124 uno::Reference
< reflection::XConstantsTypeDescription
> m_xTypeDescription
;
125 uno::Sequence
< OUString
> m_aValues
;
126 uno::Sequence
< uno::Reference
< reflection::XConstantTypeDescription
> > m_aConstants
;
132 StringRepresentation::StringRepresentation(uno::Reference
< uno::XComponentContext
> context
) :
133 m_xContext(std::move(context
))
136 // com.sun.star.uno.XServiceInfo:
137 OUString SAL_CALL
StringRepresentation::getImplementationName()
139 return u
"StringRepresentation"_ustr
;
142 sal_Bool SAL_CALL
StringRepresentation::supportsService(OUString
const & serviceName
)
144 return cppu::supportsService(this, serviceName
);
147 uno::Sequence
< OUString
> SAL_CALL
StringRepresentation::getSupportedServiceNames()
149 return { u
"com.sun.star.inspection.StringRepresentation"_ustr
};
152 // inspection::XStringRepresentation:
153 OUString SAL_CALL
StringRepresentation::convertToControlValue(const uno::Any
& PropertyValue
)
156 if ( !convertGenericValueToString( PropertyValue
, sReturn
) )
158 sReturn
= convertSimpleToString( PropertyValue
);
160 if ( sReturn
.isEmpty() && PropertyValue
.hasValue() )
162 SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertPropertyValueToStringRepresentation: cannot convert values of type '"
163 << PropertyValue
.getValueTypeName()
172 uno::Any SAL_CALL
StringRepresentation::convertToPropertyValue(const OUString
& ControlValue
, const uno::Type
& ControlValueType
)
176 uno::TypeClass ePropertyType
= ControlValueType
.getTypeClass();
177 switch ( ePropertyType
)
179 case uno::TypeClass_FLOAT
:
180 case uno::TypeClass_DOUBLE
:
181 case uno::TypeClass_BYTE
:
182 case uno::TypeClass_SHORT
:
183 case uno::TypeClass_LONG
:
184 case uno::TypeClass_HYPER
:
185 case uno::TypeClass_UNSIGNED_SHORT
:
186 case uno::TypeClass_UNSIGNED_LONG
:
187 case uno::TypeClass_UNSIGNED_HYPER
:
190 aReturn
= convertStringToSimple(ControlValue
, ePropertyType
);
192 catch( const script::CannotConvertException
& ) { }
193 catch( const lang::IllegalArgumentException
& ) { }
197 #if OSL_DEBUG_LEVEL > 0
200 convertStringToGenericValue( ControlValue
, aReturn
, ControlValueType
);
202 #if OSL_DEBUG_LEVEL > 0
203 // could not convert ...
204 if ( !bCanConvert
&& !ControlValue
.isEmpty() )
206 SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertStringRepresentationToPropertyValue: cannot convert into values of type '"
207 << ControlValueType
.getTypeName() << "'!" );
217 // This comparison functor assumes an underlying set of constants with pairwise
218 // unequal values that are all of UNO SHORT or LONG type:
219 struct CompareConstants
{
221 css::uno::Reference
< css::reflection::XConstantTypeDescription
> const &
223 css::uno::Reference
< css::reflection::XConstantTypeDescription
> const &
226 return c1
->getConstantValue().get
<sal_Int32
>()
227 < c2
->getConstantValue().get
<sal_Int32
>();
233 // lang::XInitialization:
234 void SAL_CALL
StringRepresentation::initialize(const uno::Sequence
< uno::Any
> & aArguments
)
236 sal_Int32 nLength
= aArguments
.getLength();
240 const uno::Any
* pIter
= aArguments
.getConstArray();
241 m_xTypeConverter
.set(*pIter
++,uno::UNO_QUERY
);
245 OUString sConstantName
;
246 *pIter
++ >>= sConstantName
;
247 *pIter
>>= m_aValues
;
249 if ( !m_xContext
.is() )
252 uno::Reference
< container::XHierarchicalNameAccess
> xTypeDescProv(
253 m_xContext
->getValueByName(u
"/singletons/com.sun.star.reflection.theTypeDescriptionManager"_ustr
),
254 uno::UNO_QUERY_THROW
);
256 m_xTypeDescription
.set( xTypeDescProv
->getByHierarchicalName( sConstantName
), uno::UNO_QUERY_THROW
);
258 uno::Reference
< reflection::XConstantTypeDescription
> >
259 cs(m_xTypeDescription
->getConstants());
260 auto [begin
, end
] = asNonConstRange(cs
);
261 std::sort(begin
, end
, CompareConstants());
262 m_aConstants
= std::move(cs
);
265 OUString
StringRepresentation::convertSimpleToString( const uno::Any
& _rValue
)
268 if ( m_xTypeConverter
.is() && _rValue
.hasValue() )
272 if ( m_aConstants
.hasElements() )
274 sal_Int16 nConstantValue
= 0;
275 if ( _rValue
>>= nConstantValue
)
277 const uno::Reference
< reflection::XConstantTypeDescription
>* pIter
= m_aConstants
.getConstArray();
278 const uno::Reference
< reflection::XConstantTypeDescription
>* pEnd
= pIter
+ m_aConstants
.getLength();
279 for(sal_Int32 i
= 0;pIter
!= pEnd
;++pIter
,++i
)
281 if ( (*pIter
)->getConstantValue() == _rValue
)
283 OSL_ENSURE(i
< m_aValues
.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
284 sReturn
= m_aValues
[i
];
291 if ( sReturn
.isEmpty() )
292 m_xTypeConverter
->convertToSimpleType( _rValue
, uno::TypeClass_STRING
) >>= sReturn
;
294 catch( const script::CannotConvertException
& ) { }
295 catch( const lang::IllegalArgumentException
& ) { }
303 struct ConvertIntegerFromAndToString
305 OUString
operator()( sal_Int32 _rIntValue
) const
307 return OUString::number( _rIntValue
);
309 sal_Int32
operator()( std::u16string_view _rStringValue
) const
311 return o3tl::toInt32(_rStringValue
);
315 struct StringIdentity
317 OUString
operator()( const OUString
& _rValue
) const
323 template < class ElementType
, class Transformer
>
324 OUString
composeSequenceElements( const Sequence
< ElementType
>& _rElements
, const Transformer
& _rTransformer
)
326 OUStringBuffer sCompose
;
328 // loop through the elements and concatenate the string representations of the integers
329 // (separated by a line break)
330 for (const auto& rElement
: _rElements
)
332 sCompose
.append(OUString(_rTransformer(rElement
)) + "\n");
334 sCompose
.stripEnd('\n');
336 return sCompose
.makeStringAndClear();
339 template < class ElementType
, class Transformer
>
340 void splitComposedStringToSequence( std::u16string_view _rComposed
, Sequence
< ElementType
>& _out_SplitUp
, const Transformer
& _rTransformer
)
342 _out_SplitUp
.realloc( 0 );
343 if ( _rComposed
.empty() )
345 sal_Int32 tokenPos
= 0;
348 _out_SplitUp
.realloc( _out_SplitUp
.getLength() + 1 );
349 _out_SplitUp
.getArray()[ _out_SplitUp
.getLength() - 1 ] = static_cast<ElementType
>(_rTransformer( OUString(o3tl::getToken(_rComposed
, 0, '\n', tokenPos
)) ));
351 while ( tokenPos
!= -1 );
356 bool StringRepresentation::convertGenericValueToString( const uno::Any
& _rValue
, OUString
& _rStringRep
)
358 bool bCanConvert
= true;
360 switch ( _rValue
.getValueTypeClass() )
362 case uno::TypeClass_STRING
:
363 _rValue
>>= _rStringRep
;
366 case uno::TypeClass_BOOLEAN
:
370 _rStringRep
= bValue
? PcrRes(RID_RSC_ENUM_YESNO
[1])
371 : PcrRes(RID_RSC_ENUM_YESNO
[0]);
375 // some sequence types
376 case uno::TypeClass_SEQUENCE
:
378 Sequence
< OUString
> aStringValues
;
379 Sequence
< sal_Int8
> aInt8Values
;
380 Sequence
< sal_uInt16
> aUInt16Values
;
381 Sequence
< sal_Int16
> aInt16Values
;
382 Sequence
< sal_uInt32
> aUInt32Values
;
383 Sequence
< sal_Int32
> aInt32Values
;
386 if ( _rValue
>>= aStringValues
)
388 _rStringRep
= composeSequenceElements( aStringValues
, StringIdentity() );
391 else if ( _rValue
>>= aInt8Values
)
393 _rStringRep
= composeSequenceElements( aInt8Values
, ConvertIntegerFromAndToString() );
396 else if ( _rValue
>>= aUInt16Values
)
398 _rStringRep
= composeSequenceElements( aUInt16Values
, ConvertIntegerFromAndToString() );
401 else if ( _rValue
>>= aInt16Values
)
403 _rStringRep
= composeSequenceElements( aInt16Values
, ConvertIntegerFromAndToString() );
406 else if ( _rValue
>>= aUInt32Values
)
408 _rStringRep
= composeSequenceElements( aUInt32Values
, ConvertIntegerFromAndToString() );
411 else if ( _rValue
>>= aInt32Values
)
413 _rStringRep
= composeSequenceElements( aInt32Values
, ConvertIntegerFromAndToString() );
419 case uno::TypeClass_CONSTANT
:
423 case uno::TypeClass_STRUCT
:
424 OSL_FAIL( "StringRepresentation::convertGenericValueToString(STRUCT): this is dead code - isn't it?" );
425 if ( _rValue
.getValueType().equals( cppu::UnoType
< util::Date
>::get() ))
427 // weird enough, the string representation of dates, as used
428 // by the control displaying dates, and thus as passed through the layers,
431 _rValue
>>= aUnoDate
;
432 _rStringRep
= ::dbtools::DBTypeConversion::toDateString(aUnoDate
);
434 else if ( _rValue
.getValueType().equals( cppu::UnoType
< util::Time
>::get() ))
436 // similar for time (HHMMSSHH)
438 _rValue
>>= aUnoTime
;
439 _rStringRep
= ::dbtools::DBTypeConversion::toTimeString(aUnoTime
);
441 else if ( _rValue
.getValueType().equals( cppu::UnoType
< util::DateTime
>::get() ))
443 util::DateTime aUnoDateTime
;
444 _rValue
>>= aUnoDateTime
;
445 _rStringRep
= ::dbtools::DBTypeConversion::toDateTimeString(aUnoDateTime
);
459 uno::Any
StringRepresentation::convertStringToSimple( const OUString
& _rValue
,const uno::TypeClass
& _ePropertyType
)
462 if ( m_xTypeConverter
.is() && !_rValue
.isEmpty() )
466 if ( m_aConstants
.hasElements() && m_aValues
.hasElements() )
468 const OUString
* pIter
= m_aValues
.getConstArray();
469 const OUString
* pEnd
= pIter
+ m_aValues
.getLength();
470 for(sal_Int32 i
= 0;pIter
!= pEnd
;++pIter
,++i
)
472 if ( *pIter
== _rValue
)
474 OSL_ENSURE(i
< m_aConstants
.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
475 aReturn
= m_aConstants
[i
]->getConstantValue();
481 if ( !aReturn
.hasValue() )
482 aReturn
= m_xTypeConverter
->convertToSimpleType( Any( _rValue
), _ePropertyType
);
484 catch( const script::CannotConvertException
& ) { }
485 catch( const lang::IllegalArgumentException
& ) { }
490 bool StringRepresentation::convertStringToGenericValue( const OUString
& _rStringRep
, uno::Any
& _rValue
, const uno::Type
& _rTargetType
)
492 bool bCanConvert
= true;
494 switch ( _rTargetType
.getTypeClass() )
496 case uno::TypeClass_STRING
:
497 _rValue
<<= _rStringRep
;
500 case uno::TypeClass_BOOLEAN
:
502 _rValue
<<= PcrRes(RID_RSC_ENUM_YESNO
[0]) != _rStringRep
;
506 case uno::TypeClass_SEQUENCE
:
508 uno::Type aElementType
= ::comphelper::getSequenceElementType( _rTargetType
);
510 switch ( aElementType
.getTypeClass() )
512 case uno::TypeClass_STRING
:
514 Sequence
< OUString
> aElements
;
515 splitComposedStringToSequence( _rStringRep
, aElements
, StringIdentity() );
516 _rValue
<<= aElements
;
519 case uno::TypeClass_SHORT
:
521 Sequence
< sal_Int16
> aElements
;
522 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
523 _rValue
<<= aElements
;
526 case uno::TypeClass_UNSIGNED_SHORT
:
528 Sequence
< sal_uInt16
> aElements
;
529 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
530 _rValue
<<= aElements
;
533 case uno::TypeClass_LONG
:
535 Sequence
< sal_Int32
> aElements
;
536 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
537 _rValue
<<= aElements
;
540 case uno::TypeClass_UNSIGNED_LONG
:
542 Sequence
< sal_uInt32
> aElements
;
543 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
544 _rValue
<<= aElements
;
547 case uno::TypeClass_BYTE
:
549 Sequence
< sal_Int8
> aElements
;
550 splitComposedStringToSequence( _rStringRep
, aElements
, ConvertIntegerFromAndToString() );
551 _rValue
<<= aElements
;
561 case uno::TypeClass_STRUCT
:
562 OSL_FAIL( "StringRepresentation::convertStringToGenericValue(STRUCT): this is dead code - isn't it?" );
563 if ( _rTargetType
.equals( cppu::UnoType
< util::Date
>::get() ))
565 // weird enough, the string representation of dates, as used
566 // by the control displaying dates, and thus as passed through the layers,
569 _rValue
<<= ::dbtools::DBTypeConversion::toDate(_rStringRep
);
571 else if ( _rTargetType
.equals( cppu::UnoType
< util::Time
>::get() ))
573 // similar for time (HHMMSSHH)
574 _rValue
<<= ::dbtools::DBTypeConversion::toTime(_rStringRep
);
576 else if ( _rTargetType
.equals( cppu::UnoType
< util::DateTime
>::get() ))
578 _rValue
<<= ::dbtools::DBTypeConversion::toDateTime(_rStringRep
);
596 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
597 extensions_propctrlr_StringRepresentation_get_implementation(
598 css::uno::XComponentContext
* context
, css::uno::Sequence
<css::uno::Any
> const&)
600 return cppu::acquire(new pcr::StringRepresentation(context
));
604 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */