Avoid potential negative array index access to cached text.
[LibreOffice.git] / toolkit / source / controls / formattedcontrol.cxx
blobcf3094c3585781a9eac7229009566f360e004c37
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 <controls/formattedcontrol.hxx>
21 #include <helper/property.hxx>
23 #include <com/sun/star/awt/XVclWindowPeer.hpp>
24 #include <com/sun/star/uno/XComponentContext.hpp>
25 #include <com/sun/star/util/NumberFormatter.hpp>
26 #include <com/sun/star/util/NumberFormatsSupplier.hpp>
28 #include <comphelper/diagnose_ex.hxx>
29 #include <comphelper/processfactory.hxx>
30 #include <osl/diagnose.h>
32 #include <helper/unopropertyarrayhelper.hxx>
33 #include <mutex>
35 namespace toolkit
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::awt;
41 using namespace ::com::sun::star::lang;
42 using namespace ::com::sun::star::beans;
43 using namespace ::com::sun::star::util;
46 namespace
49 std::mutex& getDefaultFormatsMutex()
51 static std::mutex s_aDefaultFormatsMutex;
52 return s_aDefaultFormatsMutex;
55 Reference< XNumberFormatsSupplier > s_xDefaultFormats;
56 bool s_bTriedCreation = false;
57 oslInterlockedCount s_refCount(0);
59 const Reference< XNumberFormatsSupplier >& lcl_getDefaultFormats_throw()
61 std::scoped_lock aGuard( getDefaultFormatsMutex() );
63 if ( !s_xDefaultFormats.is() && !s_bTriedCreation )
65 s_bTriedCreation = true;
66 s_xDefaultFormats = NumberFormatsSupplier::createWithDefaultLocale( ::comphelper::getProcessComponentContext() );
68 if ( !s_xDefaultFormats.is() )
69 throw RuntimeException();
71 return s_xDefaultFormats;
74 void lcl_registerDefaultFormatsClient()
76 osl_atomic_increment( &s_refCount );
79 void lcl_revokeDefaultFormatsClient()
81 Reference< XNumberFormatsSupplier > xReleasePotentialLastReference;
83 std::scoped_lock aGuard( getDefaultFormatsMutex() );
84 if ( 0 != osl_atomic_decrement( &s_refCount ) )
85 return;
87 xReleasePotentialLastReference = std::move(s_xDefaultFormats);
88 s_bTriedCreation = false;
90 xReleasePotentialLastReference.clear();
95 // = UnoControlFormattedFieldModel
98 UnoControlFormattedFieldModel::UnoControlFormattedFieldModel( const Reference< XComponentContext >& rxContext )
99 :UnoControlModel( rxContext )
100 ,m_bRevokedAsClient( false )
101 ,m_bSettingValueAndText( false )
103 ImplRegisterProperty( BASEPROPERTY_ALIGN );
104 ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR );
105 ImplRegisterProperty( BASEPROPERTY_BORDER );
106 ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR );
107 ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL );
108 ImplRegisterProperty( BASEPROPERTY_EFFECTIVE_DEFAULT );
109 ImplRegisterProperty( BASEPROPERTY_EFFECTIVE_VALUE );
110 ImplRegisterProperty( BASEPROPERTY_EFFECTIVE_MAX );
111 ImplRegisterProperty( BASEPROPERTY_EFFECTIVE_MIN );
112 ImplRegisterProperty( BASEPROPERTY_ENABLED );
113 ImplRegisterProperty( BASEPROPERTY_ENABLEVISIBLE );
114 ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR );
115 ImplRegisterProperty( BASEPROPERTY_FORMATKEY );
116 ImplRegisterProperty( BASEPROPERTY_FORMATSSUPPLIER );
117 ImplRegisterProperty( BASEPROPERTY_HELPTEXT );
118 ImplRegisterProperty( BASEPROPERTY_HELPURL );
119 ImplRegisterProperty( BASEPROPERTY_MAXTEXTLEN );
120 ImplRegisterProperty( BASEPROPERTY_PRINTABLE );
121 ImplRegisterProperty( BASEPROPERTY_REPEAT );
122 ImplRegisterProperty( BASEPROPERTY_REPEAT_DELAY );
123 ImplRegisterProperty( BASEPROPERTY_READONLY );
124 ImplRegisterProperty( BASEPROPERTY_SPIN );
125 ImplRegisterProperty( BASEPROPERTY_STRICTFORMAT );
126 ImplRegisterProperty( BASEPROPERTY_TABSTOP );
127 ImplRegisterProperty( BASEPROPERTY_TEXT );
128 ImplRegisterProperty( BASEPROPERTY_TEXTCOLOR );
129 ImplRegisterProperty( BASEPROPERTY_HIDEINACTIVESELECTION );
130 ImplRegisterProperty( BASEPROPERTY_ENFORCE_FORMAT );
131 ImplRegisterProperty( BASEPROPERTY_VERTICALALIGN );
132 ImplRegisterProperty( BASEPROPERTY_WRITING_MODE );
133 ImplRegisterProperty( BASEPROPERTY_CONTEXT_WRITING_MODE );
134 ImplRegisterProperty( BASEPROPERTY_MOUSE_WHEEL_BEHAVIOUR );
135 ImplRegisterProperty( BASEPROPERTY_HIGHLIGHT_COLOR );
136 ImplRegisterProperty( BASEPROPERTY_HIGHLIGHT_TEXT_COLOR );
138 Any aTreatAsNumber;
139 aTreatAsNumber <<= true;
140 ImplRegisterProperty( BASEPROPERTY_TREATASNUMBER, aTreatAsNumber );
142 lcl_registerDefaultFormatsClient();
146 UnoControlFormattedFieldModel::~UnoControlFormattedFieldModel()
151 OUString UnoControlFormattedFieldModel::getServiceName()
153 return "stardiv.vcl.controlmodel.FormattedField";
157 void UnoControlFormattedFieldModel::setFastPropertyValue_NoBroadcast( std::unique_lock<std::mutex>& rGuard, sal_Int32 nHandle, const Any& rValue )
159 UnoControlModel::setFastPropertyValue_NoBroadcast( rGuard, nHandle, rValue );
161 switch ( nHandle )
163 case BASEPROPERTY_EFFECTIVE_VALUE:
164 if ( !m_bSettingValueAndText )
165 impl_updateTextFromValue_nothrow(rGuard);
166 break;
167 case BASEPROPERTY_FORMATSSUPPLIER:
168 impl_updateCachedFormatter_nothrow(rGuard);
169 impl_updateTextFromValue_nothrow(rGuard);
170 break;
171 case BASEPROPERTY_FORMATKEY:
172 impl_updateCachedFormatKey_nothrow(rGuard);
173 impl_updateTextFromValue_nothrow(rGuard);
174 break;
179 void UnoControlFormattedFieldModel::impl_updateTextFromValue_nothrow( std::unique_lock<std::mutex>& rGuard)
181 if ( !m_xCachedFormatter.is() )
182 impl_updateCachedFormatter_nothrow(rGuard);
183 if ( !m_xCachedFormatter.is() )
184 return;
188 Any aEffectiveValue;
189 getFastPropertyValue( rGuard, aEffectiveValue, BASEPROPERTY_EFFECTIVE_VALUE );
191 OUString sStringValue;
192 if ( !( aEffectiveValue >>= sStringValue ) )
194 double nDoubleValue(0);
195 if ( aEffectiveValue >>= nDoubleValue )
197 sal_Int32 nFormatKey( 0 );
198 if ( m_aCachedFormat.hasValue() )
199 m_aCachedFormat >>= nFormatKey;
200 sStringValue = m_xCachedFormatter->convertNumberToString( nFormatKey, nDoubleValue );
204 setFastPropertyValueImpl( rGuard, BASEPROPERTY_TEXT, Any( sStringValue ) );
206 catch( const Exception& )
208 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
213 void UnoControlFormattedFieldModel::impl_updateCachedFormatter_nothrow(std::unique_lock<std::mutex>& rGuard)
215 Any aFormatsSupplier;
216 getFastPropertyValue( rGuard, aFormatsSupplier, BASEPROPERTY_FORMATSSUPPLIER );
219 Reference< XNumberFormatsSupplier > xSupplier( aFormatsSupplier, UNO_QUERY );
220 if ( !xSupplier.is() )
221 xSupplier = lcl_getDefaultFormats_throw();
223 if ( !m_xCachedFormatter.is() )
225 m_xCachedFormatter.set(
226 NumberFormatter::create(::comphelper::getProcessComponentContext()),
227 UNO_QUERY_THROW
230 m_xCachedFormatter->attachNumberFormatsSupplier( xSupplier );
232 catch( const Exception& )
234 DBG_UNHANDLED_EXCEPTION("toolkit.controls");
239 void UnoControlFormattedFieldModel::impl_updateCachedFormatKey_nothrow(std::unique_lock<std::mutex>& rGuard)
241 Any aFormatKey;
242 getFastPropertyValue( rGuard, aFormatKey, BASEPROPERTY_FORMATKEY );
243 m_aCachedFormat = aFormatKey;
247 void UnoControlFormattedFieldModel::dispose( )
249 UnoControlModel::dispose();
251 std::unique_lock aGuard( m_aMutex );
252 if ( !m_bRevokedAsClient )
254 lcl_revokeDefaultFormatsClient();
255 m_bRevokedAsClient = true;
260 void UnoControlFormattedFieldModel::ImplNormalizePropertySequence( const sal_Int32 _nCount, sal_Int32* _pHandles,
261 Any* _pValues, sal_Int32* _pValidHandles ) const
263 ImplEnsureHandleOrder( _nCount, _pHandles, _pValues, BASEPROPERTY_EFFECTIVE_VALUE, BASEPROPERTY_TEXT );
265 UnoControlModel::ImplNormalizePropertySequence( _nCount, _pHandles, _pValues, _pValidHandles );
269 namespace
271 class ResetFlagOnExit
273 private:
274 bool& m_rFlag;
276 public:
277 explicit ResetFlagOnExit( bool& _rFlag )
278 :m_rFlag( _rFlag )
281 ~ResetFlagOnExit()
283 m_rFlag = false;
289 void SAL_CALL UnoControlFormattedFieldModel::setPropertyValues( const Sequence< OUString >& _rPropertyNames, const Sequence< Any >& _rValues )
291 bool bSettingValue = false;
292 bool bSettingText = false;
293 for ( auto const & propertyName : _rPropertyNames )
295 if ( BASEPROPERTY_EFFECTIVE_VALUE == GetPropertyId( propertyName ) )
296 bSettingValue = true;
298 if ( BASEPROPERTY_TEXT == GetPropertyId( propertyName ) )
299 bSettingText = true;
302 m_bSettingValueAndText = ( bSettingValue && bSettingText );
303 ResetFlagOnExit aResetFlag( m_bSettingValueAndText );
304 UnoControlModel::setPropertyValues( _rPropertyNames, _rValues );
308 bool UnoControlFormattedFieldModel::convertFastPropertyValue(
309 std::unique_lock<std::mutex>& rGuard,
310 Any& rConvertedValue, Any& rOldValue, sal_Int32 nPropId,
311 const Any& rValue )
313 if ( BASEPROPERTY_EFFECTIVE_DEFAULT == nPropId && rValue.hasValue() )
315 double dVal = 0;
316 bool bStreamed = (rValue >>= dVal);
317 if ( bStreamed )
319 rConvertedValue <<= dVal;
321 else
323 sal_Int32 nVal = 0;
324 bStreamed = (rValue >>= nVal);
325 if ( bStreamed )
327 rConvertedValue <<= static_cast<double>(nVal);
329 else
331 OUString sVal;
332 bStreamed = (rValue >>= sVal);
333 if ( bStreamed )
335 rConvertedValue <<= sVal;
340 if ( bStreamed )
342 getFastPropertyValue( rGuard, rOldValue, nPropId );
343 return !CompareProperties( rConvertedValue, rOldValue );
346 throw IllegalArgumentException(
347 ("Unable to convert the given value for the property "
348 + GetPropertyName(static_cast<sal_uInt16>(nPropId))
349 + " (double, integer, or string expected)."),
350 static_cast< XPropertySet* >(this),
354 return UnoControlModel::convertFastPropertyValue( rGuard, rConvertedValue, rOldValue, nPropId, rValue );
358 Any UnoControlFormattedFieldModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const
360 Any aReturn;
361 switch (nPropId)
363 case BASEPROPERTY_DEFAULTCONTROL: aReturn <<= OUString("stardiv.vcl.control.FormattedField"); break;
365 case BASEPROPERTY_TREATASNUMBER: aReturn <<= true; break;
367 case BASEPROPERTY_EFFECTIVE_DEFAULT:
368 case BASEPROPERTY_EFFECTIVE_VALUE:
369 case BASEPROPERTY_EFFECTIVE_MAX:
370 case BASEPROPERTY_EFFECTIVE_MIN:
371 case BASEPROPERTY_FORMATKEY:
372 case BASEPROPERTY_FORMATSSUPPLIER:
373 // (void)
374 break;
376 default : aReturn = UnoControlModel::ImplGetDefaultValue( nPropId ); break;
379 return aReturn;
383 ::cppu::IPropertyArrayHelper& UnoControlFormattedFieldModel::getInfoHelper()
385 static UnoPropertyArrayHelper aHelper( ImplGetPropertyIds() );
386 return aHelper;
389 // beans::XMultiPropertySet
391 Reference< XPropertySetInfo > UnoControlFormattedFieldModel::getPropertySetInfo( )
393 static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
394 return xInfo;
397 OUString UnoControlFormattedFieldModel::getImplementationName()
399 return "stardiv.Toolkit.UnoControlFormattedFieldModel";
402 css::uno::Sequence<OUString>
403 UnoControlFormattedFieldModel::getSupportedServiceNames()
405 auto s(UnoControlModel::getSupportedServiceNames());
406 s.realloc(s.getLength() + 2);
407 auto ps = s.getArray();
408 ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlFormattedFieldModel";
409 ps[s.getLength() - 1] = "stardiv.vcl.controlmodel.FormattedField";
410 return s;
413 // = UnoFormattedFieldControl
416 UnoFormattedFieldControl::UnoFormattedFieldControl()
421 OUString UnoFormattedFieldControl::GetComponentServiceName() const
423 return "FormattedField";
427 void UnoFormattedFieldControl::textChanged(const TextEvent& e)
429 Reference< XVclWindowPeer > xPeer(getPeer(), UNO_QUERY);
430 OSL_ENSURE(xPeer.is(), "UnoFormattedFieldControl::textChanged : what kind of peer do I have ?");
432 Sequence< OUString > aNames{ GetPropertyName( BASEPROPERTY_EFFECTIVE_VALUE ),
433 GetPropertyName( BASEPROPERTY_TEXT ) };
435 Sequence< Any > aValues{ xPeer->getProperty( aNames[0] ),
436 xPeer->getProperty( aNames[1] ) };
438 ImplSetPropertyValues( aNames, aValues, false );
440 if ( GetTextListeners().getLength() )
441 GetTextListeners().textChanged( e );
444 OUString UnoFormattedFieldControl::getImplementationName()
446 return "stardiv.Toolkit.UnoFormattedFieldControl";
449 css::uno::Sequence<OUString>
450 UnoFormattedFieldControl::getSupportedServiceNames()
452 auto s(UnoEditControl::getSupportedServiceNames());
453 s.realloc(s.getLength() + 2);
454 auto ps = s.getArray();
455 ps[s.getLength() - 2] = "com.sun.star.awt.UnoControlFormattedField";
456 ps[s.getLength() - 1] = "stardiv.vcl.control.FormattedField";
457 return s;
459 } // namespace toolkit
462 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
463 stardiv_Toolkit_UnoControlFormattedFieldModel_get_implementation(
464 css::uno::XComponentContext *context,
465 css::uno::Sequence<css::uno::Any> const &)
467 return cppu::acquire(new toolkit::UnoControlFormattedFieldModel(context));
470 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
471 stardiv_Toolkit_UnoFormattedFieldControl_get_implementation(
472 css::uno::XComponentContext *,
473 css::uno::Sequence<css::uno::Any> const &)
475 return cppu::acquire(new toolkit::UnoFormattedFieldControl());
478 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */