LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / forms / source / component / ListBox.cxx
blob12cd2be5f887c94f918065c43417d202e6ac825f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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>
51 #include <optional>
53 #include <algorithm>
54 #include <iterator>
55 #include <climits>
57 namespace frm
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();
78 //= helper
80 namespace
83 struct RowSetValueToString
85 OUString operator()( const ORowSetValue& _value ) const
87 return _value.getString();
92 struct AppendRowSetValueString
94 explicit AppendRowSetValueString( OUString& _string )
95 :m_string( _string )
99 void operator()( const ORowSetValue& _append )
101 m_string += _append.getString();
104 private:
105 OUString& m_string;
109 Sequence< OUString > lcl_convertToStringSequence( const ValueList& _values )
111 Sequence< OUString > aStrings( _values.size() );
112 ::std::transform(
113 _values.begin(),
114 _values.end(),
115 aStrings.getArray(),
116 RowSetValueToString()
118 return aStrings;
123 //= ItemEventDescription
125 typedef ::comphelper::EventHolder< ItemEvent > ItemEventDescription;
128 //= OListBoxModel
130 Sequence< Type> OListBoxModel::_getTypes()
132 return TypeBag(
133 OBoundControlModel::_getTypes(),
134 OEntryListHelper::getTypes(),
135 OErrorBroadcaster::getTypes()
136 ).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)
153 ,m_nNULLPos(-1)
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);
162 init();
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 )
176 ,m_nNULLPos(-1)
177 ,m_nBoundColumnType( DataType::SQLNULL )
180 init();
184 OListBoxModel::~OListBoxModel()
186 if (!OComponentHelper::rBHelper.bDisposed)
188 acquire();
189 dispose();
194 // XCloneable
196 css::uno::Reference< css::util::XCloneable > SAL_CALL OListBoxModel::createClone()
198 rtl::Reference<OListBoxModel> pClone = new OListBoxModel(this, getContext());
199 pClone->clonedFrom(this);
200 return pClone;
203 // XServiceInfo
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;
226 return aSupported;
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 );
237 return aReturn;
240 // OComponentHelper
242 void OListBoxModel::disposing()
244 OBoundControlModel::disposing();
245 OEntryListHelper::disposing();
246 OErrorBroadcaster::disposing();
250 void OListBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
252 switch (_nHandle)
254 case PROPERTY_ID_BOUNDCOLUMN:
255 _rValue = m_aBoundColumn;
256 break;
258 case PROPERTY_ID_LISTSOURCETYPE:
259 _rValue <<= m_eListSourceType;
260 break;
262 case PROPERTY_ID_LISTSOURCE:
263 _rValue <<= lcl_convertToStringSequence( m_aListSourceValues );
264 break;
266 case PROPERTY_ID_VALUE_SEQ:
267 _rValue <<= lcl_convertToStringSequence( m_aBoundValues );
268 break;
270 case PROPERTY_ID_SELECT_VALUE_SEQ:
271 _rValue <<= getCurrentMultiValue();
272 break;
274 case PROPERTY_ID_SELECT_VALUE:
275 _rValue = getCurrentSingleValue();
276 break;
278 case PROPERTY_ID_DEFAULT_SELECT_SEQ:
279 _rValue <<= m_aDefaultSelectSeq;
280 break;
282 case PROPERTY_ID_STRINGITEMLIST:
283 _rValue <<= comphelper::containerToSequence(getStringItemList());
284 break;
286 case PROPERTY_ID_TYPEDITEMLIST:
287 _rValue <<= getTypedItemList();
288 break;
290 default:
291 OBoundControlModel::getFastPropertyValue(_rValue, _nHandle);
296 void OListBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
298 switch (_nHandle)
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;
304 break;
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;
310 break;
312 case PROPERTY_ID_LISTSOURCE:
314 // extract
315 Sequence< OUString > aListSource;
316 OSL_VERIFY( _rValue >>= aListSource );
318 // copy to member
319 ValueList().swap(m_aListSourceValues);
320 ::std::copy(
321 std::cbegin(aListSource),
322 std::cend(aListSource),
323 ::std::insert_iterator< ValueList >( m_aListSourceValues, m_aListSourceValues.end() )
326 // propagate
327 if ( m_eListSourceType == ListSourceType_VALUELIST )
329 setBoundValues(std::vector(m_aListSourceValues));
331 else
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
336 loadData( false );
339 break;
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;
348 _rValue >>= v;
349 Any newSelectSeq(translateBindingValuesToControlValue(v));
350 setControlValue( newSelectSeq, eOther );
352 break;
354 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
355 case PROPERTY_ID_SELECT_VALUE :
357 ORowSetValue v;
358 v.fill(_rValue);
359 Any newSelectSeq(translateDbValueToControlValue(v));
360 setControlValue( newSelectSeq, eOther );
362 break;
363 #endif
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 );
372 break;
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
381 // only control one.
383 resetNoBroadcast();
384 break;
386 case PROPERTY_ID_TYPEDITEMLIST:
388 ControlModelLock aLock( *this );
389 setNewTypedItemList( _rValue, aLock );
390 // Same TODO as above.
392 resetNoBroadcast();
393 break;
395 default:
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);
405 switch (_nHandle)
407 case PROPERTY_ID_BOUNDCOLUMN :
408 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aBoundColumn, ::cppu::UnoType<sal_Int16>::get());
409 break;
411 case PROPERTY_ID_LISTSOURCETYPE:
412 bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType);
413 break;
415 case PROPERTY_ID_LISTSOURCE:
416 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, lcl_convertToStringSequence( m_aListSourceValues ) );
417 break;
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());
425 break;
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;
435 bModified = true;
437 break;
439 case PROPERTY_ID_DEFAULT_SELECT_SEQ :
440 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultSelectSeq);
441 break;
443 case PROPERTY_ID_STRINGITEMLIST:
444 bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue );
445 break;
447 case PROPERTY_ID_TYPEDITEMLIST :
448 if (hasExternalListSource())
449 throw IllegalArgumentException();
450 bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, getTypedItemList());
451 break;
453 default:
454 return OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
456 return bModified;
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
463 // #i27024#
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
523 return;
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
533 return;
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;
562 // Version
563 // Version 0x0002: ListSource becomes StringSeq
564 _rxOutStream->writeShort(0x0004);
566 // Masking for any
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" );
612 // Version
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);
621 clearBoundValues();
622 m_eListSourceType = ListSourceType_VALUELIST;
623 m_aDefaultSelectSeq.realloc(0);
624 defaultCommonProperties();
625 return;
628 // Masking for any
629 sal_uInt16 nAnyMask;
630 _rxInStream >> nAnyMask;
632 // ListSourceSeq
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 );
642 sal_Int32 nIdx{ 0 };
643 for (sal_Int32 i=0; i<nTokens; ++i)
645 aListSourceSeq.getArray()[i] = sListSource.getToken(0, ';', nIdx);
648 else
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;
663 // DefaultSelectSeq
664 Sequence<sal_Int16> aDefaultSelectSeq;
665 _rxInStream >> aDefaultSelectSeq;
666 Any aDefaultSelectSeqAny;
667 aDefaultSelectSeqAny <<= aDefaultSelectSeq;
668 setFastPropertyValue(PROPERTY_ID_DEFAULT_SELECT_SEQ, aDefaultSelectSeqAny);
670 // BoundColumn
671 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
673 sal_Int16 nValue;
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();
683 if (nVersion > 2)
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>() ) );
696 if (nVersion > 3)
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
702 resetNoBroadcast();
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 );
714 m_nNULLPos = -1;
715 m_nBoundColumnType = DataType::SQLNULL;
717 // pre-requisites:
718 // PRE1: connection
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;
725 // PRE2: list source
726 OUString sListSource;
727 // if our list source type is no value list, we need to concatenate
728 // the single list source elements
729 ::std::for_each(
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() )
738 clearBoundValues();
739 return;
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
760 break;
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
769 OUString aFieldName;
770 OUString aBoundFieldName;
772 if ( !!aBoundColumn && ( *aBoundColumn >= 0 ) && xFieldsByIndex.is() )
774 if ( *aBoundColumn >= xFieldsByIndex->getCount() )
775 break;
777 Reference<XPropertySet> xFieldAsSet(xFieldsByIndex->getByIndex( *aBoundColumn ),UNO_QUERY);
778 assert(xFieldAsSet.is());
779 xFieldAsSet->getPropertyValue(PROPERTY_NAME) >>= aBoundFieldName;
780 aBoundColumn = 1;
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();
789 else
791 // otherwise look for the alias
792 Reference< XColumnsSupplier > xSupplyFields;
793 xFormProps->getPropertyValue("SingleSelectQueryComposer") >>= xSupplyFields;
795 // search the field
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())
809 break;
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 );
830 bExecute = true;
832 break;
834 case ListSourceType_QUERY:
835 m_aListRowSet.setCommandFromQuery( sListSource );
836 bExecute = true;
837 break;
839 default:
840 m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType );
841 m_aListRowSet.setCommand( sListSource );
842 bExecute = true;
843 break;
846 if (bExecute)
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;
855 return;
857 xListCursor.reset( m_aListRowSet.execute() );
860 catch(const SQLException& eSQL)
862 onError(eSQL, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST));
863 return;
865 catch(const Exception&)
867 return;
870 // Fill display and value lists
871 ValueList aDisplayList, aValueList;
872 bool bUseNULL = hasField() && !isRequired();
874 // empty BoundColumn is treated as BoundColumn==0,
875 if(!aBoundColumn)
876 aBoundColumn = 0;
880 OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ),
881 "OListBoxModel::loadData: logic error!" );
882 if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) )
883 return;
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;
904 if ( xColumns.is() )
905 xColumns->getByIndex(0) >>= xDataField;
906 if ( !xDataField.is() )
907 return;
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" );
931 OUString aStr;
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 );
942 else
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,
952 // so back off.
953 bUseNULL = false;
956 break;
957 #endif
958 case ListSourceType_TABLEFIELDS:
960 Reference<XNameAccess> xFieldNames = getTableFields(xConnection, sListSource);
961 if (xFieldNames.is())
963 const css::uno::Sequence<OUString> seqNames = xFieldNames->getElementNames();
964 ::std::copy(
965 seqNames.begin(),
966 seqNames.end(),
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));
977 else
979 aValueList = aDisplayList;
983 break;
984 default:
985 SAL_WARN( "forms.component", "OListBoxModel::loadData: unreachable!" );
986 break;
989 catch(const SQLException& eSQL)
991 onError(eSQL, ResourceManager::loadString(RID_BASELISTBOX_ERROR_FILLLIST));
992 return;
994 catch( const Exception& )
996 DBG_UNHANDLED_EXCEPTION("forms.component");
997 return;
1001 // Create Values sequence
1002 // Add NULL entry
1003 if (bUseNULL && m_nNULLPos == -1)
1005 aValueList.insert( aValueList.begin(), ORowSetValue() );
1007 aDisplayList.insert( aDisplayList.begin(), ORowSetValue( OUString() ) );
1008 m_nNULLPos = 0;
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
1022 if ( hasField() )
1024 setFastPropertyValue( PROPERTY_ID_MULTISELECTION, css::uno::Any(false) );
1027 if ( !hasExternalListSource() )
1028 impl_refreshDbEntryList( false );
1032 void OListBoxModel::onDisconnectedDbColumn()
1034 clearBoundValues();
1035 m_nNULLPos = -1;
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());
1065 m_nNULLPos = -1;
1066 m_aConvertedBoundValues.resize(m_aBoundValues.size());
1067 ValueList::iterator dst = m_aConvertedBoundValues.begin();
1068 sal_Int16 nPos = 0;
1069 for (auto const& src : m_aBoundValues)
1071 if(m_nNULLPos == -1 &&
1072 !isRequired() &&
1073 (src == s_aEmptyStringValue || src == s_aEmptyValue || src.isNull()) )
1075 m_nNULLPos = nPos;
1076 dst->setNull();
1078 else
1080 *dst = src;
1082 dst->setTypeKind(nFieldType);
1083 ++dst;
1084 ++nPos;
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)
1116 *dst = src;
1117 dst->setTypeKind(nFieldType);
1118 ++dst;
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());
1123 return aValues;
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();
1163 else
1167 m_xColumnUpdate->updateObject( aCurrentValue.makeAny() );
1169 catch ( const Exception& )
1171 return false;
1174 m_aSaveValue = aCurrentValue;
1176 return true;
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 };
1192 else
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() )
1222 ORowSetValue v;
1223 v.fill(value);
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();
1229 ++pIndex;
1230 ++nCount;
1233 else
1235 if ( m_nNULLPos != -1 )
1237 *pIndex = m_nNULLPos;
1238 ++pIndex;
1239 ++nCount;
1243 assert(aSelectionIndicies.getArray() + nCount == pIndex);
1244 #endif
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?!" );
1256 return Any();
1259 ORowSetValue aCurrentValue;
1260 aCurrentValue.fill( getValueType(), m_xColumn );
1262 m_aSaveValue = aCurrentValue;
1264 return makeAny( translateDbValueToControlValue(aCurrentValue) );
1265 #else
1266 return Any();
1267 #endif
1270 // XReset
1272 Any OListBoxModel::getDefaultForReset() const
1274 Any aValue;
1275 if (m_aDefaultSelectSeq.hasElements())
1276 aValue <<= m_aDefaultSelectSeq;
1277 else if (m_nNULLPos != -1) // bound Listbox
1279 Sequence<sal_Int16> aSeq { m_nNULLPos };
1280 aValue <<= aSeq;
1282 else
1284 Sequence<sal_Int16> aSeq;
1285 aValue <<= aSeq;
1288 return aValue;
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 );
1306 namespace
1308 // The type of how we should transfer our selection to external value bindings
1309 enum ExchangeType
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() )
1324 case TypeClass_ANY:
1325 return eValue;
1326 case TypeClass_STRING:
1327 return eEntry;
1328 case TypeClass_LONG:
1329 return eIndex;
1330 case TypeClass_SEQUENCE:
1332 Type aElementType = ::comphelper::getSequenceElementType( _rExchangeType );
1333 switch ( aElementType.getTypeClass() )
1335 case TypeClass_ANY:
1336 return eValueList;
1337 case TypeClass_STRING:
1338 return eEntryList;
1339 case TypeClass_LONG:
1340 return eIndexList;
1341 default:
1342 break;
1344 break;
1346 default:
1347 break;
1349 SAL_WARN( "forms.component", "lcl_getCurrentExchangeType: unsupported (unexpected) exchange type!" );
1350 return eEntry;
1355 Any OListBoxModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
1357 Sequence< sal_Int16 > aSelectIndexes;
1359 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1361 case eValueList:
1363 Sequence< const Any > aExternalValues;
1364 OSL_VERIFY( _rExternalValue >>= aExternalValues );
1365 aSelectIndexes = translateBindingValuesToControlValue( aExternalValues );
1367 break;
1369 case eValue:
1370 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
1372 ORowSetValue v;
1373 v.fill(_rExternalValue);
1374 aSelectIndexes = translateDbValueToControlValue(v);
1376 #endif
1377 break;
1379 case eIndexList:
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() );
1386 ::std::copy(
1387 std::cbegin(aSelectIndexesPure),
1388 std::cend(aSelectIndexesPure),
1389 aSelectIndexes.getArray()
1392 break;
1394 case eIndex:
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) };
1403 break;
1405 case eEntryList:
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) )
1416 int idx = 0;
1417 for(const OUString& s : getStringItemList())
1419 if (s==selectEntry)
1420 aSelectionSet.insert(idx);
1421 ++idx;
1425 // copy the indexes to the sequence
1426 aSelectIndexes = comphelper::containerToSequence( aSelectionSet );
1428 break;
1430 case eEntry:
1432 OUString sStringToSelect;
1433 OSL_VERIFY( _rExternalValue >>= sStringToSelect );
1434 ::std::set< sal_Int16 > aSelectionSet;
1435 int idx = 0;
1436 for(const OUString& s : getStringItemList())
1438 if (s==sStringToSelect)
1439 aSelectionSet.insert(idx);
1440 ++idx;
1443 aSelectIndexes = comphelper::containerToSequence( aSelectionSet );
1445 break;
1448 return makeAny( aSelectIndexes );
1452 namespace
1455 struct ExtractStringFromSequence_Safe
1457 protected:
1458 const std::vector< OUString >& m_rList;
1460 public:
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 ];
1468 return OUString();
1473 Any lcl_getSingleSelectedEntryTyped( const Sequence< sal_Int16 >& _rSelectSequence, const Sequence<Any>& _rTypedList )
1475 Any aReturn;
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];
1489 return aReturn;
1493 Any lcl_getSingleSelectedEntry( const Sequence< sal_Int16 >& _rSelectSequence, const std::vector< OUString >& _rStringList )
1495 Any aReturn;
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;
1509 return aReturn;
1513 Any lcl_getMultiSelectedEntries( const Sequence< sal_Int16 >& _rSelectSequence, const std::vector< OUString >& _rStringList )
1515 Sequence< OUString > aSelectedEntriesTexts( _rSelectSequence.getLength() );
1516 ::std::transform(
1517 _rSelectSequence.begin(),
1518 _rSelectSequence.end(),
1519 aSelectedEntriesTexts.getArray(),
1520 ExtractStringFromSequence_Safe( _rStringList )
1522 return makeAny( aSelectedEntriesTexts );
1526 struct ExtractAnyFromValueList_Safe
1528 protected:
1529 const ValueList& m_rList;
1531 public:
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();
1539 return Any();
1544 Any lcl_getSingleSelectedEntryAny( const Sequence< sal_Int16 >& _rSelectSequence, const ValueList& _rStringList )
1546 Any aReturn;
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] );
1556 return aReturn;
1560 Sequence< Any > lcl_getMultiSelectedEntriesAny( const Sequence< sal_Int16 >& _rSelectSequence, const ValueList& _rStringList )
1562 Sequence< Any > aSelectedEntriesValues( _rSelectSequence.getLength() );
1563 ::std::transform(
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 );
1581 Any aReturn;
1582 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1584 case eValueList:
1585 aReturn <<= getCurrentMultiValue();
1586 break;
1588 case eValue:
1589 aReturn = getCurrentSingleValue();
1590 break;
1592 case eIndexList:
1594 // unfortunately, the select sequence is a sequence<short>, but our binding
1595 // expects int's
1596 Sequence< sal_Int32 > aTransformed( aSelectSequence.getLength() );
1597 ::std::copy(
1598 std::cbegin(aSelectSequence),
1599 std::cend(aSelectSequence),
1600 aTransformed.getArray()
1602 aReturn <<= aTransformed;
1604 break;
1606 case eIndex:
1607 if ( aSelectSequence.getLength() <= 1 )
1609 sal_Int32 nIndex = -1;
1611 if ( aSelectSequence.getLength() == 1 )
1612 nIndex = aSelectSequence[0];
1614 aReturn <<= nIndex;
1616 break;
1618 case eEntryList:
1619 aReturn = lcl_getMultiSelectedEntries( aSelectSequence, getStringItemList() );
1620 break;
1622 case eEntry:
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 );
1628 else
1629 aReturn = lcl_getSingleSelectedEntry( aSelectSequence, rStrings );
1631 break;
1634 return aReturn;
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
1647 Any aCurrentValue;
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();
1690 Any aCurrentValue;
1694 bool bMultiSelection( false );
1695 OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection );
1697 if ( bMultiSelection )
1698 aCurrentValue <<= getCurrentMultiValue();
1699 else
1700 aCurrentValue = getCurrentSingleValue();
1702 catch( const Exception& )
1704 DBG_UNHANDLED_EXCEPTION("forms.component");
1707 return aCurrentValue;
1711 Sequence< Type > OListBoxModel::getSupportedBindingTypes()
1713 return
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() )
1728 return;
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 );
1745 else
1747 if ( hasField() )
1749 // TODO: update the selection in case we're bound to a database column
1751 else
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 );
1782 // OListBoxControl
1784 Sequence< Type> OListBoxControl::_getTypes()
1786 return TypeBag(
1787 OBoundControl::_getTypes(),
1788 OListBoxControl_BASE::getTypes()
1789 ).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 );
1802 return aReturn;
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);
1827 doSetDelegator();
1829 m_aChangeIdle.SetPriority(TaskPriority::LOWEST);
1830 m_aChangeIdle.SetInvokeHandler(LINK(this,OListBoxControl,OnTimeout));
1834 OListBoxControl::~OListBoxControl()
1836 if (!OComponentHelper::rBHelper.bDisposed)
1838 acquire();
1839 dispose();
1842 doResetDelegator();
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;
1856 return aSupported;
1860 // XFocusListener
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);
1868 if (xSet.is())
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();
1882 // XItemListener
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 );
1902 else
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();
1915 else
1917 if ( m_aChangeListeners.getLength() && m_aCurrentSelection.hasValue() )
1919 Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1920 if (xSet.is())
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())
1930 bModified = true;
1931 else
1933 const sal_Int16* pVal = rSelection.getConstArray();
1934 const sal_Int16* pCompVal = rOldSelection.getConstArray();
1936 while (nLen-- && !bModified)
1937 bModified = pVal[nLen] != pCompVal[nLen];
1940 if (bModified)
1942 m_aCurrentSelection = aValue;
1943 m_aChangeIdle.Start();
1947 else if (m_aCurrentSelection.hasValue())
1948 m_aCurrentSelection.clear();
1952 // XEventListener
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 );
1972 // OComponentHelper
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;
1994 if (t.is()) {
1995 t->join();
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 )
2008 return;
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();
2072 return 0;
2076 OUString SAL_CALL OListBoxControl::getItem( ::sal_Int16 nPos )
2078 if ( m_xAggregateListBox.is() )
2079 return m_xAggregateListBox->getItem( nPos );
2080 return OUString( );
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();
2096 return 0;
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();
2112 return OUString( );
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();
2149 return false;
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();
2164 return 0;
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: */