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/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/form/FormComponentType.hpp>
33 #include <com/sun/star/container/XIndexAccess.hpp>
34 #include <com/sun/star/sdbc/XRow.hpp>
35 #include <com/sun/star/awt/XWindow.hpp>
36 #include <com/sun/star/sdbc/XConnection.hpp>
38 #include <comphelper/basicio.hxx>
39 #include <comphelper/property.hxx>
40 #include <comphelper/sequence.hxx>
41 #include <comphelper/string.hxx>
42 #include <comphelper/types.hxx>
43 #include <connectivity/dbtools.hxx>
44 #include <connectivity/formattedcolumnvalue.hxx>
45 #include <o3tl/any.hxx>
46 #include <o3tl/safeint.hxx>
47 #include <tools/debug.hxx>
48 #include <comphelper/diagnose_ex.hxx>
49 #include <sal/log.hxx>
50 #include <unotools/sharedunocomponent.hxx>
60 using namespace ::com::sun::star::uno
;
61 using namespace ::com::sun::star::sdb
;
62 using namespace ::com::sun::star::sdbc
;
63 using namespace ::com::sun::star::sdbcx
;
64 using namespace ::com::sun::star::beans
;
65 using namespace ::com::sun::star::container
;
66 using namespace ::com::sun::star::form
;
67 using namespace ::com::sun::star::awt
;
68 using namespace ::com::sun::star::io
;
69 using namespace ::com::sun::star::lang
;
70 using namespace ::com::sun::star::util
;
71 using namespace ::com::sun::star::form::binding
;
72 using namespace ::dbtools
;
74 using ::connectivity::ORowSetValue
;
76 const ::connectivity::ORowSetValue
OListBoxModel::s_aEmptyValue
;
77 const ::connectivity::ORowSetValue
OListBoxModel::s_aEmptyStringValue
= OUString();
84 struct RowSetValueToString
86 OUString
operator()( const ORowSetValue
& _value
) const
88 return _value
.getString();
93 struct AppendRowSetValueString
95 explicit AppendRowSetValueString( OUString
& _string
)
100 void operator()( const ORowSetValue
& _append
)
102 m_string
+= _append
.getString();
110 Sequence
< OUString
> lcl_convertToStringSequence( const ValueList
& _values
)
112 Sequence
< OUString
> aStrings( _values
.size() );
117 RowSetValueToString()
124 //= ItemEventDescription
126 typedef ::comphelper::EventHolder
< ItemEvent
> ItemEventDescription
;
131 Sequence
< Type
> OListBoxModel::_getTypes()
134 OBoundControlModel::_getTypes(),
135 OEntryListHelper::getTypes(),
136 OErrorBroadcaster::getTypes()
140 // stuff common to all constructors
141 void OListBoxModel::init()
143 startAggregatePropertyListening( PROPERTY_STRINGITEMLIST
);
144 startAggregatePropertyListening( PROPERTY_TYPEDITEMLIST
);
148 OListBoxModel::OListBoxModel(const Reference
<XComponentContext
>& _rxFactory
)
149 :OBoundControlModel( _rxFactory
, VCL_CONTROLMODEL_LISTBOX
, FRM_SUN_CONTROL_LISTBOX
, true, true, true )
150 // use the old control name for compatibility reasons
151 ,OEntryListHelper( static_cast<OControlModel
&>(*this) )
152 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
153 ,m_nConvertedBoundValuesType(0)
155 ,m_nBoundColumnType( DataType::SQLNULL
)
158 m_nClassId
= FormComponentType::LISTBOX
;
159 m_eListSourceType
= ListSourceType_VALUELIST
;
160 m_aBoundColumn
<<= sal_Int16(1);
161 initValueProperty( PROPERTY_SELECT_SEQ
, PROPERTY_ID_SELECT_SEQ
);
167 OListBoxModel::OListBoxModel( const OListBoxModel
* _pOriginal
, const Reference
<XComponentContext
>& _rxFactory
)
168 :OBoundControlModel( _pOriginal
, _rxFactory
)
169 ,OEntryListHelper( *_pOriginal
, static_cast<OControlModel
&>(*this) )
170 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
171 ,m_eListSourceType( _pOriginal
->m_eListSourceType
)
172 ,m_aBoundColumn( _pOriginal
->m_aBoundColumn
)
173 ,m_aListSourceValues( _pOriginal
->m_aListSourceValues
)
174 ,m_aBoundValues( _pOriginal
->m_aBoundValues
)
175 ,m_nConvertedBoundValuesType(0)
176 ,m_aDefaultSelectSeq( _pOriginal
->m_aDefaultSelectSeq
)
178 ,m_nBoundColumnType( DataType::SQLNULL
)
185 OListBoxModel::~OListBoxModel()
187 if (!OComponentHelper::rBHelper
.bDisposed
)
197 css::uno::Reference
< css::util::XCloneable
> SAL_CALL
OListBoxModel::createClone()
199 rtl::Reference
<OListBoxModel
> pClone
= new OListBoxModel(this, getContext());
200 pClone
->clonedFrom(this);
206 css::uno::Sequence
<OUString
> SAL_CALL
OListBoxModel::getSupportedServiceNames()
208 css::uno::Sequence
<OUString
> aSupported
= OBoundControlModel::getSupportedServiceNames();
210 sal_Int32 nOldLen
= aSupported
.getLength();
211 aSupported
.realloc( nOldLen
+ 9 );
212 OUString
* pStoreTo
= aSupported
.getArray() + nOldLen
;
214 *pStoreTo
++ = BINDABLE_CONTROL_MODEL
;
215 *pStoreTo
++ = DATA_AWARE_CONTROL_MODEL
;
216 *pStoreTo
++ = VALIDATABLE_CONTROL_MODEL
;
218 *pStoreTo
++ = BINDABLE_DATA_AWARE_CONTROL_MODEL
;
219 *pStoreTo
++ = VALIDATABLE_BINDABLE_CONTROL_MODEL
;
221 *pStoreTo
++ = FRM_SUN_COMPONENT_LISTBOX
;
222 *pStoreTo
++ = FRM_SUN_COMPONENT_DATABASE_LISTBOX
;
223 *pStoreTo
++ = BINDABLE_DATABASE_LIST_BOX
;
225 *pStoreTo
++ = FRM_COMPONENT_LISTBOX
;
231 Any SAL_CALL
OListBoxModel::queryAggregation(const Type
& _rType
)
233 Any aReturn
= OBoundControlModel::queryAggregation( _rType
);
234 if ( !aReturn
.hasValue() )
235 aReturn
= OEntryListHelper::queryInterface( _rType
);
236 if ( !aReturn
.hasValue() )
237 aReturn
= OErrorBroadcaster::queryInterface( _rType
);
243 void OListBoxModel::disposing()
245 OBoundControlModel::disposing();
246 OEntryListHelper::disposing();
247 OErrorBroadcaster::disposing();
251 void OListBoxModel::getFastPropertyValue(Any
& _rValue
, sal_Int32 _nHandle
) const
255 case PROPERTY_ID_BOUNDCOLUMN
:
256 _rValue
= m_aBoundColumn
;
259 case PROPERTY_ID_LISTSOURCETYPE
:
260 _rValue
<<= m_eListSourceType
;
263 case PROPERTY_ID_LISTSOURCE
:
264 _rValue
<<= lcl_convertToStringSequence( m_aListSourceValues
);
267 case PROPERTY_ID_VALUE_SEQ
:
268 _rValue
<<= lcl_convertToStringSequence( m_aBoundValues
);
271 case PROPERTY_ID_SELECT_VALUE_SEQ
:
272 _rValue
<<= getCurrentMultiValue();
275 case PROPERTY_ID_SELECT_VALUE
:
276 _rValue
= getCurrentSingleValue();
279 case PROPERTY_ID_DEFAULT_SELECT_SEQ
:
280 _rValue
<<= m_aDefaultSelectSeq
;
283 case PROPERTY_ID_STRINGITEMLIST
:
284 _rValue
<<= comphelper::containerToSequence(getStringItemList());
287 case PROPERTY_ID_TYPEDITEMLIST
:
288 _rValue
<<= getTypedItemList();
292 OBoundControlModel::getFastPropertyValue(_rValue
, _nHandle
);
297 void OListBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle
, const Any
& _rValue
)
301 case PROPERTY_ID_BOUNDCOLUMN
:
302 DBG_ASSERT((_rValue
.getValueTypeClass() == TypeClass_SHORT
) || (_rValue
.getValueTypeClass() == TypeClass_VOID
),
303 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
304 m_aBoundColumn
= _rValue
;
307 case PROPERTY_ID_LISTSOURCETYPE
:
308 DBG_ASSERT(_rValue
.getValueType().equals(::cppu::UnoType
<ListSourceType
>::get()),
309 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
310 _rValue
>>= m_eListSourceType
;
313 case PROPERTY_ID_LISTSOURCE
:
316 Sequence
< OUString
> aListSource
;
317 OSL_VERIFY( _rValue
>>= aListSource
);
320 ValueList().swap(m_aListSourceValues
);
322 std::cbegin(aListSource
),
323 std::cend(aListSource
),
324 ::std::insert_iterator
< ValueList
>( m_aListSourceValues
, m_aListSourceValues
.end() )
328 if ( m_eListSourceType
== ListSourceType_VALUELIST
)
330 setBoundValues(std::vector(m_aListSourceValues
));
334 if ( m_xCursor
.is() && !hasField() && !hasExternalListSource() )
335 // listbox is already connected to a database, and no external list source
336 // data source changed -> refresh
342 case PROPERTY_ID_VALUE_SEQ
:
343 SAL_WARN( "forms.component", "ValueItemList is read-only!" );
344 throw PropertyVetoException();
346 case PROPERTY_ID_SELECT_VALUE_SEQ
:
348 Sequence
< const Any
> v
;
350 Any
newSelectSeq(translateBindingValuesToControlValue(v
));
351 setControlValue( newSelectSeq
, eOther
);
355 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
356 case PROPERTY_ID_SELECT_VALUE
:
360 Any
newSelectSeq(translateDbValueToControlValue(v
));
361 setControlValue( newSelectSeq
, eOther
);
365 case PROPERTY_ID_DEFAULT_SELECT_SEQ
:
366 DBG_ASSERT(_rValue
.getValueType().equals(cppu::UnoType
<Sequence
<sal_Int16
>>::get()),
367 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
368 _rValue
>>= m_aDefaultSelectSeq
;
370 DBG_ASSERT(m_xAggregateFastSet
.is(), "OListBoxModel::setFastPropertyValue_NoBroadcast(DEFAULT_SELECT_SEQ) : invalid aggregate !");
371 if ( m_xAggregateFastSet
.is() )
372 setControlValue( _rValue
, eOther
);
375 case PROPERTY_ID_STRINGITEMLIST
:
377 ControlModelLock
aLock( *this );
378 setNewStringItemList( _rValue
, aLock
);
379 // TODO: this is bogus. setNewStringItemList expects a guard which has the *only*
380 // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
381 // a lock - so we effectively has two locks here, of which setNewStringItemList can
387 case PROPERTY_ID_TYPEDITEMLIST
:
389 ControlModelLock
aLock( *this );
390 setNewTypedItemList( _rValue
, aLock
);
391 // Same TODO as above.
397 OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle
, _rValue
);
402 sal_Bool
OListBoxModel::convertFastPropertyValue(
403 Any
& _rConvertedValue
, Any
& _rOldValue
, sal_Int32 _nHandle
, const Any
& _rValue
)
405 bool bModified(false);
408 case PROPERTY_ID_BOUNDCOLUMN
:
409 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aBoundColumn
, ::cppu::UnoType
<sal_Int16
>::get());
412 case PROPERTY_ID_LISTSOURCETYPE
:
413 bModified
= tryPropertyValueEnum(_rConvertedValue
, _rOldValue
, _rValue
, m_eListSourceType
);
416 case PROPERTY_ID_LISTSOURCE
:
417 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, lcl_convertToStringSequence( m_aListSourceValues
) );
420 case PROPERTY_ID_VALUE_SEQ
:
421 SAL_WARN( "forms.component", "ValueItemList is read-only!" );
422 throw IllegalArgumentException();
424 case PROPERTY_ID_SELECT_VALUE_SEQ
:
425 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, getCurrentMultiValue());
428 case PROPERTY_ID_SELECT_VALUE
:
430 // Any from connectivity::ORowSetValue
431 Any aCurrentValue
= getCurrentSingleValue();
432 if (aCurrentValue
!= _rValue
)
434 _rOldValue
= std::move(aCurrentValue
);
435 _rConvertedValue
= _rValue
;
440 case PROPERTY_ID_DEFAULT_SELECT_SEQ
:
441 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aDefaultSelectSeq
);
444 case PROPERTY_ID_STRINGITEMLIST
:
445 bModified
= convertNewListSourceProperty( _rConvertedValue
, _rOldValue
, _rValue
);
448 case PROPERTY_ID_TYPEDITEMLIST
:
449 if (hasExternalListSource())
450 throw IllegalArgumentException();
451 bModified
= tryPropertyValue( _rConvertedValue
, _rOldValue
, _rValue
, getTypedItemList());
455 return OBoundControlModel::convertFastPropertyValue(_rConvertedValue
, _rOldValue
, _nHandle
, _rValue
);
461 void SAL_CALL
OListBoxModel::setPropertyValues( const Sequence
< OUString
>& _rPropertyNames
, const Sequence
< Any
>& _rValues
)
463 // if both SelectedItems and StringItemList are set, care for this
465 const Any
* pSelectSequenceValue
= nullptr;
467 const OUString
* pSelectedItemsPos
= std::find(
468 _rPropertyNames
.begin(), _rPropertyNames
.end(), PROPERTY_SELECT_SEQ
470 auto aStringItemListExists
= std::any_of(
471 _rPropertyNames
.begin(), _rPropertyNames
.end(),
472 [](OUString
const & s
) { return s
== PROPERTY_STRINGITEMLIST
; }
474 if ( ( pSelectedItemsPos
!= _rPropertyNames
.end() ) && aStringItemListExists
)
476 if (_rPropertyNames
.getLength() != _rValues
.getLength())
477 throw css::lang::IllegalArgumentException(u
"lengths do not match"_ustr
,
478 static_cast<cppu::OWeakObject
*>(this), -1);
480 // both properties are present
481 // -> remember the value for the select sequence
482 pSelectSequenceValue
= _rValues
.getConstArray() + ( pSelectedItemsPos
- _rPropertyNames
.begin() );
485 OBoundControlModel::setPropertyValues( _rPropertyNames
, _rValues
);
487 if ( pSelectSequenceValue
)
489 setPropertyValue( PROPERTY_SELECT_SEQ
, *pSelectSequenceValue
);
490 // Note that this is the only reliable way, since one of the properties is implemented
491 // by ourself, and one is implemented by the aggregate, we cannot rely on any particular
492 // results when setting them both - too many undocumented behavior in all the involved
498 void OListBoxModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
500 OBoundControlModel::describeFixedProperties( _rProps
);
501 sal_Int32 nOldCount
= _rProps
.getLength();
502 _rProps
.realloc( nOldCount
+ 10);
503 css::beans::Property
* pProperties
= _rProps
.getArray() + nOldCount
;
504 *pProperties
++ = css::beans::Property(PROPERTY_TABINDEX
, PROPERTY_ID_TABINDEX
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::BOUND
);
505 *pProperties
++ = css::beans::Property(PROPERTY_BOUNDCOLUMN
, PROPERTY_ID_BOUNDCOLUMN
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::MAYBEVOID
);
506 *pProperties
++ = css::beans::Property(PROPERTY_LISTSOURCETYPE
, PROPERTY_ID_LISTSOURCETYPE
, cppu::UnoType
<ListSourceType
>::get(), css::beans::PropertyAttribute::BOUND
);
507 *pProperties
++ = css::beans::Property(PROPERTY_LISTSOURCE
, PROPERTY_ID_LISTSOURCE
, cppu::UnoType
<css::uno::Sequence
<OUString
>>::get(), css::beans::PropertyAttribute::BOUND
);
508 *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
);
509 *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
);
510 *pProperties
++ = css::beans::Property(PROPERTY_SELECT_VALUE
, PROPERTY_ID_SELECT_VALUE
, cppu::UnoType
<Any
>::get(), css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::TRANSIENT
);
511 *pProperties
++ = css::beans::Property(PROPERTY_DEFAULT_SELECT_SEQ
, PROPERTY_ID_DEFAULT_SELECT_SEQ
, cppu::UnoType
<Sequence
<sal_Int16
>>::get(), css::beans::PropertyAttribute::BOUND
);
512 *pProperties
++ = css::beans::Property(PROPERTY_STRINGITEMLIST
, PROPERTY_ID_STRINGITEMLIST
, cppu::UnoType
<Sequence
< OUString
>>::get(), css::beans::PropertyAttribute::BOUND
);
513 *pProperties
++ = css::beans::Property(PROPERTY_TYPEDITEMLIST
, PROPERTY_ID_TYPEDITEMLIST
, cppu::UnoType
<Sequence
< Any
>>::get(), css::beans::PropertyAttribute::OPTIONAL
);
514 DBG_ASSERT( pProperties
== _rProps
.getArray() + _rProps
.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
518 void OListBoxModel::_propertyChanged( const PropertyChangeEvent
& i_rEvent
)
520 if ( i_rEvent
.PropertyName
== PROPERTY_STRINGITEMLIST
)
522 ControlModelLock
aLock( *this );
523 // SYNCHRONIZED ----->
524 // our aggregate internally changed its StringItemList property - reflect this in our "overridden"
525 // version of the property
526 setNewStringItemList( i_rEvent
.NewValue
, aLock
);
527 // <----- SYNCHRONIZED
530 else if ( i_rEvent
.PropertyName
== PROPERTY_TYPEDITEMLIST
)
532 ControlModelLock
aLock( *this );
533 // SYNCHRONIZED ----->
534 // our aggregate internally changed its TypedItemList property - reflect this in our "overridden"
535 // version of the property
536 setNewTypedItemList( i_rEvent
.NewValue
, aLock
);
537 // <----- SYNCHRONIZED
540 OBoundControlModel::_propertyChanged( i_rEvent
);
544 void OListBoxModel::describeAggregateProperties( Sequence
< Property
>& _rAggregateProps
) const
546 OBoundControlModel::describeAggregateProperties( _rAggregateProps
);
548 // superseded properties:
549 RemoveProperty( _rAggregateProps
, PROPERTY_STRINGITEMLIST
);
550 RemoveProperty( _rAggregateProps
, PROPERTY_TYPEDITEMLIST
);
554 OUString SAL_CALL
OListBoxModel::getServiceName()
556 return FRM_COMPONENT_LISTBOX
; // old (non-sun) name for compatibility !
560 void SAL_CALL
OListBoxModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
)
562 OBoundControlModel::write(_rxOutStream
);
564 // Dummy sequence, to stay compatible if SelectSeq is not saved anymore
565 Sequence
<sal_Int16
> aDummySeq
;
568 // Version 0x0002: ListSource becomes StringSeq
569 _rxOutStream
->writeShort(0x0004);
572 sal_uInt16 nAnyMask
= 0;
573 if (m_aBoundColumn
.getValueTypeClass() != TypeClass_VOID
)
574 nAnyMask
|= BOUNDCOLUMN
;
576 _rxOutStream
<< nAnyMask
;
578 _rxOutStream
<< lcl_convertToStringSequence( m_aListSourceValues
);
579 _rxOutStream
<< static_cast<sal_Int16
>(m_eListSourceType
);
580 _rxOutStream
<< aDummySeq
;
581 _rxOutStream
<< m_aDefaultSelectSeq
;
583 if ((nAnyMask
& BOUNDCOLUMN
) == BOUNDCOLUMN
)
585 sal_Int16 nBoundColumn
= 0;
586 m_aBoundColumn
>>= nBoundColumn
;
587 _rxOutStream
<< nBoundColumn
;
589 writeHelpTextCompatibly(_rxOutStream
);
591 // from version 0x0004 : common properties
592 writeCommonProperties(_rxOutStream
);
596 void SAL_CALL
OListBoxModel::read(const Reference
<XObjectInputStream
>& _rxInStream
)
598 // We need to respect dependencies for certain variables.
599 // Therefore, we need to set them explicitly via setPropertyValue().
601 OBoundControlModel::read(_rxInStream
);
602 ControlModelLock
aLock( *this );
604 // since we are "overwriting" the StringItemList of our aggregate (means we have
605 // an own place to store the value, instead of relying on our aggregate storing it),
606 // we need to respect what the aggregate just read for the StringItemList property.
609 if ( m_xAggregateSet
.is() )
610 setNewStringItemList( m_xAggregateSet
->getPropertyValue( PROPERTY_STRINGITEMLIST
), aLock
);
612 catch( const Exception
& )
614 TOOLS_WARN_EXCEPTION( "forms.component", "OComboBoxModel::read: caught an exception while examining the aggregate's string item list" );
618 sal_uInt16 nVersion
= _rxInStream
->readShort();
619 DBG_ASSERT(nVersion
> 0, "OListBoxModel::read : version 0 ? this should never have been written !");
621 if (nVersion
> 0x0004)
623 SAL_WARN( "forms.component", "OListBoxModel::read : invalid (means unknown) version !");
624 ValueList().swap(m_aListSourceValues
);
625 m_aBoundColumn
<<= sal_Int16(0);
627 m_eListSourceType
= ListSourceType_VALUELIST
;
628 m_aDefaultSelectSeq
.realloc(0);
629 defaultCommonProperties();
635 _rxInStream
>> nAnyMask
;
638 css::uno::Sequence
<OUString
> aListSourceSeq
;
639 if (nVersion
== 0x0001)
641 // Create ListSourceSeq from String
642 OUString sListSource
;
643 _rxInStream
>> sListSource
;
645 const sal_Int32 nTokens
{ comphelper::string::getTokenCount(sListSource
, ';') };
646 aListSourceSeq
.realloc( nTokens
);
648 for (sal_Int32 i
=0; i
<nTokens
; ++i
)
650 aListSourceSeq
.getArray()[i
] = sListSource
.getToken(0, ';', nIdx
);
654 _rxInStream
>> aListSourceSeq
;
656 sal_Int16 nListSourceType
;
657 _rxInStream
>> nListSourceType
;
658 m_eListSourceType
= static_cast<ListSourceType
>(nListSourceType
);
659 Any aListSourceSeqAny
;
660 aListSourceSeqAny
<<= aListSourceSeq
;
662 setFastPropertyValue(PROPERTY_ID_LISTSOURCE
, aListSourceSeqAny
);
664 // Dummy sequence, to stay compatible if SelectSeq is not saved anymore
665 Sequence
<sal_Int16
> aDummySeq
;
666 _rxInStream
>> aDummySeq
;
669 Sequence
<sal_Int16
> aDefaultSelectSeq
;
670 _rxInStream
>> aDefaultSelectSeq
;
671 Any aDefaultSelectSeqAny
;
672 aDefaultSelectSeqAny
<<= aDefaultSelectSeq
;
673 setFastPropertyValue(PROPERTY_ID_DEFAULT_SELECT_SEQ
, aDefaultSelectSeqAny
);
676 if ((nAnyMask
& BOUNDCOLUMN
) == BOUNDCOLUMN
)
679 _rxInStream
>> nValue
;
680 m_aBoundColumn
<<= nValue
;
682 else // the constructor initialises to 1, so if it is empty,
683 // we must explicitly set to empty
685 m_aBoundColumn
= Any();
689 readHelpTextCompatibly(_rxInStream
);
691 // if our string list is not filled from the value list, we must empty it
692 // this can be the case when somebody saves in alive mode
693 if ( ( m_eListSourceType
!= ListSourceType_VALUELIST
)
694 && !hasExternalListSource()
697 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, Any( css::uno::Sequence
<OUString
>() ) );
698 setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST
, Any( css::uno::Sequence
<css::uno::Any
>() ) );
702 readCommonProperties(_rxInStream
);
704 // Display the default values after reading
705 if ( !getControlSource().isEmpty() )
706 // (not if we don't have a control source - the "State" property acts like it is persistent, then
711 void OListBoxModel::loadData( bool _bForce
)
713 SAL_INFO( "forms.component", "OListBoxModel::loadData" );
714 DBG_ASSERT( m_eListSourceType
!= ListSourceType_VALUELIST
, "OListBoxModel::loadData: cannot load value list from DB!" );
715 DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::loadData: cannot load from DB when I have an external list source!" );
717 const sal_Int16
nNULLPosBackup( m_nNULLPos
);
718 const sal_Int32
nBoundColumnTypeBackup( m_nBoundColumnType
);
720 m_nBoundColumnType
= DataType::SQLNULL
;
724 Reference
< XConnection
> xConnection
;
725 // is the active connection of our form
726 Reference
< XPropertySet
> xFormProps( m_xCursor
, UNO_QUERY
);
727 if ( xFormProps
.is() )
728 xFormProps
->getPropertyValue( PROPERTY_ACTIVE_CONNECTION
) >>= xConnection
;
731 OUString sListSource
;
732 // if our list source type is no value list, we need to concatenate
733 // the single list source elements
735 m_aListSourceValues
.begin(),
736 m_aListSourceValues
.end(),
737 AppendRowSetValueString( sListSource
)
740 // outta here if we don't have all pre-requisites
741 if ( !xConnection
.is() || sListSource
.isEmpty() )
747 ::std::optional
< sal_Int16
> aBoundColumn(std::nullopt
);
748 if ( m_aBoundColumn
.getValueTypeClass() == TypeClass_SHORT
)
750 sal_Int16
nBoundColumn( 0 );
751 m_aBoundColumn
>>= nBoundColumn
;
752 aBoundColumn
= nBoundColumn
;
755 ::utl::SharedUNOComponent
< XResultSet
> xListCursor
;
758 m_aListRowSet
.setConnection( xConnection
);
760 bool bExecute
= false;
761 switch (m_eListSourceType
)
763 case ListSourceType_TABLEFIELDS
:
764 // don't work with a statement here, the fields will be collected below
767 case ListSourceType_TABLE
:
769 Reference
<XNameAccess
> xFieldsByName
= getTableFields(xConnection
, sListSource
);
770 Reference
<XIndexAccess
> xFieldsByIndex(xFieldsByName
, UNO_QUERY
);
772 // do we have a bound column if yes we have to select it
773 // and the displayed column is the first column otherwise we act as a combobox
775 OUString aBoundFieldName
;
777 if ( !!aBoundColumn
&& ( *aBoundColumn
>= 0 ) && xFieldsByIndex
.is() )
779 if ( *aBoundColumn
>= xFieldsByIndex
->getCount() )
782 Reference
<XPropertySet
> xFieldAsSet(xFieldsByIndex
->getByIndex( *aBoundColumn
),UNO_QUERY
);
783 assert(xFieldAsSet
.is());
784 xFieldAsSet
->getPropertyValue(PROPERTY_NAME
) >>= aBoundFieldName
;
787 xFieldAsSet
.set(xFieldsByIndex
->getByIndex(0),UNO_QUERY
);
788 xFieldAsSet
->getPropertyValue(PROPERTY_NAME
) >>= aFieldName
;
790 else if (xFieldsByName
.is())
792 if ( xFieldsByName
->hasByName( getControlSource() ) )
793 aFieldName
= getControlSource();
796 // otherwise look for the alias
797 Reference
< XColumnsSupplier
> xSupplyFields
;
798 xFormProps
->getPropertyValue(u
"SingleSelectQueryComposer"_ustr
) >>= xSupplyFields
;
801 DBG_ASSERT(xSupplyFields
.is(), "OListBoxModel::loadData : invalid query composer !");
803 Reference
<XNameAccess
> xFieldNames
= xSupplyFields
->getColumns();
804 if ( xFieldNames
->hasByName( getControlSource() ) )
806 Reference
<XPropertySet
> xComposerFieldAsSet
;
807 xFieldNames
->getByName( getControlSource() ) >>= xComposerFieldAsSet
;
808 if (hasProperty(PROPERTY_FIELDSOURCE
, xComposerFieldAsSet
))
809 xComposerFieldAsSet
->getPropertyValue(PROPERTY_FIELDSOURCE
) >>= aFieldName
;
813 if (aFieldName
.isEmpty())
816 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
817 OUString aQuote
= xMeta
->getIdentifierQuoteString();
818 OUString
aStatement(u
"SELECT "_ustr
);
819 if (aBoundFieldName
.isEmpty()) // act like a combobox
820 aStatement
+= "DISTINCT ";
822 aStatement
+= quoteName(aQuote
,aFieldName
);
823 if (!aBoundFieldName
.isEmpty())
825 aStatement
+= ", " + quoteName(aQuote
, aBoundFieldName
);
827 aStatement
+= " FROM ";
829 OUString sCatalog
, sSchema
, sTable
;
830 qualifiedNameComponents( xMeta
, sListSource
, sCatalog
, sSchema
, sTable
, EComposeRule::InDataManipulation
);
831 aStatement
+= composeTableNameForSelect( xConnection
, sCatalog
, sSchema
, sTable
);
833 m_aListRowSet
.setEscapeProcessing( false );
834 m_aListRowSet
.setCommand( aStatement
);
839 case ListSourceType_QUERY
:
840 m_aListRowSet
.setCommandFromQuery( sListSource
);
845 m_aListRowSet
.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH
!= m_eListSourceType
);
846 m_aListRowSet
.setCommand( sListSource
);
853 if ( !_bForce
&& !m_aListRowSet
.isDirty() )
855 // if none of the settings of the row set changed, compared to the last
856 // invocation of loadData, then don't re-fill the list. Instead, assume
857 // the list entries are the same.
858 m_nNULLPos
= nNULLPosBackup
;
859 m_nBoundColumnType
= nBoundColumnTypeBackup
;
862 xListCursor
.reset( m_aListRowSet
.execute() );
865 catch(const SQLException
& eSQL
)
867 onError(eSQL
, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST
));
870 catch(const Exception
&)
875 // Fill display and value lists
876 ValueList aDisplayList
, aValueList
;
877 bool bUseNULL
= hasField() && !isRequired();
879 // empty BoundColumn is treated as BoundColumn==0,
885 OSL_ENSURE( xListCursor
.is() || ( ListSourceType_TABLEFIELDS
== m_eListSourceType
),
886 "OListBoxModel::loadData: logic error!" );
887 if ( !xListCursor
.is() && ( ListSourceType_TABLEFIELDS
!= m_eListSourceType
) )
890 switch (m_eListSourceType
)
892 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
893 case ListSourceType_SQL
:
894 case ListSourceType_SQLPASSTHROUGH
:
895 case ListSourceType_TABLE
:
896 case ListSourceType_QUERY
:
898 // Get field of the ResultSet's 1st column
899 Reference
<XColumnsSupplier
> xSupplyCols(xListCursor
, UNO_QUERY
);
900 DBG_ASSERT(xSupplyCols
.is(), "OListBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
901 Reference
<XIndexAccess
> xColumns
;
902 if (xSupplyCols
.is())
904 xColumns
.set(xSupplyCols
->getColumns(), UNO_QUERY
);
905 DBG_ASSERT(xColumns
.is(), "OListBoxModel::loadData : no columns supplied by the row set !");
908 Reference
< XPropertySet
> xDataField
;
910 xColumns
->getByIndex(0) >>= xDataField
;
911 if ( !xDataField
.is() )
914 ::dbtools::FormattedColumnValue
aValueFormatter( getContext(), m_xCursor
, xDataField
);
916 // Get the field of BoundColumn of the ResultSet
917 m_nBoundColumnType
= DataType::SQLNULL
;
918 if ( *aBoundColumn
>= 0 )
922 Reference
< XPropertySet
> xBoundField( xColumns
->getByIndex( *aBoundColumn
), UNO_QUERY_THROW
);
923 OSL_VERIFY( xBoundField
->getPropertyValue(u
"Type"_ustr
) >>= m_nBoundColumnType
);
925 catch( const Exception
& )
927 DBG_UNHANDLED_EXCEPTION("forms.component");
930 else if ( *aBoundColumn
== -1)
931 m_nBoundColumnType
= DataType::SMALLINT
;
933 // If the LB is bound to a field and empty entries are valid, we remember the position
934 // for an empty entry
935 SAL_INFO( "forms.component", "OListBoxModel::loadData: string collection" );
937 sal_Int16 entryPos
= 0;
938 ORowSetValue aBoundValue
;
939 Reference
< XRow
> xCursorRow( xListCursor
, UNO_QUERY_THROW
);
940 while ( xListCursor
->next() && ( entryPos
++ < SHRT_MAX
) ) // SHRT_MAX is the maximum number of entries
942 aStr
= aValueFormatter
.getFormattedValue();
943 aDisplayList
.emplace_back(aStr
);
945 if(*aBoundColumn
>= 0)
946 aBoundValue
.fill( *aBoundColumn
+ 1, m_nBoundColumnType
, xCursorRow
);
948 // -1 because getRow() is 1-indexed, but ListBox positions are 0-indexed
949 aBoundValue
= static_cast<sal_Int16
>(xListCursor
->getRow()-1);
950 aValueList
.push_back( aBoundValue
);
952 if ( m_nNULLPos
== -1 && aBoundValue
.isNull() )
953 m_nNULLPos
= sal_Int16( aDisplayList
.size() - 1 );
954 if ( bUseNULL
&& ( m_nNULLPos
== -1 ) && aStr
.isEmpty() )
955 // There is already a non-NULL entry with empty display string;
956 // adding another one for NULL would make things confusing,
963 case ListSourceType_TABLEFIELDS
:
965 Reference
<XNameAccess
> xFieldNames
= getTableFields(xConnection
, sListSource
);
966 if (xFieldNames
.is())
968 const css::uno::Sequence
<OUString
> seqNames
= xFieldNames
->getElementNames();
972 ::std::insert_iterator
< ValueList
>( aDisplayList
, aDisplayList
.end() )
974 if(*aBoundColumn
== -1)
976 // the type of i matters! It will be the type of the ORowSetValue pushed to aValueList!
977 for(size_t i
=0; i
< aDisplayList
.size(); ++i
)
979 aValueList
.emplace_back(sal_Int16(i
));
984 aValueList
= aDisplayList
;
990 SAL_WARN( "forms.component", "OListBoxModel::loadData: unreachable!" );
994 catch(const SQLException
& eSQL
)
996 onError(eSQL
, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST
));
999 catch( const Exception
& )
1001 DBG_UNHANDLED_EXCEPTION("forms.component");
1006 // Create Values sequence
1008 if (bUseNULL
&& m_nNULLPos
== -1)
1010 aValueList
.insert( aValueList
.begin(), ORowSetValue() );
1012 aDisplayList
.insert( aDisplayList
.begin(), ORowSetValue( OUString() ) );
1016 setBoundValues(std::move(aValueList
));
1018 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, Any( lcl_convertToStringSequence( aDisplayList
) ) );
1019 setFastPropertyValue( PROPERTY_ID_TYPEDITEMLIST
, Any( css::uno::Sequence
<css::uno::Any
>() ) );
1023 void OListBoxModel::onConnectedDbColumn( const Reference
< XInterface
>& /*_rxForm*/ )
1025 // list boxes which are bound to a db column don't have multi selection
1026 // - this would be unable to reflect in the db column
1029 setFastPropertyValue( PROPERTY_ID_MULTISELECTION
, css::uno::Any(false) );
1032 if ( !hasExternalListSource() )
1033 impl_refreshDbEntryList( false );
1037 void OListBoxModel::onDisconnectedDbColumn()
1041 m_nBoundColumnType
= DataType::SQLNULL
;
1043 if ( m_eListSourceType
!= ListSourceType_VALUELIST
)
1045 if ( !hasExternalListSource() )
1046 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, Any( css::uno::Sequence
<OUString
>() ) );
1048 m_aListRowSet
.dispose();
1053 void OListBoxModel::setBoundValues(ValueList
&& l
)
1055 m_aConvertedBoundValues
.clear();
1056 m_aBoundValues
= std::move(l
);
1060 void OListBoxModel::clearBoundValues()
1062 ValueList().swap(m_aConvertedBoundValues
);
1063 ValueList().swap(m_aBoundValues
);
1067 void OListBoxModel::convertBoundValues(const sal_Int32 nFieldType
) const
1069 assert(s_aEmptyValue
.isNull());
1071 m_aConvertedBoundValues
.resize(m_aBoundValues
.size());
1072 ValueList::iterator dst
= m_aConvertedBoundValues
.begin();
1074 for (auto const& src
: m_aBoundValues
)
1076 if(m_nNULLPos
== -1 &&
1078 (src
== s_aEmptyStringValue
|| src
== s_aEmptyValue
|| src
.isNull()) )
1087 dst
->setTypeKind(nFieldType
);
1091 m_nConvertedBoundValuesType
= nFieldType
;
1092 OSL_ENSURE(dst
== m_aConvertedBoundValues
.end(), "OListBoxModel::convertBoundValues expected to have overwritten all of m_aConvertedBoundValues, but did not.");
1093 assert(dst
== m_aConvertedBoundValues
.end());
1096 sal_Int32
OListBoxModel::getValueType() const
1098 return (m_nBoundColumnType
!= css::sdbc::DataType::SQLNULL
) ?
1099 m_nBoundColumnType
:
1100 ( hasField() ? getFieldType() : DataType::VARCHAR
);
1103 ValueList
OListBoxModel::impl_getValues() const
1105 const sal_Int32 nFieldType
= getValueType();
1107 if ( !m_aConvertedBoundValues
.empty() && m_nConvertedBoundValuesType
== nFieldType
)
1108 return m_aConvertedBoundValues
;
1110 if ( !m_aBoundValues
.empty() )
1112 convertBoundValues(nFieldType
);
1113 return m_aConvertedBoundValues
;
1116 const std::vector
< OUString
>& aStringItems( getStringItemList() );
1117 ValueList
aValues( aStringItems
.size() );
1118 ValueList::iterator dst
= aValues
.begin();
1119 for (auto const& src
: aStringItems
)
1122 dst
->setTypeKind(nFieldType
);
1125 m_nConvertedBoundValuesType
= nFieldType
;
1126 OSL_ENSURE(dst
== aValues
.end(), "OListBoxModel::impl_getValues expected to have set all of aValues, but did not.");
1127 assert(dst
== aValues
.end());
1131 ORowSetValue
OListBoxModel::getFirstSelectedValue() const
1133 DBG_ASSERT( m_xAggregateFastSet
.is(), "OListBoxModel::getFirstSelectedValue: invalid aggregate!" );
1134 if ( !m_xAggregateFastSet
.is() )
1135 return s_aEmptyValue
;
1137 Sequence
< sal_Int16
> aSelectedIndices
;
1138 OSL_VERIFY( m_xAggregateFastSet
->getFastPropertyValue( getValuePropertyAggHandle() ) >>= aSelectedIndices
);
1139 if ( !aSelectedIndices
.hasElements() )
1140 // nothing selected at all
1141 return s_aEmptyValue
;
1143 if ( ( m_nNULLPos
!= -1 ) && ( aSelectedIndices
[0] == m_nNULLPos
) )
1144 // the dedicated "NULL" entry is selected
1145 return s_aEmptyValue
;
1147 ValueList
aValues( impl_getValues() );
1149 size_t selectedValue
= aSelectedIndices
[0];
1150 if ( selectedValue
>= aValues
.size() )
1152 SAL_WARN( "forms.component", "OListBoxModel::getFirstSelectedValue: inconsistent selection/valuelist!" );
1153 return s_aEmptyValue
;
1156 return aValues
[ selectedValue
];
1160 bool OListBoxModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
1162 // current selection list
1163 const ORowSetValue
aCurrentValue( getFirstSelectedValue() );
1164 if ( aCurrentValue
!= m_aSaveValue
)
1166 if ( aCurrentValue
.isNull() )
1167 m_xColumnUpdate
->updateNull();
1172 m_xColumnUpdate
->updateObject( aCurrentValue
.makeAny() );
1174 catch ( const Exception
& )
1179 m_aSaveValue
= aCurrentValue
;
1185 Sequence
< sal_Int16
> OListBoxModel::translateDbValueToControlValue(const ORowSetValue
&i_aValue
) const
1187 Sequence
< sal_Int16
> aSelectionIndicies
;
1189 // reset selection for NULL values
1190 if ( i_aValue
.isNull() )
1192 if ( m_nNULLPos
!= -1 )
1194 aSelectionIndicies
= { m_nNULLPos
};
1199 ValueList
aValues( impl_getValues() );
1200 assert( m_nConvertedBoundValuesType
== getValueType());
1201 ORowSetValue
v(i_aValue
);
1202 v
.setTypeKind( m_nConvertedBoundValuesType
);
1203 ValueList::const_iterator curValuePos
= ::std::find( aValues
.begin(), aValues
.end(), v
);
1204 if ( curValuePos
!= aValues
.end() )
1206 aSelectionIndicies
= { o3tl::narrowing
<sal_Int16
>(curValuePos
- aValues
.begin()) };
1210 return aSelectionIndicies
;
1213 Sequence
< sal_Int16
> OListBoxModel::translateBindingValuesToControlValue(const Sequence
< const Any
> &i_aValues
) const
1215 const ValueList
aValues( impl_getValues() );
1216 assert( m_nConvertedBoundValuesType
== getValueType());
1217 Sequence
< sal_Int16
> aSelectionIndicies(i_aValues
.getLength());
1219 sal_Int32
nCount(0);
1221 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1222 sal_Int16
*pIndex
= aSelectionIndicies
.getArray();
1223 for ( auto const & value
: i_aValues
)
1225 if ( value
.hasValue() )
1229 v
.setTypeKind( m_nConvertedBoundValuesType
);
1230 ValueList::const_iterator curValuePos
= ::std::find( aValues
.begin(), aValues
.end(), v
);
1231 if ( curValuePos
!= aValues
.end() )
1233 *pIndex
= curValuePos
- aValues
.begin();
1240 if ( m_nNULLPos
!= -1 )
1242 *pIndex
= m_nNULLPos
;
1248 assert(aSelectionIndicies
.getArray() + nCount
== pIndex
);
1250 aSelectionIndicies
.realloc(nCount
);
1251 return aSelectionIndicies
;
1254 Any
OListBoxModel::translateDbColumnToControlValue()
1256 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1257 Reference
< XPropertySet
> xBoundField( getField() );
1258 if ( !xBoundField
.is() )
1260 SAL_WARN( "forms.component", "OListBoxModel::translateDbColumnToControlValue: no field? How could that happen?!" );
1264 ORowSetValue aCurrentValue
;
1265 aCurrentValue
.fill( getValueType(), m_xColumn
);
1267 m_aSaveValue
= aCurrentValue
;
1269 return Any( translateDbValueToControlValue(aCurrentValue
) );
1277 Any
OListBoxModel::getDefaultForReset() const
1280 if (m_aDefaultSelectSeq
.hasElements())
1281 aValue
<<= m_aDefaultSelectSeq
;
1282 else if (m_nNULLPos
!= -1) // bound Listbox
1284 Sequence
<sal_Int16
> aSeq
{ m_nNULLPos
};
1289 Sequence
<sal_Int16
> aSeq
;
1297 void OListBoxModel::resetNoBroadcast()
1299 OBoundControlModel::resetNoBroadcast();
1300 m_aSaveValue
.setNull();
1304 void SAL_CALL
OListBoxModel::disposing( const EventObject
& _rSource
)
1306 if ( !OEntryListHelper::handleDisposing( _rSource
) )
1307 OBoundControlModel::disposing( _rSource
);
1313 // The type of how we should transfer our selection to external value bindings
1316 eIndexList
, /// as list of indexes of selected entries
1317 eIndex
, /// as index of the selected entry
1318 eEntryList
, /// as list of string representations of selected *display* entries
1319 eEntry
, /// as string representation of the selected *display* entry
1320 eValueList
, /// as list of string representations of selected values
1321 eValue
/// as string representation of the selected value
1325 ExchangeType
lcl_getCurrentExchangeType( const Type
& _rExchangeType
)
1327 switch ( _rExchangeType
.getTypeClass() )
1331 case TypeClass_STRING
:
1333 case TypeClass_LONG
:
1335 case TypeClass_SEQUENCE
:
1337 Type aElementType
= ::comphelper::getSequenceElementType( _rExchangeType
);
1338 switch ( aElementType
.getTypeClass() )
1342 case TypeClass_STRING
:
1344 case TypeClass_LONG
:
1354 SAL_WARN( "forms.component", "lcl_getCurrentExchangeType: unsupported (unexpected) exchange type!" );
1360 Any
OListBoxModel::translateExternalValueToControlValue( const Any
& _rExternalValue
) const
1362 Sequence
< sal_Int16
> aSelectIndexes
;
1364 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1368 Sequence
< const Any
> aExternalValues
;
1369 OSL_VERIFY( _rExternalValue
>>= aExternalValues
);
1370 aSelectIndexes
= translateBindingValuesToControlValue( aExternalValues
);
1375 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1378 v
.fill(_rExternalValue
);
1379 aSelectIndexes
= translateDbValueToControlValue(v
);
1386 // unfortunately, our select sequence is a sequence<short>, while the external binding
1387 // supplies sequence<int> only -> transform this
1388 Sequence
< sal_Int32
> aSelectIndexesPure
;
1389 OSL_VERIFY( _rExternalValue
>>= aSelectIndexesPure
);
1390 aSelectIndexes
.realloc( aSelectIndexesPure
.getLength() );
1392 std::cbegin(aSelectIndexesPure
),
1393 std::cend(aSelectIndexesPure
),
1394 aSelectIndexes
.getArray()
1401 sal_Int32 nSelectIndex
= -1;
1402 OSL_VERIFY( _rExternalValue
>>= nSelectIndex
);
1403 if ( ( nSelectIndex
>= 0 ) && ( o3tl::make_unsigned(nSelectIndex
) < getStringItemList().size() ) )
1405 aSelectIndexes
= { o3tl::narrowing
<sal_Int16
>(nSelectIndex
) };
1412 // we can retrieve a string list from the binding for multiple selection
1413 Sequence
< OUString
> aSelectEntries
;
1414 OSL_VERIFY( _rExternalValue
>>= aSelectEntries
);
1416 ::std::set
< sal_Int16
> aSelectionSet
;
1418 // find the selection entries in our item list
1419 for (OUString
const& selectEntry
: aSelectEntries
)
1422 for(const OUString
& s
: getStringItemList())
1425 aSelectionSet
.insert(idx
);
1430 // copy the indexes to the sequence
1431 aSelectIndexes
= comphelper::containerToSequence( aSelectionSet
);
1437 OUString sStringToSelect
;
1438 OSL_VERIFY( _rExternalValue
>>= sStringToSelect
);
1439 ::std::set
< sal_Int16
> aSelectionSet
;
1441 for(const OUString
& s
: getStringItemList())
1443 if (s
==sStringToSelect
)
1444 aSelectionSet
.insert(idx
);
1448 aSelectIndexes
= comphelper::containerToSequence( aSelectionSet
);
1453 return Any( aSelectIndexes
);
1460 struct ExtractStringFromSequence_Safe
1463 const std::vector
< OUString
>& m_rList
;
1466 explicit ExtractStringFromSequence_Safe( const std::vector
< OUString
>& _rList
) : m_rList( _rList
) { }
1468 const OUString
& operator ()( sal_Int16 _nIndex
)
1470 OSL_ENSURE( _nIndex
< static_cast<sal_Int32
>(m_rList
.size()), "ExtractStringFromSequence_Safe: inconsistence!" );
1471 if ( _nIndex
< static_cast<sal_Int32
>(m_rList
.size()) )
1472 return m_rList
[ _nIndex
];
1473 return EMPTY_OUSTRING
;
1478 Any
lcl_getSingleSelectedEntryTyped( const Sequence
< sal_Int16
>& _rSelectSequence
, const Sequence
<Any
>& _rTypedList
)
1482 // by definition, multiple selected entries are transferred as NULL if the
1483 // binding does not support lists
1484 if ( _rSelectSequence
.getLength() <= 1 )
1486 if ( _rSelectSequence
.getLength() == 1 )
1488 sal_Int32 nIndex
= _rSelectSequence
[0];
1489 if (0 <= nIndex
&& nIndex
< _rTypedList
.getLength())
1490 aReturn
= _rTypedList
[nIndex
];
1498 Any
lcl_getSingleSelectedEntry( const Sequence
< sal_Int16
>& _rSelectSequence
, const std::vector
< OUString
>& _rStringList
)
1502 // by definition, multiple selected entries are transferred as NULL if the
1503 // binding does not support string lists
1504 if ( _rSelectSequence
.getLength() <= 1 )
1506 OUString sSelectedEntry
;
1508 if ( _rSelectSequence
.getLength() == 1 )
1509 sSelectedEntry
= ExtractStringFromSequence_Safe( _rStringList
)( _rSelectSequence
[0] );
1511 aReturn
<<= sSelectedEntry
;
1518 Any
lcl_getMultiSelectedEntries( const Sequence
< sal_Int16
>& _rSelectSequence
, const std::vector
< OUString
>& _rStringList
)
1520 Sequence
< OUString
> aSelectedEntriesTexts( _rSelectSequence
.getLength() );
1522 _rSelectSequence
.begin(),
1523 _rSelectSequence
.end(),
1524 aSelectedEntriesTexts
.getArray(),
1525 ExtractStringFromSequence_Safe( _rStringList
)
1527 return Any( aSelectedEntriesTexts
);
1531 struct ExtractAnyFromValueList_Safe
1534 const ValueList
& m_rList
;
1537 explicit ExtractAnyFromValueList_Safe( const ValueList
& _rList
) : m_rList( _rList
) { }
1539 Any
operator ()( sal_Int16 _nIndex
)
1541 OSL_ENSURE( o3tl::make_unsigned(_nIndex
) < m_rList
.size(), "ExtractAnyFromValueList: inconsistence!" );
1542 if ( o3tl::make_unsigned(_nIndex
) < m_rList
.size() )
1543 return m_rList
[ _nIndex
].makeAny();
1549 Any
lcl_getSingleSelectedEntryAny( const Sequence
< sal_Int16
>& _rSelectSequence
, const ValueList
& _rStringList
)
1553 // by definition, multiple selected entries are transferred as NULL if the
1554 // binding does not support string lists
1555 if ( _rSelectSequence
.getLength() <= 1 )
1557 if ( _rSelectSequence
.getLength() == 1 )
1558 aReturn
= ExtractAnyFromValueList_Safe( _rStringList
)( _rSelectSequence
[0] );
1565 Sequence
< Any
> lcl_getMultiSelectedEntriesAny( const Sequence
< sal_Int16
>& _rSelectSequence
, const ValueList
& _rStringList
)
1567 Sequence
< Any
> aSelectedEntriesValues( _rSelectSequence
.getLength() );
1569 _rSelectSequence
.begin(),
1570 _rSelectSequence
.end(),
1571 aSelectedEntriesValues
.getArray(),
1572 ExtractAnyFromValueList_Safe( _rStringList
)
1574 return aSelectedEntriesValues
;
1579 Any
OListBoxModel::translateControlValueToExternalValue( ) const
1581 OSL_PRECOND( hasExternalValueBinding(), "OListBoxModel::translateControlValueToExternalValue: no binding!" );
1583 Sequence
< sal_Int16
> aSelectSequence
;
1584 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1587 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1590 aReturn
<<= getCurrentMultiValue();
1594 aReturn
= getCurrentSingleValue();
1599 // unfortunately, the select sequence is a sequence<short>, but our binding
1601 Sequence
< sal_Int32
> aTransformed( aSelectSequence
.getLength() );
1603 std::cbegin(aSelectSequence
),
1604 std::cend(aSelectSequence
),
1605 aTransformed
.getArray()
1607 aReturn
<<= aTransformed
;
1612 if ( aSelectSequence
.getLength() <= 1 )
1614 sal_Int32 nIndex
= -1;
1616 if ( aSelectSequence
.getLength() == 1 )
1617 nIndex
= aSelectSequence
[0];
1624 aReturn
= lcl_getMultiSelectedEntries( aSelectSequence
, getStringItemList() );
1629 const std::vector
<OUString
>& rStrings
= getStringItemList();
1630 const Sequence
<Any
>& rValues
= getTypedItemList();
1631 if (rStrings
.size() == static_cast<size_t>(rValues
.getLength()))
1632 aReturn
= lcl_getSingleSelectedEntryTyped( aSelectSequence
, rValues
);
1634 aReturn
= lcl_getSingleSelectedEntry( aSelectSequence
, rStrings
);
1643 Any
OListBoxModel::translateControlValueToValidatableValue( ) const
1645 OSL_PRECOND( hasValidator(), "OListBoxModel::translateControlValueToValidatableValue: no validator, so why should I?" );
1646 return getCurrentFormComponentValue();
1650 Any
OListBoxModel::getCurrentSingleValue() const
1656 Sequence
< sal_Int16
> aSelectSequence
;
1657 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1658 aCurrentValue
= lcl_getSingleSelectedEntryAny( aSelectSequence
, impl_getValues() );
1660 catch( const Exception
& )
1662 DBG_UNHANDLED_EXCEPTION("forms.component");
1665 return aCurrentValue
;
1668 Sequence
< Any
> OListBoxModel::getCurrentMultiValue() const
1670 Sequence
< Any
> aCurrentValue
;
1674 Sequence
< sal_Int16
> aSelectSequence
;
1675 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1676 aCurrentValue
= lcl_getMultiSelectedEntriesAny( aSelectSequence
, impl_getValues() );
1678 catch( const Exception
& )
1680 DBG_UNHANDLED_EXCEPTION("forms.component");
1683 return aCurrentValue
;
1686 Any
OListBoxModel::getCurrentFormComponentValue() const
1689 Reference
< css::form::validation::XValidator
> vtor (const_cast<OListBoxModel
*>(this)->getValidator());
1690 Reference
< XValueBinding
> extBinding (const_cast<OListBoxModel
*>(this)->getValueBinding());
1691 if ( vtor
.is() && vtor
== extBinding
)
1692 return translateControlValueToExternalValue();
1699 bool bMultiSelection( false );
1700 OSL_VERIFY( const_cast< OListBoxModel
* >( this )->getPropertyValue( PROPERTY_MULTISELECTION
) >>= bMultiSelection
);
1702 if ( bMultiSelection
)
1703 aCurrentValue
<<= getCurrentMultiValue();
1705 aCurrentValue
= getCurrentSingleValue();
1707 catch( const Exception
& )
1709 DBG_UNHANDLED_EXCEPTION("forms.component");
1712 return aCurrentValue
;
1716 Sequence
< Type
> OListBoxModel::getSupportedBindingTypes()
1720 cppu::UnoType
<Sequence
< Any
>>::get(),
1721 cppu::UnoType
<Any
>::get(),
1722 cppu::UnoType
<Sequence
< sal_Int32
>>::get(),
1723 cppu::UnoType
<sal_Int32
>::get(),
1724 cppu::UnoType
<Sequence
< OUString
>>::get(),
1725 cppu::UnoType
<OUString
>::get()
1730 void OListBoxModel::stringItemListChanged( ControlModelLock
& _rInstanceLock
)
1732 if ( !m_xAggregateSet
.is() )
1735 suspendValueListening();
1738 m_xAggregateSet
->setPropertyValue( PROPERTY_STRINGITEMLIST
, Any( comphelper::containerToSequence(getStringItemList()) ) );
1739 m_xAggregateSet
->setPropertyValue( PROPERTY_TYPEDITEMLIST
, Any( getTypedItemList() ) );
1741 catch( const Exception
& )
1743 DBG_UNHANDLED_EXCEPTION("forms.component");
1745 resumeValueListening();
1747 // update the selection here
1748 if ( hasExternalValueBinding( ) )
1749 transferExternalValueToControl( _rInstanceLock
);
1754 // TODO: update the selection in case we're bound to a database column
1758 if ( m_aDefaultSelectSeq
.hasElements() )
1759 setControlValue( Any( m_aDefaultSelectSeq
), eOther
);
1765 void OListBoxModel::impl_refreshDbEntryList( bool _bForce
)
1767 DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::impl_refreshDbEntryList: invalid call!" );
1769 if ( !hasExternalListSource( )
1770 && ( m_eListSourceType
!= ListSourceType_VALUELIST
)
1771 && ( m_xCursor
.is() )
1774 loadData( _bForce
);
1779 void OListBoxModel::refreshInternalEntryList()
1781 impl_refreshDbEntryList( true );
1782 if ( hasField() && m_xCursor
.is() )
1783 initFromField( m_xCursor
);
1789 Sequence
< Type
> OListBoxControl::_getTypes()
1792 OBoundControl::_getTypes(),
1793 OListBoxControl_BASE::getTypes()
1798 Any SAL_CALL
OListBoxControl::queryAggregation(const Type
& _rType
)
1800 Any aReturn
= OListBoxControl_BASE::queryInterface( _rType
);
1802 if ( !aReturn
.hasValue()
1803 || _rType
.equals( cppu::UnoType
<XTypeProvider
>::get() )
1805 aReturn
= OBoundControl::queryAggregation( _rType
);
1811 OListBoxControl::OListBoxControl(const Reference
<XComponentContext
>& _rxFactory
)
1812 :OBoundControl( _rxFactory
, VCL_CONTROL_LISTBOX
, false )
1813 ,m_aChangeListeners( m_aMutex
)
1814 ,m_aItemListeners( m_aMutex
)
1815 ,m_aChangeIdle("forms OListBoxControl m_aChangedIdle")
1818 osl_atomic_increment(&m_refCount
);
1820 // Register as FocusListener
1821 if (auto xComp
= query_aggregation
<XWindow
>(m_xAggregate
))
1822 xComp
->addFocusListener(this);
1824 // Register as ItemListener
1825 if ( query_aggregation( m_xAggregate
, m_xAggregateListBox
) )
1826 m_xAggregateListBox
->addItemListener(this);
1828 // Refcount at 2 for registered Listener
1829 osl_atomic_decrement(&m_refCount
);
1833 m_aChangeIdle
.SetPriority(TaskPriority::LOWEST
);
1834 m_aChangeIdle
.SetInvokeHandler(LINK(this,OListBoxControl
,OnTimeout
));
1838 OListBoxControl::~OListBoxControl()
1840 if (!OComponentHelper::rBHelper
.bDisposed
)
1847 m_xAggregateListBox
.clear();
1852 css::uno::Sequence
<OUString
> SAL_CALL
OListBoxControl::getSupportedServiceNames()
1854 css::uno::Sequence
<OUString
> aSupported
= OBoundControl::getSupportedServiceNames();
1855 aSupported
.realloc(aSupported
.getLength() + 2);
1857 OUString
* pArray
= aSupported
.getArray();
1858 pArray
[aSupported
.getLength()-2] = FRM_SUN_CONTROL_LISTBOX
;
1859 pArray
[aSupported
.getLength()-1] = STARDIV_ONE_FORM_CONTROL_LISTBOX
;
1866 void SAL_CALL
OListBoxControl::focusGained(const FocusEvent
& /*_rEvent*/)
1868 ::osl::MutexGuard
aGuard(m_aMutex
);
1869 if ( m_aChangeListeners
.getLength() ) // only if there are listeners
1871 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1874 // memorize the current selection for posting the change event
1875 m_aCurrentSelection
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1881 void SAL_CALL
OListBoxControl::focusLost(const FocusEvent
& /*_rEvent*/)
1883 m_aCurrentSelection
.clear();
1888 void SAL_CALL
OListBoxControl::itemStateChanged(const ItemEvent
& _rEvent
)
1890 // forward this to our listeners
1891 Reference
< XChild
> xChild( getModel(), UNO_QUERY
);
1892 if ( xChild
.is() && xChild
->getParent().is() )
1894 ::osl::MutexGuard
aGuard( m_aMutex
);
1895 if ( m_aItemListeners
.getLength() )
1897 if ( !m_pItemBroadcaster
.is() )
1899 m_pItemBroadcaster
.set(
1900 new ::comphelper::AsyncEventNotifier("ListBox"));
1901 m_pItemBroadcaster
->launch();
1903 m_pItemBroadcaster
->addEvent( new ItemEventDescription( _rEvent
), this );
1907 m_aItemListeners
.notifyEach( &XItemListener::itemStateChanged
, _rEvent
);
1909 // and do the handling for the ChangeListeners
1910 osl::MutexGuard
aGuard(m_aMutex
);
1911 if ( m_aChangeIdle
.IsActive() )
1913 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1914 m_aCurrentSelection
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1916 m_aChangeIdle
.Stop();
1917 m_aChangeIdle
.Start();
1921 if ( m_aChangeListeners
.getLength() && m_aCurrentSelection
.hasValue() )
1923 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1926 // Has the selection been changed?
1927 bool bModified(false);
1928 Any aValue
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1930 Sequence
<sal_Int16
> const & rSelection
= *o3tl::doAccess
<Sequence
<sal_Int16
>>(aValue
);
1931 Sequence
<sal_Int16
> const & rOldSelection
= *o3tl::doAccess
<Sequence
<sal_Int16
>>(m_aCurrentSelection
);
1932 sal_Int32 nLen
= rSelection
.getLength();
1933 if (nLen
!= rOldSelection
.getLength())
1937 const sal_Int16
* pVal
= rSelection
.getConstArray();
1938 const sal_Int16
* pCompVal
= rOldSelection
.getConstArray();
1940 while (nLen
-- && !bModified
)
1941 bModified
= pVal
[nLen
] != pCompVal
[nLen
];
1946 m_aCurrentSelection
= std::move(aValue
);
1947 m_aChangeIdle
.Start();
1951 else if (m_aCurrentSelection
.hasValue())
1952 m_aCurrentSelection
.clear();
1958 void SAL_CALL
OListBoxControl::disposing(const EventObject
& _rSource
)
1960 OBoundControl::disposing(_rSource
);
1963 // XChangeBroadcaster
1965 void SAL_CALL
OListBoxControl::addChangeListener(const Reference
<XChangeListener
>& _rxListener
)
1967 m_aChangeListeners
.addInterface( _rxListener
);
1971 void SAL_CALL
OListBoxControl::removeChangeListener(const Reference
<XChangeListener
>& _rxListener
)
1973 m_aChangeListeners
.removeInterface( _rxListener
);
1978 void OListBoxControl::disposing()
1980 if (m_aChangeIdle
.IsActive())
1981 m_aChangeIdle
.Stop();
1983 EventObject
aEvent( *this );
1984 m_aChangeListeners
.disposeAndClear( aEvent
);
1985 m_aItemListeners
.disposeAndClear( aEvent
);
1987 rtl::Reference
< comphelper::AsyncEventNotifier
> t
;
1989 ::osl::MutexGuard
aGuard( m_aMutex
);
1990 if ( m_pItemBroadcaster
.is() )
1992 t
= m_pItemBroadcaster
;
1993 m_pItemBroadcaster
->removeEventsForProcessor( this );
1994 m_pItemBroadcaster
->terminate();
1995 m_pItemBroadcaster
= nullptr;
2002 OBoundControl::disposing();
2006 void OListBoxControl::processEvent( const AnyEvent
& _rEvent
)
2008 Reference
< XListBox
> xKeepAlive( this );
2010 ::osl::MutexGuard
aGuard( m_aMutex
);
2011 if ( OComponentHelper::rBHelper
.bDisposed
)
2014 const ItemEventDescription
& rItemEvent
= static_cast< const ItemEventDescription
& >( _rEvent
);
2015 m_aItemListeners
.notifyEach( &XItemListener::itemStateChanged
, rItemEvent
.getEventObject() );
2019 IMPL_LINK_NOARG(OListBoxControl
, OnTimeout
, Timer
*, void)
2021 m_aChangeListeners
.notifyEach( &XChangeListener::changed
, EventObject( *this ) );
2025 void SAL_CALL
OListBoxControl::addItemListener( const Reference
< XItemListener
>& l
)
2027 m_aItemListeners
.addInterface( l
);
2031 void SAL_CALL
OListBoxControl::removeItemListener( const Reference
< XItemListener
>& l
)
2033 m_aItemListeners
.removeInterface( l
);
2037 void SAL_CALL
OListBoxControl::addActionListener( const Reference
< XActionListener
>& l
)
2039 if ( m_xAggregateListBox
.is() )
2040 m_xAggregateListBox
->addActionListener( l
);
2044 void SAL_CALL
OListBoxControl::removeActionListener( const Reference
< XActionListener
>& l
)
2046 if ( m_xAggregateListBox
.is() )
2047 m_xAggregateListBox
->removeActionListener( l
);
2051 void SAL_CALL
OListBoxControl::addItem( const OUString
& aItem
, ::sal_Int16 nPos
)
2053 if ( m_xAggregateListBox
.is() )
2054 m_xAggregateListBox
->addItem( aItem
, nPos
);
2058 void SAL_CALL
OListBoxControl::addItems( const Sequence
< OUString
>& aItems
, ::sal_Int16 nPos
)
2060 if ( m_xAggregateListBox
.is() )
2061 m_xAggregateListBox
->addItems( aItems
, nPos
);
2065 void SAL_CALL
OListBoxControl::removeItems( ::sal_Int16 nPos
, ::sal_Int16 nCount
)
2067 if ( m_xAggregateListBox
.is() )
2068 m_xAggregateListBox
->removeItems( nPos
, nCount
);
2072 ::sal_Int16 SAL_CALL
OListBoxControl::getItemCount( )
2074 if ( m_xAggregateListBox
.is() )
2075 return m_xAggregateListBox
->getItemCount();
2080 OUString SAL_CALL
OListBoxControl::getItem( ::sal_Int16 nPos
)
2082 if ( m_xAggregateListBox
.is() )
2083 return m_xAggregateListBox
->getItem( nPos
);
2088 Sequence
< OUString
> SAL_CALL
OListBoxControl::getItems( )
2090 if ( m_xAggregateListBox
.is() )
2091 return m_xAggregateListBox
->getItems();
2092 return Sequence
< OUString
>( );
2096 ::sal_Int16 SAL_CALL
OListBoxControl::getSelectedItemPos( )
2098 if ( m_xAggregateListBox
.is() )
2099 return m_xAggregateListBox
->getSelectedItemPos();
2104 Sequence
< ::sal_Int16
> SAL_CALL
OListBoxControl::getSelectedItemsPos( )
2106 if ( m_xAggregateListBox
.is() )
2107 return m_xAggregateListBox
->getSelectedItemsPos();
2108 return Sequence
< ::sal_Int16
>( );
2112 OUString SAL_CALL
OListBoxControl::getSelectedItem( )
2114 if ( m_xAggregateListBox
.is() )
2115 return m_xAggregateListBox
->getSelectedItem();
2120 Sequence
< OUString
> SAL_CALL
OListBoxControl::getSelectedItems( )
2122 if ( m_xAggregateListBox
.is() )
2123 return m_xAggregateListBox
->getSelectedItems();
2124 return Sequence
< OUString
>( );
2128 void SAL_CALL
OListBoxControl::selectItemPos( ::sal_Int16 nPos
, sal_Bool bSelect
)
2130 if ( m_xAggregateListBox
.is() )
2131 m_xAggregateListBox
->selectItemPos( nPos
, bSelect
);
2135 void SAL_CALL
OListBoxControl::selectItemsPos( const Sequence
< ::sal_Int16
>& aPositions
, sal_Bool bSelect
)
2137 if ( m_xAggregateListBox
.is() )
2138 m_xAggregateListBox
->selectItemsPos( aPositions
, bSelect
);
2142 void SAL_CALL
OListBoxControl::selectItem( const OUString
& aItem
, sal_Bool bSelect
)
2144 if ( m_xAggregateListBox
.is() )
2145 m_xAggregateListBox
->selectItem( aItem
, bSelect
);
2149 sal_Bool SAL_CALL
OListBoxControl::isMutipleMode( )
2151 if ( m_xAggregateListBox
.is() )
2152 return m_xAggregateListBox
->isMutipleMode();
2157 void SAL_CALL
OListBoxControl::setMultipleMode( sal_Bool bMulti
)
2159 if ( m_xAggregateListBox
.is() )
2160 m_xAggregateListBox
->setMultipleMode( bMulti
);
2164 ::sal_Int16 SAL_CALL
OListBoxControl::getDropDownLineCount( )
2166 if ( m_xAggregateListBox
.is() )
2167 return m_xAggregateListBox
->getDropDownLineCount();
2172 void SAL_CALL
OListBoxControl::setDropDownLineCount( ::sal_Int16 nLines
)
2174 if ( m_xAggregateListBox
.is() )
2175 m_xAggregateListBox
->setDropDownLineCount( nLines
);
2179 void SAL_CALL
OListBoxControl::makeVisible( ::sal_Int16 nEntry
)
2181 if ( m_xAggregateListBox
.is() )
2182 m_xAggregateListBox
->makeVisible( nEntry
);
2187 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2188 com_sun_star_form_OListBoxModel_get_implementation(css::uno::XComponentContext
* component
,
2189 css::uno::Sequence
<css::uno::Any
> const &)
2191 return cppu::acquire(new frm::OListBoxModel(component
));
2194 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2195 com_sun_star_form_OListBoxControl_get_implementation(css::uno::XComponentContext
* component
,
2196 css::uno::Sequence
<css::uno::Any
> const &)
2198 return cppu::acquire(new frm::OListBoxControl(component
));
2201 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */