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 <config_features.h>
21 #include <config_fuzzers.h>
23 #include "ListBox.hxx"
24 #include <property.hxx>
25 #include <services.hxx>
26 #include <frm_resource.hxx>
27 #include <strings.hrc>
28 #include "BaseListBox.hxx"
29 #include <componenttools.hxx>
31 #include <com/sun/star/form/FormComponentType.hpp>
32 #include <com/sun/star/container/XIndexAccess.hpp>
33 #include <com/sun/star/sdbc/XRow.hpp>
34 #include <com/sun/star/awt/XWindow.hpp>
35 #include <com/sun/star/sdbc/XConnection.hpp>
37 #include <comphelper/basicio.hxx>
38 #include <comphelper/property.hxx>
39 #include <comphelper/sequence.hxx>
40 #include <comphelper/string.hxx>
41 #include <comphelper/types.hxx>
42 #include <connectivity/dbtools.hxx>
43 #include <connectivity/formattedcolumnvalue.hxx>
44 #include <o3tl/any.hxx>
45 #include <o3tl/safeint.hxx>
46 #include <tools/debug.hxx>
47 #include <tools/diagnose_ex.h>
48 #include <sal/log.hxx>
49 #include <unotools/sharedunocomponent.hxx>
59 using namespace ::com::sun::star::uno
;
60 using namespace ::com::sun::star::sdb
;
61 using namespace ::com::sun::star::sdbc
;
62 using namespace ::com::sun::star::sdbcx
;
63 using namespace ::com::sun::star::beans
;
64 using namespace ::com::sun::star::container
;
65 using namespace ::com::sun::star::form
;
66 using namespace ::com::sun::star::awt
;
67 using namespace ::com::sun::star::io
;
68 using namespace ::com::sun::star::lang
;
69 using namespace ::com::sun::star::util
;
70 using namespace ::com::sun::star::form::binding
;
71 using namespace ::dbtools
;
73 using ::connectivity::ORowSetValue
;
75 const ::connectivity::ORowSetValue
OListBoxModel::s_aEmptyValue
;
76 const ::connectivity::ORowSetValue
OListBoxModel::s_aEmptyStringValue
= OUString();
83 struct RowSetValueToString
85 OUString
operator()( const ORowSetValue
& _value
) const
87 return _value
.getString();
92 struct AppendRowSetValueString
94 explicit AppendRowSetValueString( OUString
& _string
)
99 void operator()( const ORowSetValue
& _append
)
101 m_string
+= _append
.getString();
109 Sequence
< OUString
> lcl_convertToStringSequence( const ValueList
& _values
)
111 Sequence
< OUString
> aStrings( _values
.size() );
116 RowSetValueToString()
123 //= ItemEventDescription
125 typedef ::comphelper::EventHolder
< ItemEvent
> ItemEventDescription
;
130 Sequence
< Type
> OListBoxModel::_getTypes()
133 OBoundControlModel::_getTypes(),
134 OEntryListHelper::getTypes(),
135 OErrorBroadcaster::getTypes()
139 // stuff common to all constructors
140 void OListBoxModel::init()
142 startAggregatePropertyListening( PROPERTY_STRINGITEMLIST
);
143 startAggregatePropertyListening( PROPERTY_TYPEDITEMLIST
);
147 OListBoxModel::OListBoxModel(const Reference
<XComponentContext
>& _rxFactory
)
148 :OBoundControlModel( _rxFactory
, VCL_CONTROLMODEL_LISTBOX
, FRM_SUN_CONTROL_LISTBOX
, true, true, true )
149 // use the old control name for compatibility reasons
150 ,OEntryListHelper( static_cast<OControlModel
&>(*this) )
151 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
152 ,m_nConvertedBoundValuesType(0)
154 ,m_nBoundColumnType( DataType::SQLNULL
)
157 m_nClassId
= FormComponentType::LISTBOX
;
158 m_eListSourceType
= ListSourceType_VALUELIST
;
159 m_aBoundColumn
<<= sal_Int16(1);
160 initValueProperty( PROPERTY_SELECT_SEQ
, PROPERTY_ID_SELECT_SEQ
);
166 OListBoxModel::OListBoxModel( const OListBoxModel
* _pOriginal
, const Reference
<XComponentContext
>& _rxFactory
)
167 :OBoundControlModel( _pOriginal
, _rxFactory
)
168 ,OEntryListHelper( *_pOriginal
, static_cast<OControlModel
&>(*this) )
169 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
170 ,m_eListSourceType( _pOriginal
->m_eListSourceType
)
171 ,m_aBoundColumn( _pOriginal
->m_aBoundColumn
)
172 ,m_aListSourceValues( _pOriginal
->m_aListSourceValues
)
173 ,m_aBoundValues( _pOriginal
->m_aBoundValues
)
174 ,m_nConvertedBoundValuesType(0)
175 ,m_aDefaultSelectSeq( _pOriginal
->m_aDefaultSelectSeq
)
177 ,m_nBoundColumnType( DataType::SQLNULL
)
184 OListBoxModel::~OListBoxModel()
186 if (!OComponentHelper::rBHelper
.bDisposed
)
196 css::uno::Reference
< css::util::XCloneable
> SAL_CALL
OListBoxModel::createClone()
198 rtl::Reference
<OListBoxModel
> pClone
= new OListBoxModel(this, getContext());
199 pClone
->clonedFrom(this);
205 css::uno::Sequence
<OUString
> SAL_CALL
OListBoxModel::getSupportedServiceNames()
207 css::uno::Sequence
<OUString
> aSupported
= OBoundControlModel::getSupportedServiceNames();
209 sal_Int32 nOldLen
= aSupported
.getLength();
210 aSupported
.realloc( nOldLen
+ 9 );
211 OUString
* pStoreTo
= aSupported
.getArray() + nOldLen
;
213 *pStoreTo
++ = BINDABLE_CONTROL_MODEL
;
214 *pStoreTo
++ = DATA_AWARE_CONTROL_MODEL
;
215 *pStoreTo
++ = VALIDATABLE_CONTROL_MODEL
;
217 *pStoreTo
++ = BINDABLE_DATA_AWARE_CONTROL_MODEL
;
218 *pStoreTo
++ = VALIDATABLE_BINDABLE_CONTROL_MODEL
;
220 *pStoreTo
++ = FRM_SUN_COMPONENT_LISTBOX
;
221 *pStoreTo
++ = FRM_SUN_COMPONENT_DATABASE_LISTBOX
;
222 *pStoreTo
++ = BINDABLE_DATABASE_LIST_BOX
;
224 *pStoreTo
++ = FRM_COMPONENT_LISTBOX
;
230 Any SAL_CALL
OListBoxModel::queryAggregation(const Type
& _rType
)
232 Any aReturn
= OBoundControlModel::queryAggregation( _rType
);
233 if ( !aReturn
.hasValue() )
234 aReturn
= OEntryListHelper::queryInterface( _rType
);
235 if ( !aReturn
.hasValue() )
236 aReturn
= OErrorBroadcaster::queryInterface( _rType
);
242 void OListBoxModel::disposing()
244 OBoundControlModel::disposing();
245 OEntryListHelper::disposing();
246 OErrorBroadcaster::disposing();
250 void OListBoxModel::getFastPropertyValue(Any
& _rValue
, sal_Int32 _nHandle
) const
254 case PROPERTY_ID_BOUNDCOLUMN
:
255 _rValue
= m_aBoundColumn
;
258 case PROPERTY_ID_LISTSOURCETYPE
:
259 _rValue
<<= m_eListSourceType
;
262 case PROPERTY_ID_LISTSOURCE
:
263 _rValue
<<= lcl_convertToStringSequence( m_aListSourceValues
);
266 case PROPERTY_ID_VALUE_SEQ
:
267 _rValue
<<= lcl_convertToStringSequence( m_aBoundValues
);
270 case PROPERTY_ID_SELECT_VALUE_SEQ
:
271 _rValue
<<= getCurrentMultiValue();
274 case PROPERTY_ID_SELECT_VALUE
:
275 _rValue
= getCurrentSingleValue();
278 case PROPERTY_ID_DEFAULT_SELECT_SEQ
:
279 _rValue
<<= m_aDefaultSelectSeq
;
282 case PROPERTY_ID_STRINGITEMLIST
:
283 _rValue
<<= comphelper::containerToSequence(getStringItemList());
286 case PROPERTY_ID_TYPEDITEMLIST
:
287 _rValue
<<= getTypedItemList();
291 OBoundControlModel::getFastPropertyValue(_rValue
, _nHandle
);
296 void OListBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle
, const Any
& _rValue
)
300 case PROPERTY_ID_BOUNDCOLUMN
:
301 DBG_ASSERT((_rValue
.getValueType().getTypeClass() == TypeClass_SHORT
) || (_rValue
.getValueType().getTypeClass() == TypeClass_VOID
),
302 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
303 m_aBoundColumn
= _rValue
;
306 case PROPERTY_ID_LISTSOURCETYPE
:
307 DBG_ASSERT(_rValue
.getValueType().equals(::cppu::UnoType
<ListSourceType
>::get()),
308 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
309 _rValue
>>= m_eListSourceType
;
312 case PROPERTY_ID_LISTSOURCE
:
315 Sequence
< OUString
> aListSource
;
316 OSL_VERIFY( _rValue
>>= aListSource
);
319 ValueList().swap(m_aListSourceValues
);
321 std::cbegin(aListSource
),
322 std::cend(aListSource
),
323 ::std::insert_iterator
< ValueList
>( m_aListSourceValues
, m_aListSourceValues
.end() )
327 if ( m_eListSourceType
== ListSourceType_VALUELIST
)
329 setBoundValues(std::vector(m_aListSourceValues
));
333 if ( m_xCursor
.is() && !hasField() && !hasExternalListSource() )
334 // listbox is already connected to a database, and no external list source
335 // data source changed -> refresh
341 case PROPERTY_ID_VALUE_SEQ
:
342 SAL_WARN( "forms.component", "ValueItemList is read-only!" );
343 throw PropertyVetoException();
345 case PROPERTY_ID_SELECT_VALUE_SEQ
:
347 Sequence
< const Any
> v
;
349 Any
newSelectSeq(translateBindingValuesToControlValue(v
));
350 setControlValue( newSelectSeq
, eOther
);
354 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
355 case PROPERTY_ID_SELECT_VALUE
:
359 Any
newSelectSeq(translateDbValueToControlValue(v
));
360 setControlValue( newSelectSeq
, eOther
);
364 case PROPERTY_ID_DEFAULT_SELECT_SEQ
:
365 DBG_ASSERT(_rValue
.getValueType().equals(cppu::UnoType
<Sequence
<sal_Int16
>>::get()),
366 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
367 _rValue
>>= m_aDefaultSelectSeq
;
369 DBG_ASSERT(m_xAggregateFastSet
.is(), "OListBoxModel::setFastPropertyValue_NoBroadcast(DEFAULT_SELECT_SEQ) : invalid aggregate !");
370 if ( m_xAggregateFastSet
.is() )
371 setControlValue( _rValue
, eOther
);
374 case PROPERTY_ID_STRINGITEMLIST
:
376 ControlModelLock
aLock( *this );
377 setNewStringItemList( _rValue
, aLock
);
378 // TODO: this is bogus. setNewStringItemList expects a guard which has the *only*
379 // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
380 // a lock - so we effectively has two locks here, of which setNewStringItemList can
386 case PROPERTY_ID_TYPEDITEMLIST
:
388 ControlModelLock
aLock( *this );
389 setNewTypedItemList( _rValue
, aLock
);
390 // Same TODO as above.
396 OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle
, _rValue
);
401 sal_Bool
OListBoxModel::convertFastPropertyValue(
402 Any
& _rConvertedValue
, Any
& _rOldValue
, sal_Int32 _nHandle
, const Any
& _rValue
)
404 bool bModified(false);
407 case PROPERTY_ID_BOUNDCOLUMN
:
408 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aBoundColumn
, ::cppu::UnoType
<sal_Int16
>::get());
411 case PROPERTY_ID_LISTSOURCETYPE
:
412 bModified
= tryPropertyValueEnum(_rConvertedValue
, _rOldValue
, _rValue
, m_eListSourceType
);
415 case PROPERTY_ID_LISTSOURCE
:
416 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, lcl_convertToStringSequence( m_aListSourceValues
) );
419 case PROPERTY_ID_VALUE_SEQ
:
420 SAL_WARN( "forms.component", "ValueItemList is read-only!" );
421 throw IllegalArgumentException();
423 case PROPERTY_ID_SELECT_VALUE_SEQ
:
424 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, getCurrentMultiValue());
427 case PROPERTY_ID_SELECT_VALUE
:
429 // Any from connectivity::ORowSetValue
430 Any _rCurrentValue
= getCurrentSingleValue();
431 if (_rCurrentValue
!= _rValue
)
433 _rOldValue
= _rCurrentValue
;
434 _rConvertedValue
= _rValue
;
439 case PROPERTY_ID_DEFAULT_SELECT_SEQ
:
440 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aDefaultSelectSeq
);
443 case PROPERTY_ID_STRINGITEMLIST
:
444 bModified
= convertNewListSourceProperty( _rConvertedValue
, _rOldValue
, _rValue
);
447 case PROPERTY_ID_TYPEDITEMLIST
:
448 if (hasExternalListSource())
449 throw IllegalArgumentException();
450 bModified
= tryPropertyValue( _rConvertedValue
, _rOldValue
, _rValue
, getTypedItemList());
454 return OBoundControlModel::convertFastPropertyValue(_rConvertedValue
, _rOldValue
, _nHandle
, _rValue
);
460 void SAL_CALL
OListBoxModel::setPropertyValues( const Sequence
< OUString
>& _rPropertyNames
, const Sequence
< Any
>& _rValues
)
462 // if both SelectedItems and StringItemList are set, care for this
464 const Any
* pSelectSequenceValue
= nullptr;
466 const OUString
* pSelectedItemsPos
= std::find(
467 _rPropertyNames
.begin(), _rPropertyNames
.end(), PROPERTY_SELECT_SEQ
469 auto aStringItemListExists
= std::any_of(
470 _rPropertyNames
.begin(), _rPropertyNames
.end(),
471 [](OUString
const & s
) { return s
== PROPERTY_STRINGITEMLIST
; }
473 if ( ( pSelectedItemsPos
!= _rPropertyNames
.end() ) && aStringItemListExists
)
475 // both properties are present
476 // -> remember the value for the select sequence
477 pSelectSequenceValue
= _rValues
.getConstArray() + ( pSelectedItemsPos
- _rPropertyNames
.begin() );
480 OBoundControlModel::setPropertyValues( _rPropertyNames
, _rValues
);
482 if ( pSelectSequenceValue
)
484 setPropertyValue( PROPERTY_SELECT_SEQ
, *pSelectSequenceValue
);
485 // Note that this is the only reliable way, since one of the properties is implemented
486 // by ourself, and one is implemented by the aggregate, we cannot rely on any particular
487 // results when setting them both - too many undocumented behavior in all the involved
493 void OListBoxModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
495 OBoundControlModel::describeFixedProperties( _rProps
);
496 sal_Int32 nOldCount
= _rProps
.getLength();
497 _rProps
.realloc( nOldCount
+ 10);
498 css::beans::Property
* pProperties
= _rProps
.getArray() + nOldCount
;
499 *pProperties
++ = css::beans::Property(PROPERTY_TABINDEX
, PROPERTY_ID_TABINDEX
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::BOUND
);
500 *pProperties
++ = css::beans::Property(PROPERTY_BOUNDCOLUMN
, PROPERTY_ID_BOUNDCOLUMN
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::MAYBEVOID
);
501 *pProperties
++ = css::beans::Property(PROPERTY_LISTSOURCETYPE
, PROPERTY_ID_LISTSOURCETYPE
, cppu::UnoType
<ListSourceType
>::get(), css::beans::PropertyAttribute::BOUND
);
502 *pProperties
++ = css::beans::Property(PROPERTY_LISTSOURCE
, PROPERTY_ID_LISTSOURCE
, cppu::UnoType
<css::uno::Sequence
<OUString
>>::get(), css::beans::PropertyAttribute::BOUND
);
503 *pProperties
++ = css::beans::Property(PROPERTY_VALUE_SEQ
, PROPERTY_ID_VALUE_SEQ
, cppu::UnoType
<css::uno::Sequence
<OUString
>>::get(), css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::READONLY
| css::beans::PropertyAttribute::TRANSIENT
);
504 *pProperties
++ = css::beans::Property(PROPERTY_SELECT_VALUE_SEQ
, PROPERTY_ID_SELECT_VALUE_SEQ
, cppu::UnoType
<Sequence
< Any
>>::get(), css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::TRANSIENT
);
505 *pProperties
++ = css::beans::Property(PROPERTY_SELECT_VALUE
, PROPERTY_ID_SELECT_VALUE
, cppu::UnoType
<Any
>::get(), css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::TRANSIENT
);
506 *pProperties
++ = css::beans::Property(PROPERTY_DEFAULT_SELECT_SEQ
, PROPERTY_ID_DEFAULT_SELECT_SEQ
, cppu::UnoType
<Sequence
<sal_Int16
>>::get(), css::beans::PropertyAttribute::BOUND
);
507 *pProperties
++ = css::beans::Property(PROPERTY_STRINGITEMLIST
, PROPERTY_ID_STRINGITEMLIST
, cppu::UnoType
<Sequence
< OUString
>>::get(), css::beans::PropertyAttribute::BOUND
);
508 *pProperties
++ = css::beans::Property(PROPERTY_TYPEDITEMLIST
, PROPERTY_ID_TYPEDITEMLIST
, cppu::UnoType
<Sequence
< Any
>>::get(), css::beans::PropertyAttribute::OPTIONAL
);
509 DBG_ASSERT( pProperties
== _rProps
.getArray() + _rProps
.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
513 void OListBoxModel::_propertyChanged( const PropertyChangeEvent
& i_rEvent
)
515 if ( i_rEvent
.PropertyName
== PROPERTY_STRINGITEMLIST
)
517 ControlModelLock
aLock( *this );
518 // SYNCHRONIZED ----->
519 // our aggregate internally changed its StringItemList property - reflect this in our "overridden"
520 // version of the property
521 setNewStringItemList( i_rEvent
.NewValue
, aLock
);
522 // <----- SYNCHRONIZED
525 else if ( i_rEvent
.PropertyName
== PROPERTY_TYPEDITEMLIST
)
527 ControlModelLock
aLock( *this );
528 // SYNCHRONIZED ----->
529 // our aggregate internally changed its TypedItemList property - reflect this in our "overridden"
530 // version of the property
531 setNewTypedItemList( i_rEvent
.NewValue
, aLock
);
532 // <----- SYNCHRONIZED
535 OBoundControlModel::_propertyChanged( i_rEvent
);
539 void OListBoxModel::describeAggregateProperties( Sequence
< Property
>& _rAggregateProps
) const
541 OBoundControlModel::describeAggregateProperties( _rAggregateProps
);
543 // superseded properties:
544 RemoveProperty( _rAggregateProps
, PROPERTY_STRINGITEMLIST
);
545 RemoveProperty( _rAggregateProps
, PROPERTY_TYPEDITEMLIST
);
549 OUString SAL_CALL
OListBoxModel::getServiceName()
551 return FRM_COMPONENT_LISTBOX
; // old (non-sun) name for compatibility !
555 void SAL_CALL
OListBoxModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
)
557 OBoundControlModel::write(_rxOutStream
);
559 // Dummy sequence, to stay compatible if SelectSeq is not saved anymore
560 Sequence
<sal_Int16
> aDummySeq
;
563 // Version 0x0002: ListSource becomes StringSeq
564 _rxOutStream
->writeShort(0x0004);
567 sal_uInt16 nAnyMask
= 0;
568 if (m_aBoundColumn
.getValueType().getTypeClass() != TypeClass_VOID
)
569 nAnyMask
|= BOUNDCOLUMN
;
571 _rxOutStream
<< nAnyMask
;
573 _rxOutStream
<< lcl_convertToStringSequence( m_aListSourceValues
);
574 _rxOutStream
<< static_cast<sal_Int16
>(m_eListSourceType
);
575 _rxOutStream
<< aDummySeq
;
576 _rxOutStream
<< m_aDefaultSelectSeq
;
578 if ((nAnyMask
& BOUNDCOLUMN
) == BOUNDCOLUMN
)
580 sal_Int16 nBoundColumn
= 0;
581 m_aBoundColumn
>>= nBoundColumn
;
582 _rxOutStream
<< nBoundColumn
;
584 writeHelpTextCompatibly(_rxOutStream
);
586 // from version 0x0004 : common properties
587 writeCommonProperties(_rxOutStream
);
591 void SAL_CALL
OListBoxModel::read(const Reference
<XObjectInputStream
>& _rxInStream
)
593 // We need to respect dependencies for certain variables.
594 // Therefore, we need to set them explicitly via setPropertyValue().
596 OBoundControlModel::read(_rxInStream
);
597 ControlModelLock
aLock( *this );
599 // since we are "overwriting" the StringItemList of our aggregate (means we have
600 // an own place to store the value, instead of relying on our aggregate storing it),
601 // we need to respect what the aggregate just read for the StringItemList property.
604 if ( m_xAggregateSet
.is() )
605 setNewStringItemList( m_xAggregateSet
->getPropertyValue( PROPERTY_STRINGITEMLIST
), aLock
);
607 catch( const Exception
& )
609 TOOLS_WARN_EXCEPTION( "forms.component", "OComboBoxModel::read: caught an exception while examining the aggregate's string item list" );
613 sal_uInt16 nVersion
= _rxInStream
->readShort();
614 DBG_ASSERT(nVersion
> 0, "OListBoxModel::read : version 0 ? this should never have been written !");
616 if (nVersion
> 0x0004)
618 SAL_WARN( "forms.component", "OListBoxModel::read : invalid (means unknown) version !");
619 ValueList().swap(m_aListSourceValues
);
620 m_aBoundColumn
<<= sal_Int16(0);
622 m_eListSourceType
= ListSourceType_VALUELIST
;
623 m_aDefaultSelectSeq
.realloc(0);
624 defaultCommonProperties();
630 _rxInStream
>> nAnyMask
;
633 css::uno::Sequence
<OUString
> aListSourceSeq
;
634 if (nVersion
== 0x0001)
636 // Create ListSourceSeq from String
637 OUString sListSource
;
638 _rxInStream
>> sListSource
;
640 const sal_Int32 nTokens
{ comphelper::string::getTokenCount(sListSource
, ';') };
641 aListSourceSeq
.realloc( nTokens
);
643 for (sal_Int32 i
=0; i
<nTokens
; ++i
)
645 aListSourceSeq
.getArray()[i
] = sListSource
.getToken(0, ';', nIdx
);
649 _rxInStream
>> aListSourceSeq
;
651 sal_Int16 nListSourceType
;
652 _rxInStream
>> nListSourceType
;
653 m_eListSourceType
= static_cast<ListSourceType
>(nListSourceType
);
654 Any aListSourceSeqAny
;
655 aListSourceSeqAny
<<= aListSourceSeq
;
657 setFastPropertyValue(PROPERTY_ID_LISTSOURCE
, aListSourceSeqAny
);
659 // Dummy sequence, to stay compatible if SelectSeq is not saved anymore
660 Sequence
<sal_Int16
> aDummySeq
;
661 _rxInStream
>> aDummySeq
;
664 Sequence
<sal_Int16
> aDefaultSelectSeq
;
665 _rxInStream
>> aDefaultSelectSeq
;
666 Any aDefaultSelectSeqAny
;
667 aDefaultSelectSeqAny
<<= aDefaultSelectSeq
;
668 setFastPropertyValue(PROPERTY_ID_DEFAULT_SELECT_SEQ
, aDefaultSelectSeqAny
);
671 if ((nAnyMask
& BOUNDCOLUMN
) == BOUNDCOLUMN
)
674 _rxInStream
>> nValue
;
675 m_aBoundColumn
<<= nValue
;
677 else // the constructor initialises to 1, so if it is empty,
678 // we must explicitly set to empty
680 m_aBoundColumn
= Any();
684 readHelpTextCompatibly(_rxInStream
);
686 // if our string list is not filled from the value list, we must empty it
687 // this can be the case when somebody saves in alive mode
688 if ( ( m_eListSourceType
!= ListSourceType_VALUELIST
)
689 && !hasExternalListSource()
692 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, makeAny( css::uno::Sequence
<OUString
>() ) );
693 setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST
, makeAny( css::uno::Sequence
<css::uno::Any
>() ) );
697 readCommonProperties(_rxInStream
);
699 // Display the default values after reading
700 if ( !getControlSource().isEmpty() )
701 // (not if we don't have a control source - the "State" property acts like it is persistent, then
706 void OListBoxModel::loadData( bool _bForce
)
708 SAL_INFO( "forms.component", "OListBoxModel::loadData" );
709 DBG_ASSERT( m_eListSourceType
!= ListSourceType_VALUELIST
, "OListBoxModel::loadData: cannot load value list from DB!" );
710 DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::loadData: cannot load from DB when I have an external list source!" );
712 const sal_Int16
nNULLPosBackup( m_nNULLPos
);
713 const sal_Int32
nBoundColumnTypeBackup( m_nBoundColumnType
);
715 m_nBoundColumnType
= DataType::SQLNULL
;
719 Reference
< XConnection
> xConnection
;
720 // is the active connection of our form
721 Reference
< XPropertySet
> xFormProps( m_xCursor
, UNO_QUERY
);
722 if ( xFormProps
.is() )
723 xFormProps
->getPropertyValue( PROPERTY_ACTIVE_CONNECTION
) >>= xConnection
;
726 OUString sListSource
;
727 // if our list source type is no value list, we need to concatenate
728 // the single list source elements
730 m_aListSourceValues
.begin(),
731 m_aListSourceValues
.end(),
732 AppendRowSetValueString( sListSource
)
735 // outta here if we don't have all pre-requisites
736 if ( !xConnection
.is() || sListSource
.isEmpty() )
742 ::std::optional
< sal_Int16
> aBoundColumn(std::nullopt
);
743 if ( m_aBoundColumn
.getValueType().getTypeClass() == TypeClass_SHORT
)
745 sal_Int16
nBoundColumn( 0 );
746 m_aBoundColumn
>>= nBoundColumn
;
747 aBoundColumn
= nBoundColumn
;
750 ::utl::SharedUNOComponent
< XResultSet
> xListCursor
;
753 m_aListRowSet
.setConnection( xConnection
);
755 bool bExecute
= false;
756 switch (m_eListSourceType
)
758 case ListSourceType_TABLEFIELDS
:
759 // don't work with a statement here, the fields will be collected below
762 case ListSourceType_TABLE
:
764 Reference
<XNameAccess
> xFieldsByName
= getTableFields(xConnection
, sListSource
);
765 Reference
<XIndexAccess
> xFieldsByIndex(xFieldsByName
, UNO_QUERY
);
767 // do we have a bound column if yes we have to select it
768 // and the displayed column is the first column otherwise we act as a combobox
770 OUString aBoundFieldName
;
772 if ( !!aBoundColumn
&& ( *aBoundColumn
>= 0 ) && xFieldsByIndex
.is() )
774 if ( *aBoundColumn
>= xFieldsByIndex
->getCount() )
777 Reference
<XPropertySet
> xFieldAsSet(xFieldsByIndex
->getByIndex( *aBoundColumn
),UNO_QUERY
);
778 assert(xFieldAsSet
.is());
779 xFieldAsSet
->getPropertyValue(PROPERTY_NAME
) >>= aBoundFieldName
;
782 xFieldAsSet
.set(xFieldsByIndex
->getByIndex(0),UNO_QUERY
);
783 xFieldAsSet
->getPropertyValue(PROPERTY_NAME
) >>= aFieldName
;
785 else if (xFieldsByName
.is())
787 if ( xFieldsByName
->hasByName( getControlSource() ) )
788 aFieldName
= getControlSource();
791 // otherwise look for the alias
792 Reference
< XColumnsSupplier
> xSupplyFields
;
793 xFormProps
->getPropertyValue("SingleSelectQueryComposer") >>= xSupplyFields
;
796 DBG_ASSERT(xSupplyFields
.is(), "OListBoxModel::loadData : invalid query composer !");
798 Reference
<XNameAccess
> xFieldNames
= xSupplyFields
->getColumns();
799 if ( xFieldNames
->hasByName( getControlSource() ) )
801 Reference
<XPropertySet
> xComposerFieldAsSet
;
802 xFieldNames
->getByName( getControlSource() ) >>= xComposerFieldAsSet
;
803 if (hasProperty(PROPERTY_FIELDSOURCE
, xComposerFieldAsSet
))
804 xComposerFieldAsSet
->getPropertyValue(PROPERTY_FIELDSOURCE
) >>= aFieldName
;
808 if (aFieldName
.isEmpty())
811 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
812 OUString aQuote
= xMeta
->getIdentifierQuoteString();
813 OUString
aStatement("SELECT ");
814 if (aBoundFieldName
.isEmpty()) // act like a combobox
815 aStatement
+= "DISTINCT ";
817 aStatement
+= quoteName(aQuote
,aFieldName
);
818 if (!aBoundFieldName
.isEmpty())
820 aStatement
+= ", " + quoteName(aQuote
, aBoundFieldName
);
822 aStatement
+= " FROM ";
824 OUString sCatalog
, sSchema
, sTable
;
825 qualifiedNameComponents( xMeta
, sListSource
, sCatalog
, sSchema
, sTable
, EComposeRule::InDataManipulation
);
826 aStatement
+= composeTableNameForSelect( xConnection
, sCatalog
, sSchema
, sTable
);
828 m_aListRowSet
.setEscapeProcessing( false );
829 m_aListRowSet
.setCommand( aStatement
);
834 case ListSourceType_QUERY
:
835 m_aListRowSet
.setCommandFromQuery( sListSource
);
840 m_aListRowSet
.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH
!= m_eListSourceType
);
841 m_aListRowSet
.setCommand( sListSource
);
848 if ( !_bForce
&& !m_aListRowSet
.isDirty() )
850 // if none of the settings of the row set changed, compared to the last
851 // invocation of loadData, then don't re-fill the list. Instead, assume
852 // the list entries are the same.
853 m_nNULLPos
= nNULLPosBackup
;
854 m_nBoundColumnType
= nBoundColumnTypeBackup
;
857 xListCursor
.reset( m_aListRowSet
.execute() );
860 catch(const SQLException
& eSQL
)
862 onError(eSQL
, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST
));
865 catch(const Exception
&)
870 // Fill display and value lists
871 ValueList aDisplayList
, aValueList
;
872 bool bUseNULL
= hasField() && !isRequired();
874 // empty BoundColumn is treated as BoundColumn==0,
880 OSL_ENSURE( xListCursor
.is() || ( ListSourceType_TABLEFIELDS
== m_eListSourceType
),
881 "OListBoxModel::loadData: logic error!" );
882 if ( !xListCursor
.is() && ( ListSourceType_TABLEFIELDS
!= m_eListSourceType
) )
885 switch (m_eListSourceType
)
887 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
888 case ListSourceType_SQL
:
889 case ListSourceType_SQLPASSTHROUGH
:
890 case ListSourceType_TABLE
:
891 case ListSourceType_QUERY
:
893 // Get field of the ResultSet's 1st column
894 Reference
<XColumnsSupplier
> xSupplyCols(xListCursor
, UNO_QUERY
);
895 DBG_ASSERT(xSupplyCols
.is(), "OListBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
896 Reference
<XIndexAccess
> xColumns
;
897 if (xSupplyCols
.is())
899 xColumns
.set(xSupplyCols
->getColumns(), UNO_QUERY
);
900 DBG_ASSERT(xColumns
.is(), "OListBoxModel::loadData : no columns supplied by the row set !");
903 Reference
< XPropertySet
> xDataField
;
905 xColumns
->getByIndex(0) >>= xDataField
;
906 if ( !xDataField
.is() )
909 ::dbtools::FormattedColumnValue
aValueFormatter( getContext(), m_xCursor
, xDataField
);
911 // Get the field of BoundColumn of the ResultSet
912 m_nBoundColumnType
= DataType::SQLNULL
;
913 if ( *aBoundColumn
>= 0 )
917 Reference
< XPropertySet
> xBoundField( xColumns
->getByIndex( *aBoundColumn
), UNO_QUERY_THROW
);
918 OSL_VERIFY( xBoundField
->getPropertyValue("Type") >>= m_nBoundColumnType
);
920 catch( const Exception
& )
922 DBG_UNHANDLED_EXCEPTION("forms.component");
925 else if ( *aBoundColumn
== -1)
926 m_nBoundColumnType
= DataType::SMALLINT
;
928 // If the LB is bound to a field and empty entries are valid, we remember the position
929 // for an empty entry
930 SAL_INFO( "forms.component", "OListBoxModel::loadData: string collection" );
932 sal_Int16 entryPos
= 0;
933 ORowSetValue aBoundValue
;
934 Reference
< XRow
> xCursorRow( xListCursor
, UNO_QUERY_THROW
);
935 while ( xListCursor
->next() && ( entryPos
++ < SHRT_MAX
) ) // SHRT_MAX is the maximum number of entries
937 aStr
= aValueFormatter
.getFormattedValue();
938 aDisplayList
.emplace_back(aStr
);
940 if(*aBoundColumn
>= 0)
941 aBoundValue
.fill( *aBoundColumn
+ 1, m_nBoundColumnType
, xCursorRow
);
943 // -1 because getRow() is 1-indexed, but ListBox positions are 0-indexed
944 aBoundValue
= static_cast<sal_Int16
>(xListCursor
->getRow()-1);
945 aValueList
.push_back( aBoundValue
);
947 if ( m_nNULLPos
== -1 && aBoundValue
.isNull() )
948 m_nNULLPos
= sal_Int16( aDisplayList
.size() - 1 );
949 if ( bUseNULL
&& ( m_nNULLPos
== -1 ) && aStr
.isEmpty() )
950 // There is already a non-NULL entry with empty display string;
951 // adding another one for NULL would make things confusing,
958 case ListSourceType_TABLEFIELDS
:
960 Reference
<XNameAccess
> xFieldNames
= getTableFields(xConnection
, sListSource
);
961 if (xFieldNames
.is())
963 const css::uno::Sequence
<OUString
> seqNames
= xFieldNames
->getElementNames();
967 ::std::insert_iterator
< ValueList
>( aDisplayList
, aDisplayList
.end() )
969 if(*aBoundColumn
== -1)
971 // the type of i matters! It will be the type of the ORowSetValue pushed to aValueList!
972 for(size_t i
=0; i
< aDisplayList
.size(); ++i
)
974 aValueList
.emplace_back(sal_Int16(i
));
979 aValueList
= aDisplayList
;
985 SAL_WARN( "forms.component", "OListBoxModel::loadData: unreachable!" );
989 catch(const SQLException
& eSQL
)
991 onError(eSQL
, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST
));
994 catch( const Exception
& )
996 DBG_UNHANDLED_EXCEPTION("forms.component");
1001 // Create Values sequence
1003 if (bUseNULL
&& m_nNULLPos
== -1)
1005 aValueList
.insert( aValueList
.begin(), ORowSetValue() );
1007 aDisplayList
.insert( aDisplayList
.begin(), ORowSetValue( OUString() ) );
1011 setBoundValues(std::move(aValueList
));
1013 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, makeAny( lcl_convertToStringSequence( aDisplayList
) ) );
1014 setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST
, makeAny( css::uno::Sequence
<css::uno::Any
>() ) );
1018 void OListBoxModel::onConnectedDbColumn( const Reference
< XInterface
>& /*_rxForm*/ )
1020 // list boxes which are bound to a db column don't have multi selection
1021 // - this would be unable to reflect in the db column
1024 setFastPropertyValue( PROPERTY_ID_MULTISELECTION
, css::uno::Any(false) );
1027 if ( !hasExternalListSource() )
1028 impl_refreshDbEntryList( false );
1032 void OListBoxModel::onDisconnectedDbColumn()
1036 m_nBoundColumnType
= DataType::SQLNULL
;
1038 if ( m_eListSourceType
!= ListSourceType_VALUELIST
)
1040 if ( !hasExternalListSource() )
1041 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, makeAny( css::uno::Sequence
<OUString
>() ) );
1043 m_aListRowSet
.dispose();
1048 void OListBoxModel::setBoundValues(ValueList
&& l
)
1050 m_aConvertedBoundValues
.clear();
1051 m_aBoundValues
= std::move(l
);
1055 void OListBoxModel::clearBoundValues()
1057 ValueList().swap(m_aConvertedBoundValues
);
1058 ValueList().swap(m_aBoundValues
);
1062 void OListBoxModel::convertBoundValues(const sal_Int32 nFieldType
) const
1064 assert(s_aEmptyValue
.isNull());
1066 m_aConvertedBoundValues
.resize(m_aBoundValues
.size());
1067 ValueList::iterator dst
= m_aConvertedBoundValues
.begin();
1069 for (auto const& src
: m_aBoundValues
)
1071 if(m_nNULLPos
== -1 &&
1073 (src
== s_aEmptyStringValue
|| src
== s_aEmptyValue
|| src
.isNull()) )
1082 dst
->setTypeKind(nFieldType
);
1086 m_nConvertedBoundValuesType
= nFieldType
;
1087 OSL_ENSURE(dst
== m_aConvertedBoundValues
.end(), "OListBoxModel::convertBoundValues expected to have overwritten all of m_aConvertedBoundValues, but did not.");
1088 assert(dst
== m_aConvertedBoundValues
.end());
1091 sal_Int32
OListBoxModel::getValueType() const
1093 return (m_nBoundColumnType
!= css::sdbc::DataType::SQLNULL
) ?
1094 m_nBoundColumnType
:
1095 ( hasField() ? getFieldType() : DataType::VARCHAR
);
1098 ValueList
OListBoxModel::impl_getValues() const
1100 const sal_Int32 nFieldType
= getValueType();
1102 if ( !m_aConvertedBoundValues
.empty() && m_nConvertedBoundValuesType
== nFieldType
)
1103 return m_aConvertedBoundValues
;
1105 if ( !m_aBoundValues
.empty() )
1107 convertBoundValues(nFieldType
);
1108 return m_aConvertedBoundValues
;
1111 const std::vector
< OUString
>& aStringItems( getStringItemList() );
1112 ValueList
aValues( aStringItems
.size() );
1113 ValueList::iterator dst
= aValues
.begin();
1114 for (auto const& src
: aStringItems
)
1117 dst
->setTypeKind(nFieldType
);
1120 m_nConvertedBoundValuesType
= nFieldType
;
1121 OSL_ENSURE(dst
== aValues
.end(), "OListBoxModel::impl_getValues expected to have set all of aValues, but did not.");
1122 assert(dst
== aValues
.end());
1126 ORowSetValue
OListBoxModel::getFirstSelectedValue() const
1128 DBG_ASSERT( m_xAggregateFastSet
.is(), "OListBoxModel::getFirstSelectedValue: invalid aggregate!" );
1129 if ( !m_xAggregateFastSet
.is() )
1130 return s_aEmptyValue
;
1132 Sequence
< sal_Int16
> aSelectedIndices
;
1133 OSL_VERIFY( m_xAggregateFastSet
->getFastPropertyValue( getValuePropertyAggHandle() ) >>= aSelectedIndices
);
1134 if ( !aSelectedIndices
.hasElements() )
1135 // nothing selected at all
1136 return s_aEmptyValue
;
1138 if ( ( m_nNULLPos
!= -1 ) && ( aSelectedIndices
[0] == m_nNULLPos
) )
1139 // the dedicated "NULL" entry is selected
1140 return s_aEmptyValue
;
1142 ValueList
aValues( impl_getValues() );
1144 size_t selectedValue
= aSelectedIndices
[0];
1145 if ( selectedValue
>= aValues
.size() )
1147 SAL_WARN( "forms.component", "OListBoxModel::getFirstSelectedValue: inconsistent selection/valuelist!" );
1148 return s_aEmptyValue
;
1151 return aValues
[ selectedValue
];
1155 bool OListBoxModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
1157 // current selection list
1158 const ORowSetValue
aCurrentValue( getFirstSelectedValue() );
1159 if ( aCurrentValue
!= m_aSaveValue
)
1161 if ( aCurrentValue
.isNull() )
1162 m_xColumnUpdate
->updateNull();
1167 m_xColumnUpdate
->updateObject( aCurrentValue
.makeAny() );
1169 catch ( const Exception
& )
1174 m_aSaveValue
= aCurrentValue
;
1180 Sequence
< sal_Int16
> OListBoxModel::translateDbValueToControlValue(const ORowSetValue
&i_aValue
) const
1182 Sequence
< sal_Int16
> aSelectionIndicies
;
1184 // reset selection for NULL values
1185 if ( i_aValue
.isNull() )
1187 if ( m_nNULLPos
!= -1 )
1189 aSelectionIndicies
= { m_nNULLPos
};
1194 ValueList
aValues( impl_getValues() );
1195 assert( m_nConvertedBoundValuesType
== getValueType());
1196 ORowSetValue
v(i_aValue
);
1197 v
.setTypeKind( m_nConvertedBoundValuesType
);
1198 ValueList::const_iterator curValuePos
= ::std::find( aValues
.begin(), aValues
.end(), v
);
1199 if ( curValuePos
!= aValues
.end() )
1201 aSelectionIndicies
= { o3tl::narrowing
<sal_Int16
>(curValuePos
- aValues
.begin()) };
1205 return aSelectionIndicies
;
1208 Sequence
< sal_Int16
> OListBoxModel::translateBindingValuesToControlValue(const Sequence
< const Any
> &i_aValues
) const
1210 const ValueList
aValues( impl_getValues() );
1211 assert( m_nConvertedBoundValuesType
== getValueType());
1212 Sequence
< sal_Int16
> aSelectionIndicies(i_aValues
.getLength());
1214 sal_Int32
nCount(0);
1216 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1217 sal_Int16
*pIndex
= aSelectionIndicies
.getArray();
1218 for ( auto const & value
: i_aValues
)
1220 if ( value
.hasValue() )
1224 v
.setTypeKind( m_nConvertedBoundValuesType
);
1225 ValueList::const_iterator curValuePos
= ::std::find( aValues
.begin(), aValues
.end(), v
);
1226 if ( curValuePos
!= aValues
.end() )
1228 *pIndex
= curValuePos
- aValues
.begin();
1235 if ( m_nNULLPos
!= -1 )
1237 *pIndex
= m_nNULLPos
;
1243 assert(aSelectionIndicies
.getArray() + nCount
== pIndex
);
1245 aSelectionIndicies
.realloc(nCount
);
1246 return aSelectionIndicies
;
1249 Any
OListBoxModel::translateDbColumnToControlValue()
1251 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1252 Reference
< XPropertySet
> xBoundField( getField() );
1253 if ( !xBoundField
.is() )
1255 SAL_WARN( "forms.component", "OListBoxModel::translateDbColumnToControlValue: no field? How could that happen?!" );
1259 ORowSetValue aCurrentValue
;
1260 aCurrentValue
.fill( getValueType(), m_xColumn
);
1262 m_aSaveValue
= aCurrentValue
;
1264 return makeAny( translateDbValueToControlValue(aCurrentValue
) );
1272 Any
OListBoxModel::getDefaultForReset() const
1275 if (m_aDefaultSelectSeq
.hasElements())
1276 aValue
<<= m_aDefaultSelectSeq
;
1277 else if (m_nNULLPos
!= -1) // bound Listbox
1279 Sequence
<sal_Int16
> aSeq
{ m_nNULLPos
};
1284 Sequence
<sal_Int16
> aSeq
;
1292 void OListBoxModel::resetNoBroadcast()
1294 OBoundControlModel::resetNoBroadcast();
1295 m_aSaveValue
.setNull();
1299 void SAL_CALL
OListBoxModel::disposing( const EventObject
& _rSource
)
1301 if ( !OEntryListHelper::handleDisposing( _rSource
) )
1302 OBoundControlModel::disposing( _rSource
);
1308 // The type of how we should transfer our selection to external value bindings
1311 eIndexList
, /// as list of indexes of selected entries
1312 eIndex
, /// as index of the selected entry
1313 eEntryList
, /// as list of string representations of selected *display* entries
1314 eEntry
, /// as string representation of the selected *display* entry
1315 eValueList
, /// as list of string representations of selected values
1316 eValue
/// as string representation of the selected value
1320 ExchangeType
lcl_getCurrentExchangeType( const Type
& _rExchangeType
)
1322 switch ( _rExchangeType
.getTypeClass() )
1326 case TypeClass_STRING
:
1328 case TypeClass_LONG
:
1330 case TypeClass_SEQUENCE
:
1332 Type aElementType
= ::comphelper::getSequenceElementType( _rExchangeType
);
1333 switch ( aElementType
.getTypeClass() )
1337 case TypeClass_STRING
:
1339 case TypeClass_LONG
:
1349 SAL_WARN( "forms.component", "lcl_getCurrentExchangeType: unsupported (unexpected) exchange type!" );
1355 Any
OListBoxModel::translateExternalValueToControlValue( const Any
& _rExternalValue
) const
1357 Sequence
< sal_Int16
> aSelectIndexes
;
1359 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1363 Sequence
< const Any
> aExternalValues
;
1364 OSL_VERIFY( _rExternalValue
>>= aExternalValues
);
1365 aSelectIndexes
= translateBindingValuesToControlValue( aExternalValues
);
1370 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1373 v
.fill(_rExternalValue
);
1374 aSelectIndexes
= translateDbValueToControlValue(v
);
1381 // unfortunately, our select sequence is a sequence<short>, while the external binding
1382 // supplies sequence<int> only -> transform this
1383 Sequence
< sal_Int32
> aSelectIndexesPure
;
1384 OSL_VERIFY( _rExternalValue
>>= aSelectIndexesPure
);
1385 aSelectIndexes
.realloc( aSelectIndexesPure
.getLength() );
1387 std::cbegin(aSelectIndexesPure
),
1388 std::cend(aSelectIndexesPure
),
1389 aSelectIndexes
.getArray()
1396 sal_Int32 nSelectIndex
= -1;
1397 OSL_VERIFY( _rExternalValue
>>= nSelectIndex
);
1398 if ( ( nSelectIndex
>= 0 ) && ( nSelectIndex
< static_cast<sal_Int32
>(getStringItemList().size()) ) )
1400 aSelectIndexes
= { o3tl::narrowing
<sal_Int16
>(nSelectIndex
) };
1407 // we can retrieve a string list from the binding for multiple selection
1408 Sequence
< OUString
> aSelectEntries
;
1409 OSL_VERIFY( _rExternalValue
>>= aSelectEntries
);
1411 ::std::set
< sal_Int16
> aSelectionSet
;
1413 // find the selection entries in our item list
1414 for ( OUString
const & selectEntry
: std::as_const(aSelectEntries
) )
1417 for(const OUString
& s
: getStringItemList())
1420 aSelectionSet
.insert(idx
);
1425 // copy the indexes to the sequence
1426 aSelectIndexes
= comphelper::containerToSequence( aSelectionSet
);
1432 OUString sStringToSelect
;
1433 OSL_VERIFY( _rExternalValue
>>= sStringToSelect
);
1434 ::std::set
< sal_Int16
> aSelectionSet
;
1436 for(const OUString
& s
: getStringItemList())
1438 if (s
==sStringToSelect
)
1439 aSelectionSet
.insert(idx
);
1443 aSelectIndexes
= comphelper::containerToSequence( aSelectionSet
);
1448 return makeAny( aSelectIndexes
);
1455 struct ExtractStringFromSequence_Safe
1458 const std::vector
< OUString
>& m_rList
;
1461 explicit ExtractStringFromSequence_Safe( const std::vector
< OUString
>& _rList
) : m_rList( _rList
) { }
1463 OUString
operator ()( sal_Int16 _nIndex
)
1465 OSL_ENSURE( _nIndex
< static_cast<sal_Int32
>(m_rList
.size()), "ExtractStringFromSequence_Safe: inconsistence!" );
1466 if ( _nIndex
< static_cast<sal_Int32
>(m_rList
.size()) )
1467 return m_rList
[ _nIndex
];
1473 Any
lcl_getSingleSelectedEntryTyped( const Sequence
< sal_Int16
>& _rSelectSequence
, const Sequence
<Any
>& _rTypedList
)
1477 // by definition, multiple selected entries are transferred as NULL if the
1478 // binding does not support lists
1479 if ( _rSelectSequence
.getLength() <= 1 )
1481 if ( _rSelectSequence
.getLength() == 1 )
1483 sal_Int32 nIndex
= _rSelectSequence
[0];
1484 if (0 <= nIndex
&& nIndex
< _rTypedList
.getLength())
1485 aReturn
= _rTypedList
[nIndex
];
1493 Any
lcl_getSingleSelectedEntry( const Sequence
< sal_Int16
>& _rSelectSequence
, const std::vector
< OUString
>& _rStringList
)
1497 // by definition, multiple selected entries are transferred as NULL if the
1498 // binding does not support string lists
1499 if ( _rSelectSequence
.getLength() <= 1 )
1501 OUString sSelectedEntry
;
1503 if ( _rSelectSequence
.getLength() == 1 )
1504 sSelectedEntry
= ExtractStringFromSequence_Safe( _rStringList
)( _rSelectSequence
[0] );
1506 aReturn
<<= sSelectedEntry
;
1513 Any
lcl_getMultiSelectedEntries( const Sequence
< sal_Int16
>& _rSelectSequence
, const std::vector
< OUString
>& _rStringList
)
1515 Sequence
< OUString
> aSelectedEntriesTexts( _rSelectSequence
.getLength() );
1517 _rSelectSequence
.begin(),
1518 _rSelectSequence
.end(),
1519 aSelectedEntriesTexts
.getArray(),
1520 ExtractStringFromSequence_Safe( _rStringList
)
1522 return makeAny( aSelectedEntriesTexts
);
1526 struct ExtractAnyFromValueList_Safe
1529 const ValueList
& m_rList
;
1532 explicit ExtractAnyFromValueList_Safe( const ValueList
& _rList
) : m_rList( _rList
) { }
1534 Any
operator ()( sal_Int16 _nIndex
)
1536 OSL_ENSURE( o3tl::make_unsigned(_nIndex
) < m_rList
.size(), "ExtractAnyFromValueList: inconsistence!" );
1537 if ( o3tl::make_unsigned(_nIndex
) < m_rList
.size() )
1538 return m_rList
[ _nIndex
].makeAny();
1544 Any
lcl_getSingleSelectedEntryAny( const Sequence
< sal_Int16
>& _rSelectSequence
, const ValueList
& _rStringList
)
1548 // by definition, multiple selected entries are transferred as NULL if the
1549 // binding does not support string lists
1550 if ( _rSelectSequence
.getLength() <= 1 )
1552 if ( _rSelectSequence
.getLength() == 1 )
1553 aReturn
= ExtractAnyFromValueList_Safe( _rStringList
)( _rSelectSequence
[0] );
1560 Sequence
< Any
> lcl_getMultiSelectedEntriesAny( const Sequence
< sal_Int16
>& _rSelectSequence
, const ValueList
& _rStringList
)
1562 Sequence
< Any
> aSelectedEntriesValues( _rSelectSequence
.getLength() );
1564 _rSelectSequence
.begin(),
1565 _rSelectSequence
.end(),
1566 aSelectedEntriesValues
.getArray(),
1567 ExtractAnyFromValueList_Safe( _rStringList
)
1569 return aSelectedEntriesValues
;
1574 Any
OListBoxModel::translateControlValueToExternalValue( ) const
1576 OSL_PRECOND( hasExternalValueBinding(), "OListBoxModel::translateControlValueToExternalValue: no binding!" );
1578 Sequence
< sal_Int16
> aSelectSequence
;
1579 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1582 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1585 aReturn
<<= getCurrentMultiValue();
1589 aReturn
= getCurrentSingleValue();
1594 // unfortunately, the select sequence is a sequence<short>, but our binding
1596 Sequence
< sal_Int32
> aTransformed( aSelectSequence
.getLength() );
1598 std::cbegin(aSelectSequence
),
1599 std::cend(aSelectSequence
),
1600 aTransformed
.getArray()
1602 aReturn
<<= aTransformed
;
1607 if ( aSelectSequence
.getLength() <= 1 )
1609 sal_Int32 nIndex
= -1;
1611 if ( aSelectSequence
.getLength() == 1 )
1612 nIndex
= aSelectSequence
[0];
1619 aReturn
= lcl_getMultiSelectedEntries( aSelectSequence
, getStringItemList() );
1624 const std::vector
<OUString
>& rStrings
= getStringItemList();
1625 const Sequence
<Any
>& rValues
= getTypedItemList();
1626 if (rStrings
.size() == static_cast<size_t>(rValues
.getLength()))
1627 aReturn
= lcl_getSingleSelectedEntryTyped( aSelectSequence
, rValues
);
1629 aReturn
= lcl_getSingleSelectedEntry( aSelectSequence
, rStrings
);
1638 Any
OListBoxModel::translateControlValueToValidatableValue( ) const
1640 OSL_PRECOND( hasValidator(), "OListBoxModel::translateControlValueToValidatableValue: no validator, so why should I?" );
1641 return getCurrentFormComponentValue();
1645 Any
OListBoxModel::getCurrentSingleValue() const
1651 Sequence
< sal_Int16
> aSelectSequence
;
1652 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1653 aCurrentValue
= lcl_getSingleSelectedEntryAny( aSelectSequence
, impl_getValues() );
1655 catch( const Exception
& )
1657 DBG_UNHANDLED_EXCEPTION("forms.component");
1660 return aCurrentValue
;
1663 Sequence
< Any
> OListBoxModel::getCurrentMultiValue() const
1665 Sequence
< Any
> aCurrentValue
;
1669 Sequence
< sal_Int16
> aSelectSequence
;
1670 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1671 aCurrentValue
= lcl_getMultiSelectedEntriesAny( aSelectSequence
, impl_getValues() );
1673 catch( const Exception
& )
1675 DBG_UNHANDLED_EXCEPTION("forms.component");
1678 return aCurrentValue
;
1681 Any
OListBoxModel::getCurrentFormComponentValue() const
1684 Reference
< css::form::validation::XValidator
> vtor (const_cast<OListBoxModel
*>(this)->getValidator());
1685 Reference
< XValueBinding
> extBinding (const_cast<OListBoxModel
*>(this)->getValueBinding());
1686 if ( vtor
.is() && vtor
== extBinding
)
1687 return translateControlValueToExternalValue();
1694 bool bMultiSelection( false );
1695 OSL_VERIFY( const_cast< OListBoxModel
* >( this )->getPropertyValue( PROPERTY_MULTISELECTION
) >>= bMultiSelection
);
1697 if ( bMultiSelection
)
1698 aCurrentValue
<<= getCurrentMultiValue();
1700 aCurrentValue
= getCurrentSingleValue();
1702 catch( const Exception
& )
1704 DBG_UNHANDLED_EXCEPTION("forms.component");
1707 return aCurrentValue
;
1711 Sequence
< Type
> OListBoxModel::getSupportedBindingTypes()
1715 cppu::UnoType
<Sequence
< Any
>>::get(),
1716 cppu::UnoType
<Any
>::get(),
1717 cppu::UnoType
<Sequence
< sal_Int32
>>::get(),
1718 cppu::UnoType
<sal_Int32
>::get(),
1719 cppu::UnoType
<Sequence
< OUString
>>::get(),
1720 cppu::UnoType
<OUString
>::get()
1725 void OListBoxModel::stringItemListChanged( ControlModelLock
& _rInstanceLock
)
1727 if ( !m_xAggregateSet
.is() )
1730 suspendValueListening();
1733 m_xAggregateSet
->setPropertyValue( PROPERTY_STRINGITEMLIST
, makeAny( comphelper::containerToSequence(getStringItemList()) ) );
1734 m_xAggregateSet
->setPropertyValue( PROPERTY_TYPEDITEMLIST
, makeAny( getTypedItemList() ) );
1736 catch( const Exception
& )
1738 DBG_UNHANDLED_EXCEPTION("forms.component");
1740 resumeValueListening();
1742 // update the selection here
1743 if ( hasExternalValueBinding( ) )
1744 transferExternalValueToControl( _rInstanceLock
);
1749 // TODO: update the selection in case we're bound to a database column
1753 if ( m_aDefaultSelectSeq
.hasElements() )
1754 setControlValue( makeAny( m_aDefaultSelectSeq
), eOther
);
1760 void OListBoxModel::impl_refreshDbEntryList( bool _bForce
)
1762 DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::impl_refreshDbEntryList: invalid call!" );
1764 if ( !hasExternalListSource( )
1765 && ( m_eListSourceType
!= ListSourceType_VALUELIST
)
1766 && ( m_xCursor
.is() )
1769 loadData( _bForce
);
1774 void OListBoxModel::refreshInternalEntryList()
1776 impl_refreshDbEntryList( true );
1777 if ( hasField() && m_xCursor
.is() )
1778 initFromField( m_xCursor
);
1784 Sequence
< Type
> OListBoxControl::_getTypes()
1787 OBoundControl::_getTypes(),
1788 OListBoxControl_BASE::getTypes()
1793 Any SAL_CALL
OListBoxControl::queryAggregation(const Type
& _rType
)
1795 Any aReturn
= OListBoxControl_BASE::queryInterface( _rType
);
1797 if ( !aReturn
.hasValue()
1798 || _rType
.equals( cppu::UnoType
<XTypeProvider
>::get() )
1800 aReturn
= OBoundControl::queryAggregation( _rType
);
1806 OListBoxControl::OListBoxControl(const Reference
<XComponentContext
>& _rxFactory
)
1807 :OBoundControl( _rxFactory
, VCL_CONTROL_LISTBOX
, false )
1808 ,m_aChangeListeners( m_aMutex
)
1809 ,m_aItemListeners( m_aMutex
)
1810 ,m_aChangeIdle("forms OListBoxControl m_aChangedIdle")
1813 osl_atomic_increment(&m_refCount
);
1815 // Register as FocusListener
1816 Reference
<XWindow
> xComp
;
1817 if (query_aggregation(m_xAggregate
, xComp
))
1818 xComp
->addFocusListener(this);
1820 // Register as ItemListener
1821 if ( query_aggregation( m_xAggregate
, m_xAggregateListBox
) )
1822 m_xAggregateListBox
->addItemListener(this);
1824 // Refcount at 2 for registered Listener
1825 osl_atomic_decrement(&m_refCount
);
1829 m_aChangeIdle
.SetPriority(TaskPriority::LOWEST
);
1830 m_aChangeIdle
.SetInvokeHandler(LINK(this,OListBoxControl
,OnTimeout
));
1834 OListBoxControl::~OListBoxControl()
1836 if (!OComponentHelper::rBHelper
.bDisposed
)
1843 m_xAggregateListBox
.clear();
1848 css::uno::Sequence
<OUString
> SAL_CALL
OListBoxControl::getSupportedServiceNames()
1850 css::uno::Sequence
<OUString
> aSupported
= OBoundControl::getSupportedServiceNames();
1851 aSupported
.realloc(aSupported
.getLength() + 2);
1853 OUString
* pArray
= aSupported
.getArray();
1854 pArray
[aSupported
.getLength()-2] = FRM_SUN_CONTROL_LISTBOX
;
1855 pArray
[aSupported
.getLength()-1] = STARDIV_ONE_FORM_CONTROL_LISTBOX
;
1862 void SAL_CALL
OListBoxControl::focusGained(const FocusEvent
& /*_rEvent*/)
1864 ::osl::MutexGuard
aGuard(m_aMutex
);
1865 if ( m_aChangeListeners
.getLength() ) // only if there are listeners
1867 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1870 // memorize the current selection for posting the change event
1871 m_aCurrentSelection
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1877 void SAL_CALL
OListBoxControl::focusLost(const FocusEvent
& /*_rEvent*/)
1879 m_aCurrentSelection
.clear();
1884 void SAL_CALL
OListBoxControl::itemStateChanged(const ItemEvent
& _rEvent
)
1886 // forward this to our listeners
1887 Reference
< XChild
> xChild( getModel(), UNO_QUERY
);
1888 if ( xChild
.is() && xChild
->getParent().is() )
1890 ::osl::MutexGuard
aGuard( m_aMutex
);
1891 if ( m_aItemListeners
.getLength() )
1893 if ( !m_pItemBroadcaster
.is() )
1895 m_pItemBroadcaster
.set(
1896 new ::comphelper::AsyncEventNotifier("ListBox"));
1897 m_pItemBroadcaster
->launch();
1899 m_pItemBroadcaster
->addEvent( new ItemEventDescription( _rEvent
), this );
1903 m_aItemListeners
.notifyEach( &XItemListener::itemStateChanged
, _rEvent
);
1905 // and do the handling for the ChangeListeners
1906 osl::MutexGuard
aGuard(m_aMutex
);
1907 if ( m_aChangeIdle
.IsActive() )
1909 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1910 m_aCurrentSelection
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1912 m_aChangeIdle
.Stop();
1913 m_aChangeIdle
.Start();
1917 if ( m_aChangeListeners
.getLength() && m_aCurrentSelection
.hasValue() )
1919 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1922 // Has the selection been changed?
1923 bool bModified(false);
1924 Any aValue
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1926 Sequence
<sal_Int16
> const & rSelection
= *o3tl::doAccess
<Sequence
<sal_Int16
>>(aValue
);
1927 Sequence
<sal_Int16
> const & rOldSelection
= *o3tl::doAccess
<Sequence
<sal_Int16
>>(m_aCurrentSelection
);
1928 sal_Int32 nLen
= rSelection
.getLength();
1929 if (nLen
!= rOldSelection
.getLength())
1933 const sal_Int16
* pVal
= rSelection
.getConstArray();
1934 const sal_Int16
* pCompVal
= rOldSelection
.getConstArray();
1936 while (nLen
-- && !bModified
)
1937 bModified
= pVal
[nLen
] != pCompVal
[nLen
];
1942 m_aCurrentSelection
= aValue
;
1943 m_aChangeIdle
.Start();
1947 else if (m_aCurrentSelection
.hasValue())
1948 m_aCurrentSelection
.clear();
1954 void SAL_CALL
OListBoxControl::disposing(const EventObject
& _rSource
)
1956 OBoundControl::disposing(_rSource
);
1959 // XChangeBroadcaster
1961 void SAL_CALL
OListBoxControl::addChangeListener(const Reference
<XChangeListener
>& _rxListener
)
1963 m_aChangeListeners
.addInterface( _rxListener
);
1967 void SAL_CALL
OListBoxControl::removeChangeListener(const Reference
<XChangeListener
>& _rxListener
)
1969 m_aChangeListeners
.removeInterface( _rxListener
);
1974 void OListBoxControl::disposing()
1976 if (m_aChangeIdle
.IsActive())
1977 m_aChangeIdle
.Stop();
1979 EventObject
aEvent( *this );
1980 m_aChangeListeners
.disposeAndClear( aEvent
);
1981 m_aItemListeners
.disposeAndClear( aEvent
);
1983 rtl::Reference
< comphelper::AsyncEventNotifier
> t
;
1985 ::osl::MutexGuard
aGuard( m_aMutex
);
1986 if ( m_pItemBroadcaster
.is() )
1988 t
= m_pItemBroadcaster
;
1989 m_pItemBroadcaster
->removeEventsForProcessor( this );
1990 m_pItemBroadcaster
->terminate();
1991 m_pItemBroadcaster
= nullptr;
1998 OBoundControl::disposing();
2002 void OListBoxControl::processEvent( const AnyEvent
& _rEvent
)
2004 Reference
< XListBox
> xKeepAlive( this );
2006 ::osl::MutexGuard
aGuard( m_aMutex
);
2007 if ( OComponentHelper::rBHelper
.bDisposed
)
2010 const ItemEventDescription
& rItemEvent
= static_cast< const ItemEventDescription
& >( _rEvent
);
2011 m_aItemListeners
.notifyEach( &XItemListener::itemStateChanged
, rItemEvent
.getEventObject() );
2015 IMPL_LINK_NOARG(OListBoxControl
, OnTimeout
, Timer
*, void)
2017 m_aChangeListeners
.notifyEach( &XChangeListener::changed
, EventObject( *this ) );
2021 void SAL_CALL
OListBoxControl::addItemListener( const Reference
< XItemListener
>& l
)
2023 m_aItemListeners
.addInterface( l
);
2027 void SAL_CALL
OListBoxControl::removeItemListener( const Reference
< XItemListener
>& l
)
2029 m_aItemListeners
.removeInterface( l
);
2033 void SAL_CALL
OListBoxControl::addActionListener( const Reference
< XActionListener
>& l
)
2035 if ( m_xAggregateListBox
.is() )
2036 m_xAggregateListBox
->addActionListener( l
);
2040 void SAL_CALL
OListBoxControl::removeActionListener( const Reference
< XActionListener
>& l
)
2042 if ( m_xAggregateListBox
.is() )
2043 m_xAggregateListBox
->removeActionListener( l
);
2047 void SAL_CALL
OListBoxControl::addItem( const OUString
& aItem
, ::sal_Int16 nPos
)
2049 if ( m_xAggregateListBox
.is() )
2050 m_xAggregateListBox
->addItem( aItem
, nPos
);
2054 void SAL_CALL
OListBoxControl::addItems( const Sequence
< OUString
>& aItems
, ::sal_Int16 nPos
)
2056 if ( m_xAggregateListBox
.is() )
2057 m_xAggregateListBox
->addItems( aItems
, nPos
);
2061 void SAL_CALL
OListBoxControl::removeItems( ::sal_Int16 nPos
, ::sal_Int16 nCount
)
2063 if ( m_xAggregateListBox
.is() )
2064 m_xAggregateListBox
->removeItems( nPos
, nCount
);
2068 ::sal_Int16 SAL_CALL
OListBoxControl::getItemCount( )
2070 if ( m_xAggregateListBox
.is() )
2071 return m_xAggregateListBox
->getItemCount();
2076 OUString SAL_CALL
OListBoxControl::getItem( ::sal_Int16 nPos
)
2078 if ( m_xAggregateListBox
.is() )
2079 return m_xAggregateListBox
->getItem( nPos
);
2084 Sequence
< OUString
> SAL_CALL
OListBoxControl::getItems( )
2086 if ( m_xAggregateListBox
.is() )
2087 return m_xAggregateListBox
->getItems();
2088 return Sequence
< OUString
>( );
2092 ::sal_Int16 SAL_CALL
OListBoxControl::getSelectedItemPos( )
2094 if ( m_xAggregateListBox
.is() )
2095 return m_xAggregateListBox
->getSelectedItemPos();
2100 Sequence
< ::sal_Int16
> SAL_CALL
OListBoxControl::getSelectedItemsPos( )
2102 if ( m_xAggregateListBox
.is() )
2103 return m_xAggregateListBox
->getSelectedItemsPos();
2104 return Sequence
< ::sal_Int16
>( );
2108 OUString SAL_CALL
OListBoxControl::getSelectedItem( )
2110 if ( m_xAggregateListBox
.is() )
2111 return m_xAggregateListBox
->getSelectedItem();
2116 Sequence
< OUString
> SAL_CALL
OListBoxControl::getSelectedItems( )
2118 if ( m_xAggregateListBox
.is() )
2119 return m_xAggregateListBox
->getSelectedItems();
2120 return Sequence
< OUString
>( );
2124 void SAL_CALL
OListBoxControl::selectItemPos( ::sal_Int16 nPos
, sal_Bool bSelect
)
2126 if ( m_xAggregateListBox
.is() )
2127 m_xAggregateListBox
->selectItemPos( nPos
, bSelect
);
2131 void SAL_CALL
OListBoxControl::selectItemsPos( const Sequence
< ::sal_Int16
>& aPositions
, sal_Bool bSelect
)
2133 if ( m_xAggregateListBox
.is() )
2134 m_xAggregateListBox
->selectItemsPos( aPositions
, bSelect
);
2138 void SAL_CALL
OListBoxControl::selectItem( const OUString
& aItem
, sal_Bool bSelect
)
2140 if ( m_xAggregateListBox
.is() )
2141 m_xAggregateListBox
->selectItem( aItem
, bSelect
);
2145 sal_Bool SAL_CALL
OListBoxControl::isMutipleMode( )
2147 if ( m_xAggregateListBox
.is() )
2148 return m_xAggregateListBox
->isMutipleMode();
2153 void SAL_CALL
OListBoxControl::setMultipleMode( sal_Bool bMulti
)
2155 if ( m_xAggregateListBox
.is() )
2156 m_xAggregateListBox
->setMultipleMode( bMulti
);
2160 ::sal_Int16 SAL_CALL
OListBoxControl::getDropDownLineCount( )
2162 if ( m_xAggregateListBox
.is() )
2163 return m_xAggregateListBox
->getDropDownLineCount();
2168 void SAL_CALL
OListBoxControl::setDropDownLineCount( ::sal_Int16 nLines
)
2170 if ( m_xAggregateListBox
.is() )
2171 m_xAggregateListBox
->setDropDownLineCount( nLines
);
2175 void SAL_CALL
OListBoxControl::makeVisible( ::sal_Int16 nEntry
)
2177 if ( m_xAggregateListBox
.is() )
2178 m_xAggregateListBox
->makeVisible( nEntry
);
2183 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2184 com_sun_star_form_OListBoxModel_get_implementation(css::uno::XComponentContext
* component
,
2185 css::uno::Sequence
<css::uno::Any
> const &)
2187 return cppu::acquire(new frm::OListBoxModel(component
));
2190 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2191 com_sun_star_form_OListBoxControl_get_implementation(css::uno::XComponentContext
* component
,
2192 css::uno::Sequence
<css::uno::Any
> const &)
2194 return cppu::acquire(new frm::OListBoxControl(component
));
2197 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */