LibreOffice Module extensions (master) 1
stringrepresentation.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
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>
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"
45
46#include <algorithm>
47
48namespace pcr{
49
50using namespace ::com::sun::star;
51using namespace ::com::sun::star::uno;
52
53namespace {
54
55class StringRepresentation:
56 public ::cppu::WeakImplHelper<
57 lang::XServiceInfo,
58 inspection::XStringRepresentation,
59 lang::XInitialization>
60{
61public:
62 explicit StringRepresentation(uno::Reference< uno::XComponentContext > context);
63 StringRepresentation (const StringRepresentation&) = delete;
64 StringRepresentation& operator=(const StringRepresentation&) = delete;
65
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;
70
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;
74
75 // lang::XInitialization:
76 virtual void SAL_CALL initialize(const uno::Sequence< uno::Any > & aArguments) override;
77
78private:
79 virtual ~StringRepresentation() override {}
80
89 static bool convertGenericValueToString(
90 const uno::Any& _rValue,
91 OUString& _rStringRep
92 );
93
102 static bool convertStringToGenericValue(
103 const OUString& _rStringRep,
104 uno::Any& _rValue,
105 const uno::Type& _rTargetType
106 );
107
113 OUString convertSimpleToString( const uno::Any& _rValue );
114
120 uno::Any convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType );
121
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;
127
128};
129
130}
131
132StringRepresentation::StringRepresentation(uno::Reference< uno::XComponentContext > context) :
133 m_xContext(std::move(context))
134{}
135
136// com.sun.star.uno.XServiceInfo:
137OUString SAL_CALL StringRepresentation::getImplementationName()
138{
139 return "StringRepresentation";
140}
141
142sal_Bool SAL_CALL StringRepresentation::supportsService(OUString const & serviceName)
143{
144 return cppu::supportsService(this, serviceName);
145}
146
147uno::Sequence< OUString > SAL_CALL StringRepresentation::getSupportedServiceNames()
148{
149 return { "com.sun.star.inspection.StringRepresentation" };
150}
151
152// inspection::XStringRepresentation:
153OUString SAL_CALL StringRepresentation::convertToControlValue(const uno::Any & PropertyValue)
154{
155 OUString sReturn;
156 if ( !convertGenericValueToString( PropertyValue, sReturn ) )
157 {
158 sReturn = convertSimpleToString( PropertyValue );
159#ifdef DBG_UTIL
160 if ( sReturn.isEmpty() && PropertyValue.hasValue() )
161 {
162 SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertPropertyValueToStringRepresentation: cannot convert values of type '"
163 << PropertyValue.getValueType().getTypeName()
164 << "'!" );
165 }
166#endif
167 }
168
169 return sReturn;
170}
171
172uno::Any SAL_CALL StringRepresentation::convertToPropertyValue(const OUString & ControlValue, const uno::Type & ControlValueType)
173{
174 uno::Any aReturn;
175
176 uno::TypeClass ePropertyType = ControlValueType.getTypeClass();
177 switch ( ePropertyType )
178 {
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:
188 try
189 {
190 aReturn = convertStringToSimple(ControlValue, ePropertyType);
191 }
192 catch( const script::CannotConvertException& ) { }
193 catch( const lang::IllegalArgumentException& ) { }
194 break;
195
196 default:
197 #if OSL_DEBUG_LEVEL > 0
198 bool bCanConvert =
199 #endif
200 convertStringToGenericValue( ControlValue, aReturn, ControlValueType );
201
202 #if OSL_DEBUG_LEVEL > 0
203 // could not convert ...
204 if ( !bCanConvert && !ControlValue.isEmpty() )
205 {
206 SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertStringRepresentationToPropertyValue: cannot convert into values of type '"
207 << ControlValueType.getTypeName() << "'!" );
208 }
209 #endif
210 }
211
212 return aReturn;
213}
214
215namespace {
216
217// This comparison functor assumes an underlying set of constants with pairwise
218// unequal values that are all of UNO SHORT or LONG type:
219struct CompareConstants {
220 bool operator ()(
221 css::uno::Reference< css::reflection::XConstantTypeDescription > const &
222 c1,
223 css::uno::Reference< css::reflection::XConstantTypeDescription > const &
224 c2) const
225 {
226 return c1->getConstantValue().get<sal_Int32>()
227 < c2->getConstantValue().get<sal_Int32>();
228 }
229};
230
231}
232
233// lang::XInitialization:
234void SAL_CALL StringRepresentation::initialize(const uno::Sequence< uno::Any > & aArguments)
235{
236 sal_Int32 nLength = aArguments.getLength();
237 if ( !nLength )
238 return;
239
240 const uno::Any* pIter = aArguments.getConstArray();
241 m_xTypeConverter.set(*pIter++,uno::UNO_QUERY);
242 if ( nLength != 3 )
243 return;
244
245 OUString sConstantName;
246 *pIter++ >>= sConstantName;
247 *pIter >>= m_aValues;
248
249 if ( !m_xContext.is() )
250 return;
251
252 uno::Reference< container::XHierarchicalNameAccess > xTypeDescProv(
253 m_xContext->getValueByName("/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
254 uno::UNO_QUERY_THROW );
255
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 = cs;
263}
264
265OUString StringRepresentation::convertSimpleToString( const uno::Any& _rValue )
266{
267 OUString sReturn;
268 if ( m_xTypeConverter.is() && _rValue.hasValue() )
269 {
270 try
271 {
272 if ( m_aConstants.hasElements() )
273 {
274 sal_Int16 nConstantValue = 0;
275 if ( _rValue >>= nConstantValue )
276 {
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)
280 {
281 if ( (*pIter)->getConstantValue() == _rValue )
282 {
283 OSL_ENSURE(i < m_aValues.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues");
284 sReturn = m_aValues[i];
285 break;
286 }
287 }
288 }
289 }
290
291 if ( sReturn.isEmpty() )
292 m_xTypeConverter->convertToSimpleType( _rValue, uno::TypeClass_STRING ) >>= sReturn;
293 }
294 catch( const script::CannotConvertException& ) { }
295 catch( const lang::IllegalArgumentException& ) { }
296 }
297 return sReturn;
298}
299
300
301namespace
302{
303 struct ConvertIntegerFromAndToString
304 {
305 OUString operator()( sal_Int32 _rIntValue ) const
306 {
307 return OUString::number( _rIntValue );
308 }
309 sal_Int32 operator()( std::u16string_view _rStringValue ) const
310 {
311 return o3tl::toInt32(_rStringValue);
312 }
313 };
314
315 struct StringIdentity
316 {
317 OUString operator()( const OUString& _rValue ) const
318 {
319 return _rValue;
320 }
321 };
322
323 template < class ElementType, class Transformer >
324 OUString composeSequenceElements( const Sequence< ElementType >& _rElements, const Transformer& _rTransformer )
325 {
326 OUStringBuffer sCompose;
327
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)
331 {
332 sCompose.append(OUString(_rTransformer(rElement)) + "\n");
333 }
334 sCompose.stripEnd('\n');
335
336 return sCompose.makeStringAndClear();
337 }
338
339 template < class ElementType, class Transformer >
340 void splitComposedStringToSequence( std::u16string_view _rComposed, Sequence< ElementType >& _out_SplitUp, const Transformer& _rTransformer )
341 {
342 _out_SplitUp.realloc( 0 );
343 if ( _rComposed.empty() )
344 return;
345 sal_Int32 tokenPos = 0;
346 do
347 {
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 )) ));
350 }
351 while ( tokenPos != -1 );
352 }
353}
354
355
356bool StringRepresentation::convertGenericValueToString( const uno::Any& _rValue, OUString& _rStringRep )
357{
358 bool bCanConvert = true;
359
360 switch ( _rValue.getValueTypeClass() )
361 {
362 case uno::TypeClass_STRING:
363 _rValue >>= _rStringRep;
364 break;
365
366 case uno::TypeClass_BOOLEAN:
367 {
368 bool bValue = false;
369 _rValue >>= bValue;
370 _rStringRep = bValue ? PcrRes(RID_RSC_ENUM_YESNO[1])
371 : PcrRes(RID_RSC_ENUM_YESNO[0]);
372 }
373 break;
374
375 // some sequence types
376 case uno::TypeClass_SEQUENCE:
377 {
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;
384
385 // string sequences
386 if ( _rValue >>= aStringValues )
387 {
388 _rStringRep = composeSequenceElements( aStringValues, StringIdentity() );
389 }
390 // byte sequences
391 else if ( _rValue >>= aInt8Values )
392 {
393 _rStringRep = composeSequenceElements( aInt8Values, ConvertIntegerFromAndToString() );
394 }
395 // uInt16 sequences
396 else if ( _rValue >>= aUInt16Values )
397 {
398 _rStringRep = composeSequenceElements( aUInt16Values, ConvertIntegerFromAndToString() );
399 }
400 // Int16 sequences
401 else if ( _rValue >>= aInt16Values )
402 {
403 _rStringRep = composeSequenceElements( aInt16Values, ConvertIntegerFromAndToString() );
404 }
405 // uInt32 sequences
406 else if ( _rValue >>= aUInt32Values )
407 {
408 _rStringRep = composeSequenceElements( aUInt32Values, ConvertIntegerFromAndToString() );
409 }
410 // Int32 sequences
411 else if ( _rValue >>= aInt32Values )
412 {
413 _rStringRep = composeSequenceElements( aInt32Values, ConvertIntegerFromAndToString() );
414 }
415 else
416 bCanConvert = false;
417 }
418 break;
419 case uno::TypeClass_CONSTANT:
420 break;
421
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() ))
426 {
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);
433 }
434 else if ( _rValue.getValueType().equals( cppu::UnoType< util::Time >::get() ))
435 {
436 // similar for time (HHMMSSHH)
437 util::Time aUnoTime;
438 _rValue >>= aUnoTime;
439 _rStringRep = ::dbtools::DBTypeConversion::toTimeString(aUnoTime);
440 }
441 else if ( _rValue.getValueType().equals( cppu::UnoType< util::DateTime >::get() ))
442 {
443 util::DateTime aUnoDateTime;
444 _rValue >>= aUnoDateTime;
445 _rStringRep = ::dbtools::DBTypeConversion::toDateTimeString(aUnoDateTime);
446 }
447 else
448 bCanConvert = false;
449 break;
450
451 default:
452 bCanConvert = false;
453 break;
454 }
455
456 return bCanConvert;
457}
458
459uno::Any StringRepresentation::convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType )
460{
461 uno::Any aReturn;
462 if ( m_xTypeConverter.is() && !_rValue.isEmpty() )
463 {
464 try
465 {
466 if ( m_aConstants.hasElements() && m_aValues.hasElements() )
467 {
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)
471 {
472 if ( *pIter == _rValue )
473 {
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;
477 }
478 }
479 }
480
481 if ( !aReturn.hasValue() )
482 aReturn = m_xTypeConverter->convertToSimpleType( Any( _rValue ), _ePropertyType );
483 }
484 catch( const script::CannotConvertException& ) { }
485 catch( const lang::IllegalArgumentException& ) { }
486 }
487 return aReturn;
488}
489
490bool StringRepresentation::convertStringToGenericValue( const OUString& _rStringRep, uno::Any& _rValue, const uno::Type& _rTargetType )
491{
492 bool bCanConvert = true;
493
494 switch ( _rTargetType.getTypeClass() )
495 {
496 case uno::TypeClass_STRING:
497 _rValue <<= _rStringRep;
498 break;
499
500 case uno::TypeClass_BOOLEAN:
501 {
502 _rValue <<= PcrRes(RID_RSC_ENUM_YESNO[0]) != _rStringRep;
503 }
504 break;
505
506 case uno::TypeClass_SEQUENCE:
507 {
508 uno::Type aElementType = ::comphelper::getSequenceElementType( _rTargetType );
509
510 switch ( aElementType.getTypeClass() )
511 {
512 case uno::TypeClass_STRING:
513 {
514 Sequence< OUString > aElements;
515 splitComposedStringToSequence( _rStringRep, aElements, StringIdentity() );
516 _rValue <<= aElements;
517 }
518 break;
519 case uno::TypeClass_SHORT:
520 {
521 Sequence< sal_Int16 > aElements;
522 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
523 _rValue <<= aElements;
524 }
525 break;
526 case uno::TypeClass_UNSIGNED_SHORT:
527 {
528 Sequence< sal_uInt16 > aElements;
529 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
530 _rValue <<= aElements;
531 }
532 break;
533 case uno::TypeClass_LONG:
534 {
535 Sequence< sal_Int32 > aElements;
536 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
537 _rValue <<= aElements;
538 }
539 break;
540 case uno::TypeClass_UNSIGNED_LONG:
541 {
542 Sequence< sal_uInt32 > aElements;
543 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
544 _rValue <<= aElements;
545 }
546 break;
547 case uno::TypeClass_BYTE:
548 {
549 Sequence< sal_Int8 > aElements;
550 splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() );
551 _rValue <<= aElements;
552 }
553 break;
554 default:
555 bCanConvert = false;
556 break;
557 }
558 }
559 break;
560
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() ))
564 {
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.
568
569 _rValue <<= ::dbtools::DBTypeConversion::toDate(_rStringRep);
570 }
571 else if ( _rTargetType.equals( cppu::UnoType< util::Time >::get() ))
572 {
573 // similar for time (HHMMSSHH)
574 _rValue <<= ::dbtools::DBTypeConversion::toTime(_rStringRep);
575 }
576 else if ( _rTargetType.equals( cppu::UnoType< util::DateTime >::get() ))
577 {
578 _rValue <<= ::dbtools::DBTypeConversion::toDateTime(_rStringRep);
579 }
580 else
581 bCanConvert = false;
582 break;
583
584 default:
585 bCanConvert = false;
586 break;
587 }
588
589 return bCanConvert;
590}
591
592
593} // pcr
594
595
596extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
598 css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
599{
600 return cppu::acquire(new pcr::StringRepresentation(context));
601}
602
603
604/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xContext
Definition: filehandler.cxx:78
Sequence< PropertyValue > m_aValues
Sequence< PropertyValue > aArguments
#define SAL_WARN(area, stream)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
ElementType
int i
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
enumrange< T >::Iterator begin(enumrange< T >)
end
a property handler for any virtual string properties
Definition: browserline.cxx:39
OUString PcrRes(TranslateId aId)
Definition: modulepcr.cxx:26
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * extensions_propctrlr_StringRepresentation_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
bool hasValue()
unsigned char sal_Bool
sal_Int32 nLength