tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / extensions / source / propctrlr / stringrepresentation.cxx
blob673ddd5dca27c210ff6d211dbe4bd9b552ba2778
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 <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>
40 #include <utility>
41 #include <yesno.hrc>
42 #include <comphelper/types.hxx>
43 #include <o3tl/string_view.hxx>
44 #include "modulepcr.hxx"
46 #include <algorithm>
48 namespace pcr{
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
53 namespace {
55 class StringRepresentation:
56 public ::cppu::WeakImplHelper<
57 lang::XServiceInfo,
58 inspection::XStringRepresentation,
59 lang::XInitialization>
61 public:
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;
78 private:
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
86 @return <TRUE/>
87 if and only if the value could be converted
89 static bool convertGenericValueToString(
90 const uno::Any& _rValue,
91 OUString& _rStringRep
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
99 @return <TRUE/>
100 if and only if the value could be converted
102 static bool convertStringToGenericValue(
103 const OUString& _rStringRep,
104 uno::Any& _rValue,
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)
155 OUString sReturn;
156 if ( !convertGenericValueToString( PropertyValue, sReturn ) )
158 sReturn = convertSimpleToString( PropertyValue );
159 #ifdef DBG_UTIL
160 if ( sReturn.isEmpty() && PropertyValue.hasValue() )
162 SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertPropertyValueToStringRepresentation: cannot convert values of type '"
163 << PropertyValue.getValueTypeName()
164 << "'!" );
166 #endif
169 return sReturn;
172 uno::Any SAL_CALL StringRepresentation::convertToPropertyValue(const OUString & ControlValue, const uno::Type & ControlValueType)
174 uno::Any aReturn;
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& ) { }
194 break;
196 default:
197 #if OSL_DEBUG_LEVEL > 0
198 bool bCanConvert =
199 #endif
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() << "'!" );
209 #endif
212 return aReturn;
215 namespace {
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 {
220 bool operator ()(
221 css::uno::Reference< css::reflection::XConstantTypeDescription > const &
223 css::uno::Reference< css::reflection::XConstantTypeDescription > const &
224 c2) 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();
237 if ( !nLength )
238 return;
240 const uno::Any* pIter = aArguments.getConstArray();
241 m_xTypeConverter.set(*pIter++,uno::UNO_QUERY);
242 if ( nLength != 3 )
243 return;
245 OUString sConstantName;
246 *pIter++ >>= sConstantName;
247 *pIter >>= m_aValues;
249 if ( !m_xContext.is() )
250 return;
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 );
257 uno::Sequence<
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 )
267 OUString sReturn;
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];
285 break;
291 if ( sReturn.isEmpty() )
292 m_xTypeConverter->convertToSimpleType( _rValue, uno::TypeClass_STRING ) >>= sReturn;
294 catch( const script::CannotConvertException& ) { }
295 catch( const lang::IllegalArgumentException& ) { }
297 return sReturn;
301 namespace
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
319 return _rValue;
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() )
344 return;
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;
364 break;
366 case uno::TypeClass_BOOLEAN:
368 bool bValue = false;
369 _rValue >>= bValue;
370 _rStringRep = bValue ? PcrRes(RID_RSC_ENUM_YESNO[1])
371 : PcrRes(RID_RSC_ENUM_YESNO[0]);
373 break;
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;
385 // string sequences
386 if ( _rValue >>= aStringValues )
388 _rStringRep = composeSequenceElements( aStringValues, StringIdentity() );
390 // byte sequences
391 else if ( _rValue >>= aInt8Values )
393 _rStringRep = composeSequenceElements( aInt8Values, ConvertIntegerFromAndToString() );
395 // uInt16 sequences
396 else if ( _rValue >>= aUInt16Values )
398 _rStringRep = composeSequenceElements( aUInt16Values, ConvertIntegerFromAndToString() );
400 // Int16 sequences
401 else if ( _rValue >>= aInt16Values )
403 _rStringRep = composeSequenceElements( aInt16Values, ConvertIntegerFromAndToString() );
405 // uInt32 sequences
406 else if ( _rValue >>= aUInt32Values )
408 _rStringRep = composeSequenceElements( aUInt32Values, ConvertIntegerFromAndToString() );
410 // Int32 sequences
411 else if ( _rValue >>= aInt32Values )
413 _rStringRep = composeSequenceElements( aInt32Values, ConvertIntegerFromAndToString() );
415 else
416 bCanConvert = false;
418 break;
419 case uno::TypeClass_CONSTANT:
420 break;
422 // some structs
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,
429 // is YYYYMMDD.
430 util::Date aUnoDate;
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)
437 util::Time aUnoTime;
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);
447 else
448 bCanConvert = false;
449 break;
451 default:
452 bCanConvert = false;
453 break;
456 return bCanConvert;
459 uno::Any StringRepresentation::convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType )
461 uno::Any aReturn;
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();
476 break;
481 if ( !aReturn.hasValue() )
482 aReturn = m_xTypeConverter->convertToSimpleType( Any( _rValue ), _ePropertyType );
484 catch( const script::CannotConvertException& ) { }
485 catch( const lang::IllegalArgumentException& ) { }
487 return aReturn;
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;
498 break;
500 case uno::TypeClass_BOOLEAN:
502 _rValue <<= PcrRes(RID_RSC_ENUM_YESNO[0]) != _rStringRep;
504 break;
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;
518 break;
519 case uno::TypeClass_SHORT:
521 Sequence< sal_Int16 > aElements;
522 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
523 _rValue <<= aElements;
525 break;
526 case uno::TypeClass_UNSIGNED_SHORT:
528 Sequence< sal_uInt16 > aElements;
529 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
530 _rValue <<= aElements;
532 break;
533 case uno::TypeClass_LONG:
535 Sequence< sal_Int32 > aElements;
536 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
537 _rValue <<= aElements;
539 break;
540 case uno::TypeClass_UNSIGNED_LONG:
542 Sequence< sal_uInt32 > aElements;
543 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
544 _rValue <<= aElements;
546 break;
547 case uno::TypeClass_BYTE:
549 Sequence< sal_Int8 > aElements;
550 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
551 _rValue <<= aElements;
553 break;
554 default:
555 bCanConvert = false;
556 break;
559 break;
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,
567 // is YYYYMMDD.
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);
580 else
581 bCanConvert = false;
582 break;
584 default:
585 bCanConvert = false;
586 break;
589 return bCanConvert;
593 } // pcr
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: */