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>
22 #include "ListBox.hxx"
23 #include "property.hxx"
24 #include "property.hrc"
25 #include "services.hxx"
26 #include "frm_resource.hxx"
27 #include "frm_resource.hrc"
28 #include "BaseListBox.hxx"
29 #include "listenercontainers.hxx"
30 #include "componenttools.hxx"
32 #include <com/sun/star/util/XNumberFormatTypes.hpp>
33 #include <com/sun/star/sdbc/XRowSet.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
36 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
37 #include <com/sun/star/util/NumberFormat.hpp>
38 #include <com/sun/star/awt/XWindow.hpp>
39 #include <com/sun/star/sdbc/XConnection.hpp>
40 #include <com/sun/star/sdb/CommandType.hpp>
42 #include <comphelper/basicio.hxx>
43 #include <comphelper/container.hxx>
44 #include <comphelper/numbers.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/listenernotification.hxx>
47 #include <connectivity/dbtools.hxx>
48 #include <connectivity/formattedcolumnvalue.hxx>
49 #include <connectivity/dbconversion.hxx>
50 #include <cppuhelper/queryinterface.hxx>
51 #include <tools/debug.hxx>
52 #include <tools/diagnose_ex.h>
53 #include <unotools/sharedunocomponent.hxx>
54 #include <vcl/svapp.hxx>
56 #include <boost/optional.hpp>
64 using namespace ::com::sun::star::uno
;
65 using namespace ::com::sun::star::sdb
;
66 using namespace ::com::sun::star::sdbc
;
67 using namespace ::com::sun::star::sdbcx
;
68 using namespace ::com::sun::star::beans
;
69 using namespace ::com::sun::star::container
;
70 using namespace ::com::sun::star::form
;
71 using namespace ::com::sun::star::awt
;
72 using namespace ::com::sun::star::io
;
73 using namespace ::com::sun::star::lang
;
74 using namespace ::com::sun::star::util
;
75 using namespace ::com::sun::star::form::binding
;
76 using namespace ::dbtools
;
78 using ::connectivity::ORowSetValue
;
80 const ::connectivity::ORowSetValue
OListBoxModel::s_aEmptyValue
;
81 const ::connectivity::ORowSetValue
OListBoxModel::s_aEmptyStringValue
= OUString();
88 struct RowSetValueToString
: public ::std::unary_function
< ORowSetValue
, OUString
>
90 OUString
operator()( const ORowSetValue
& _value
) const
92 return _value
.getString();
97 struct AppendRowSetValueString
: public ::std::unary_function
< OUString
, void >
99 AppendRowSetValueString( OUString
& _string
)
104 void operator()( const OUString
& _append
)
114 Sequence
< OUString
> lcl_convertToStringSequence( const ValueList
& _values
)
116 Sequence
< OUString
> aStrings( _values
.size() );
121 RowSetValueToString()
128 //= ItemEventDescription
130 typedef ::comphelper::EventHolder
< ItemEvent
> ItemEventDescription
;
135 Sequence
< Type
> OListBoxModel::_getTypes()
138 OBoundControlModel::_getTypes(),
139 OEntryListHelper::getTypes(),
140 OErrorBroadcaster::getTypes()
144 // stuff common to all constructors
145 void OListBoxModel::init()
147 startAggregatePropertyListening( PROPERTY_STRINGITEMLIST
);
151 OListBoxModel::OListBoxModel(const Reference
<XComponentContext
>& _rxFactory
)
152 :OBoundControlModel( _rxFactory
, VCL_CONTROLMODEL_LISTBOX
, FRM_SUN_CONTROL_LISTBOX
, true, true, true )
153 // use the old control name for compatibility reasons
154 ,OEntryListHelper( (OControlModel
&)*this )
155 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
157 ,m_nConvertedBoundValuesType(0)
159 ,m_nBoundColumnType( DataType::SQLNULL
)
162 m_nClassId
= FormComponentType::LISTBOX
;
163 m_eListSourceType
= ListSourceType_VALUELIST
;
164 m_aBoundColumn
<<= (sal_Int16
)1;
165 initValueProperty( PROPERTY_SELECT_SEQ
, PROPERTY_ID_SELECT_SEQ
);
171 OListBoxModel::OListBoxModel( const OListBoxModel
* _pOriginal
, const Reference
<XComponentContext
>& _rxFactory
)
172 :OBoundControlModel( _pOriginal
, _rxFactory
)
173 ,OEntryListHelper( *_pOriginal
, (OControlModel
&)*this )
174 ,OErrorBroadcaster( OComponentHelper::rBHelper
)
176 ,m_eListSourceType( _pOriginal
->m_eListSourceType
)
177 ,m_aBoundColumn( _pOriginal
->m_aBoundColumn
)
178 ,m_aListSourceValues( _pOriginal
->m_aListSourceValues
)
179 ,m_aBoundValues( _pOriginal
->m_aBoundValues
)
180 ,m_nConvertedBoundValuesType(0)
181 ,m_aDefaultSelectSeq( _pOriginal
->m_aDefaultSelectSeq
)
183 ,m_nBoundColumnType( DataType::SQLNULL
)
190 OListBoxModel::~OListBoxModel()
192 if (!OComponentHelper::rBHelper
.bDisposed
)
202 IMPLEMENT_DEFAULT_CLONING( OListBoxModel
)
206 StringSequence SAL_CALL
OListBoxModel::getSupportedServiceNames() throw(RuntimeException
, std::exception
)
208 StringSequence 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
) throw (RuntimeException
, std::exception
)
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
<<= getStringItemList();
288 OBoundControlModel::getFastPropertyValue(_rValue
, _nHandle
);
293 void OListBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle
, const Any
& _rValue
) throw (com::sun::star::uno::Exception
, std::exception
)
297 case PROPERTY_ID_BOUNDCOLUMN
:
298 DBG_ASSERT((_rValue
.getValueType().getTypeClass() == TypeClass_SHORT
) || (_rValue
.getValueType().getTypeClass() == TypeClass_VOID
),
299 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
300 m_aBoundColumn
= _rValue
;
303 case PROPERTY_ID_LISTSOURCETYPE
:
304 DBG_ASSERT(_rValue
.getValueType().equals(::cppu::UnoType
<ListSourceType
>::get()),
305 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
306 _rValue
>>= m_eListSourceType
;
309 case PROPERTY_ID_LISTSOURCE
:
312 Sequence
< OUString
> aListSource
;
313 OSL_VERIFY( _rValue
>>= aListSource
);
316 ValueList().swap(m_aListSourceValues
);
318 aListSource
.getConstArray(),
319 aListSource
.getConstArray() + aListSource
.getLength(),
320 ::std::insert_iterator
< ValueList
>( m_aListSourceValues
, m_aListSourceValues
.end() )
324 if ( m_eListSourceType
== ListSourceType_VALUELIST
)
326 setBoundValues(m_aListSourceValues
);
330 if ( m_xCursor
.is() && !hasField() && !hasExternalListSource() )
331 // listbox is already connected to a database, and no external list source
332 // data source changed -> refresh
338 case PROPERTY_ID_VALUE_SEQ
:
339 SAL_WARN( "forms.component", "ValueItemList is read-only!" );
340 throw PropertyVetoException();
342 case PROPERTY_ID_SELECT_VALUE_SEQ
:
344 Sequence
< const Any
> v
;
346 Any
newSelectSeq(translateBindingValuesToControlValue(v
));
347 setControlValue( newSelectSeq
, eOther
);
351 #if HAVE_FEATURE_DBCONNECTIVITY
352 case PROPERTY_ID_SELECT_VALUE
:
356 Any
newSelectSeq(translateDbValueToControlValue(v
));
357 setControlValue( newSelectSeq
, eOther
);
361 case PROPERTY_ID_DEFAULT_SELECT_SEQ
:
362 DBG_ASSERT(_rValue
.getValueType().equals(cppu::UnoType
<Sequence
<sal_Int16
>>::get()),
363 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
364 _rValue
>>= m_aDefaultSelectSeq
;
366 DBG_ASSERT(m_xAggregateFastSet
.is(), "OListBoxModel::setFastPropertyValue_NoBroadcast(DEFAULT_SELECT_SEQ) : invalid aggregate !");
367 if ( m_xAggregateFastSet
.is() )
368 setControlValue( _rValue
, eOther
);
371 case PROPERTY_ID_STRINGITEMLIST
:
373 ControlModelLock
aLock( *this );
374 setNewStringItemList( _rValue
, aLock
);
375 // TODO: this is bogus. setNewStringItemList expects a guard which has the *only*
376 // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
377 // a lock - so we effectively has two locks here, of which setNewStringItemList can
384 OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle
, _rValue
);
389 sal_Bool
OListBoxModel::convertFastPropertyValue(
390 Any
& _rConvertedValue
, Any
& _rOldValue
, sal_Int32 _nHandle
, const Any
& _rValue
)
391 throw (IllegalArgumentException
)
393 bool bModified(false);
396 case PROPERTY_ID_BOUNDCOLUMN
:
397 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aBoundColumn
, ::cppu::UnoType
<sal_Int16
>::get());
400 case PROPERTY_ID_LISTSOURCETYPE
:
401 bModified
= tryPropertyValueEnum(_rConvertedValue
, _rOldValue
, _rValue
, m_eListSourceType
);
404 case PROPERTY_ID_LISTSOURCE
:
405 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, lcl_convertToStringSequence( m_aListSourceValues
) );
408 case PROPERTY_ID_VALUE_SEQ
:
409 SAL_WARN( "forms.component", "ValueItemList is read-only!" );
410 throw IllegalArgumentException();
412 case PROPERTY_ID_SELECT_VALUE_SEQ
:
413 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, getCurrentMultiValue());
416 case PROPERTY_ID_SELECT_VALUE
:
417 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, getCurrentSingleValue());
420 case PROPERTY_ID_DEFAULT_SELECT_SEQ
:
421 bModified
= tryPropertyValue(_rConvertedValue
, _rOldValue
, _rValue
, m_aDefaultSelectSeq
);
424 case PROPERTY_ID_STRINGITEMLIST
:
425 bModified
= convertNewListSourceProperty( _rConvertedValue
, _rOldValue
, _rValue
);
429 return OBoundControlModel::convertFastPropertyValue(_rConvertedValue
, _rOldValue
, _nHandle
, _rValue
);
435 void SAL_CALL
OListBoxModel::setPropertyValues( const Sequence
< OUString
>& _rPropertyNames
, const Sequence
< Any
>& _rValues
) throw(PropertyVetoException
, IllegalArgumentException
, WrappedTargetException
, RuntimeException
, std::exception
)
437 // if both SelectedItems and StringItemList are set, care for this
439 const Any
* pSelectSequenceValue
= NULL
;
441 const OUString
* pStartPos
= _rPropertyNames
.getConstArray();
442 const OUString
* pEndPos
= _rPropertyNames
.getConstArray() + _rPropertyNames
.getLength();
443 const OUString
* pSelectedItemsPos
= ::std::find_if(
445 ::std::bind2nd( ::std::equal_to
< OUString
>(), PROPERTY_SELECT_SEQ
)
447 const OUString
* pStringItemListPos
= ::std::find_if(
449 ::std::bind2nd( ::std::equal_to
< OUString
>(), PROPERTY_STRINGITEMLIST
)
451 if ( ( pSelectedItemsPos
!= pEndPos
) && ( pStringItemListPos
!= pEndPos
) )
453 // both properties are present
454 // -> remember the value for the select sequence
455 pSelectSequenceValue
= _rValues
.getConstArray() + ( pSelectedItemsPos
- pStartPos
);
458 OBoundControlModel::setPropertyValues( _rPropertyNames
, _rValues
);
460 if ( pSelectSequenceValue
)
462 setPropertyValue( PROPERTY_SELECT_SEQ
, *pSelectSequenceValue
);
463 // Note that this is the only reliable way, since one of the properties is implemented
464 // by ourself, and one is implemented by the aggregate, we cannot rely on any particular
465 // results when setting them both - too many undocumented behavior in all the involved
471 void OListBoxModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
473 BEGIN_DESCRIBE_PROPERTIES( 9, OBoundControlModel
)
474 DECL_PROP1(TABINDEX
, sal_Int16
, BOUND
);
475 DECL_PROP2(BOUNDCOLUMN
, sal_Int16
, BOUND
, MAYBEVOID
);
476 DECL_PROP1(LISTSOURCETYPE
, ListSourceType
, BOUND
);
477 DECL_PROP1(LISTSOURCE
, StringSequence
, BOUND
);
478 DECL_PROP3(VALUE_SEQ
, StringSequence
, BOUND
, READONLY
, TRANSIENT
);
479 DECL_PROP2(SELECT_VALUE_SEQ
, Sequence
< Any
>, BOUND
, TRANSIENT
);
480 DECL_PROP2(SELECT_VALUE
, Any
, BOUND
, TRANSIENT
);
481 DECL_PROP1(DEFAULT_SELECT_SEQ
, Sequence
<sal_Int16
>, BOUND
);
482 DECL_PROP1(STRINGITEMLIST
, Sequence
< OUString
>, BOUND
);
483 END_DESCRIBE_PROPERTIES();
487 void OListBoxModel::_propertyChanged( const PropertyChangeEvent
& i_rEvent
) throw ( RuntimeException
)
489 if ( i_rEvent
.PropertyName
== PROPERTY_STRINGITEMLIST
)
491 ControlModelLock
aLock( *this );
492 // SYNCHRONIZED ----->
493 // our aggregate internally changed its StringItemList property - reflect this in our "overridden"
494 // version of the property
495 setNewStringItemList( i_rEvent
.NewValue
, aLock
);
496 // <----- SYNCHRONIZED
499 OBoundControlModel::_propertyChanged( i_rEvent
);
503 void OListBoxModel::describeAggregateProperties( Sequence
< Property
>& _rAggregateProps
) const
505 OBoundControlModel::describeAggregateProperties( _rAggregateProps
);
507 // superseded properties:
508 RemoveProperty( _rAggregateProps
, PROPERTY_STRINGITEMLIST
);
512 OUString SAL_CALL
OListBoxModel::getServiceName() throw(RuntimeException
, std::exception
)
514 return OUString(FRM_COMPONENT_LISTBOX
); // old (non-sun) name for compatibility !
518 void SAL_CALL
OListBoxModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
)
519 throw(IOException
, RuntimeException
, std::exception
)
521 OBoundControlModel::write(_rxOutStream
);
523 // Dummy sequence, to stay compatible if SelectSeq is not saved anymore
524 Sequence
<sal_Int16
> aDummySeq
;
527 // Version 0x0002: ListSource becomes StringSeq
528 _rxOutStream
->writeShort(0x0004);
531 sal_uInt16 nAnyMask
= 0;
532 if (m_aBoundColumn
.getValueType().getTypeClass() != TypeClass_VOID
)
533 nAnyMask
|= BOUNDCOLUMN
;
535 _rxOutStream
<< nAnyMask
;
537 _rxOutStream
<< lcl_convertToStringSequence( m_aListSourceValues
);
538 _rxOutStream
<< (sal_Int16
)m_eListSourceType
;
539 _rxOutStream
<< aDummySeq
;
540 _rxOutStream
<< m_aDefaultSelectSeq
;
542 if ((nAnyMask
& BOUNDCOLUMN
) == BOUNDCOLUMN
)
544 sal_Int16 nBoundColumn
= 0;
545 m_aBoundColumn
>>= nBoundColumn
;
546 _rxOutStream
<< nBoundColumn
;
548 writeHelpTextCompatibly(_rxOutStream
);
550 // from version 0x0004 : common properties
551 writeCommonProperties(_rxOutStream
);
555 void SAL_CALL
OListBoxModel::read(const Reference
<XObjectInputStream
>& _rxInStream
) throw(IOException
, RuntimeException
, std::exception
)
557 // We need to respect dependencies for certain variables.
558 // Therefore, we need to set them explicitly via setPropertyValue().
560 OBoundControlModel::read(_rxInStream
);
561 ControlModelLock
aLock( *this );
563 // since we are "overwriting" the StringItemList of our aggregate (means we have
564 // an own place to store the value, instead of relying on our aggregate storing it),
565 // we need to respect what the aggregate just read for the StringItemList property.
568 if ( m_xAggregateSet
.is() )
569 setNewStringItemList( m_xAggregateSet
->getPropertyValue( PROPERTY_STRINGITEMLIST
), aLock
);
571 catch( const Exception
& )
573 SAL_WARN( "forms.component", "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" );
577 sal_uInt16 nVersion
= _rxInStream
->readShort();
578 DBG_ASSERT(nVersion
> 0, "OListBoxModel::read : version 0 ? this should never have been written !");
580 if (nVersion
> 0x0004)
582 SAL_WARN( "forms.component", "OListBoxModel::read : invalid (means unknown) version !");
583 ValueList().swap(m_aListSourceValues
);
584 m_aBoundColumn
<<= (sal_Int16
)0;
586 m_eListSourceType
= ListSourceType_VALUELIST
;
587 m_aDefaultSelectSeq
.realloc(0);
588 defaultCommonProperties();
594 _rxInStream
>> nAnyMask
;
597 StringSequence aListSourceSeq
;
598 if (nVersion
== 0x0001)
600 // Create ListSourceSeq from String
601 OUString sListSource
;
602 _rxInStream
>> sListSource
;
604 sal_Int32 nTokens
= 1;
605 const sal_Unicode
* pStr
= sListSource
.getStr();
612 aListSourceSeq
.realloc( nTokens
);
613 for (sal_uInt16 i
=0; i
<nTokens
; ++i
)
616 aListSourceSeq
.getArray()[i
] = sListSource
.getToken(i
,';',nTmp
);
620 _rxInStream
>> aListSourceSeq
;
622 sal_Int16 nListSourceType
;
623 _rxInStream
>> nListSourceType
;
624 m_eListSourceType
= (ListSourceType
)nListSourceType
;
625 Any aListSourceSeqAny
;
626 aListSourceSeqAny
<<= aListSourceSeq
;
628 setFastPropertyValue(PROPERTY_ID_LISTSOURCE
, aListSourceSeqAny
);
630 // Dummy sequence, to stay compatible if SelectSeq is not saved anymore
631 Sequence
<sal_Int16
> aDummySeq
;
632 _rxInStream
>> aDummySeq
;
635 Sequence
<sal_Int16
> aDefaultSelectSeq
;
636 _rxInStream
>> aDefaultSelectSeq
;
637 Any aDefaultSelectSeqAny
;
638 aDefaultSelectSeqAny
<<= aDefaultSelectSeq
;
639 setFastPropertyValue(PROPERTY_ID_DEFAULT_SELECT_SEQ
, aDefaultSelectSeqAny
);
642 if ((nAnyMask
& BOUNDCOLUMN
) == BOUNDCOLUMN
)
645 _rxInStream
>> nValue
;
646 m_aBoundColumn
<<= nValue
;
648 else // the constructor initialises to 1, so if it is empty,
649 // we must explicitly set to empty
651 m_aBoundColumn
= Any();
655 readHelpTextCompatibly(_rxInStream
);
657 // if our string list is not filled from the value list, we must empty it
658 // this can be the case when somebody saves in alive mode
659 if ( ( m_eListSourceType
!= ListSourceType_VALUELIST
)
660 && !hasExternalListSource()
663 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, makeAny( StringSequence() ) );
667 readCommonProperties(_rxInStream
);
669 // Display the default values after reading
670 if ( !getControlSource().isEmpty() )
671 // (not if we don't have a control source - the "State" property acts like it is persistent, then
676 void OListBoxModel::loadData( bool _bForce
)
678 SAL_INFO( "forms.component", "OListBoxModel::loadData" );
679 DBG_ASSERT( m_eListSourceType
!= ListSourceType_VALUELIST
, "OListBoxModel::loadData: cannot load value list from DB!" );
680 DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::loadData: cannot load from DB when I have an external list source!" );
682 const sal_Int16
nNULLPosBackup( m_nNULLPos
);
683 const sal_Int32
nBoundColumnTypeBackup( m_nBoundColumnType
);
685 m_nBoundColumnType
= DataType::SQLNULL
;
689 Reference
< XConnection
> xConnection
;
690 // is the active connection of our form
691 Reference
< XPropertySet
> xFormProps( m_xCursor
, UNO_QUERY
);
692 if ( xFormProps
.is() )
693 xFormProps
->getPropertyValue( PROPERTY_ACTIVE_CONNECTION
) >>= xConnection
;
696 OUString sListSource
;
697 // if our list source type is no value list, we need to concatenate
698 // the single list source elements
700 m_aListSourceValues
.begin(),
701 m_aListSourceValues
.end(),
702 AppendRowSetValueString( sListSource
)
705 // outta here if we don't have all pre-requisites
706 if ( !xConnection
.is() || sListSource
.isEmpty() )
712 ::boost::optional
< sal_Int16
> aBoundColumn(boost::none
);
713 if ( m_aBoundColumn
.getValueType().getTypeClass() == TypeClass_SHORT
)
715 sal_Int16
nBoundColumn( 0 );
716 m_aBoundColumn
>>= nBoundColumn
;
717 aBoundColumn
.reset( nBoundColumn
);
720 ::utl::SharedUNOComponent
< XResultSet
> xListCursor
;
723 m_aListRowSet
.setConnection( xConnection
);
725 bool bExecute
= false;
726 switch (m_eListSourceType
)
728 case ListSourceType_TABLEFIELDS
:
729 // don't work with a statement here, the fields will be collected below
732 case ListSourceType_TABLE
:
734 Reference
<XNameAccess
> xFieldsByName
= getTableFields(xConnection
, sListSource
);
735 Reference
<XIndexAccess
> xFieldsByIndex(xFieldsByName
, UNO_QUERY
);
737 // do we have a bound column if yes we have to select it
738 // and the displayed column is the first column othwhise we act as a combobox
740 OUString aBoundFieldName
;
742 if ( !!aBoundColumn
&& ( *aBoundColumn
>= 0 ) && xFieldsByIndex
.is() )
744 if ( *aBoundColumn
>= xFieldsByIndex
->getCount() )
747 Reference
<XPropertySet
> xFieldAsSet(xFieldsByIndex
->getByIndex( *aBoundColumn
),UNO_QUERY
);
748 assert(xFieldAsSet
.is());
749 xFieldAsSet
->getPropertyValue(PROPERTY_NAME
) >>= aBoundFieldName
;
750 aBoundColumn
.reset( 1 );
752 xFieldAsSet
.set(xFieldsByIndex
->getByIndex(0),UNO_QUERY
);
753 xFieldAsSet
->getPropertyValue(PROPERTY_NAME
) >>= aFieldName
;
755 else if (xFieldsByName
.is())
757 if ( xFieldsByName
->hasByName( getControlSource() ) )
758 aFieldName
= getControlSource();
761 // otherwise look for the alias
762 Reference
< XColumnsSupplier
> xSupplyFields
;
763 xFormProps
->getPropertyValue("SingleSelectQueryComposer") >>= xSupplyFields
;
766 DBG_ASSERT(xSupplyFields
.is(), "OListBoxModel::loadData : invalid query composer !");
768 Reference
<XNameAccess
> xFieldNames
= xSupplyFields
->getColumns();
769 if ( xFieldNames
->hasByName( getControlSource() ) )
771 Reference
<XPropertySet
> xComposerFieldAsSet
;
772 xFieldNames
->getByName( getControlSource() ) >>= xComposerFieldAsSet
;
773 if (hasProperty(PROPERTY_FIELDSOURCE
, xComposerFieldAsSet
))
774 xComposerFieldAsSet
->getPropertyValue(PROPERTY_FIELDSOURCE
) >>= aFieldName
;
778 if (aFieldName
.isEmpty())
781 Reference
<XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
782 OUString aQuote
= xMeta
->getIdentifierQuoteString();
783 OUString
aStatement("SELECT ");
784 if (aBoundFieldName
.isEmpty()) // act like a combobox
785 aStatement
+= "DISTINCT ";
787 aStatement
+= quoteName(aQuote
,aFieldName
);
788 if (!aBoundFieldName
.isEmpty())
791 aStatement
+= quoteName(aQuote
, aBoundFieldName
);
793 aStatement
+= " FROM ";
795 OUString sCatalog
, sSchema
, sTable
;
796 qualifiedNameComponents( xMeta
, sListSource
, sCatalog
, sSchema
, sTable
, eInDataManipulation
);
797 aStatement
+= composeTableNameForSelect( xConnection
, sCatalog
, sSchema
, sTable
);
799 m_aListRowSet
.setEscapeProcessing( false );
800 m_aListRowSet
.setCommand( aStatement
);
805 case ListSourceType_QUERY
:
806 m_aListRowSet
.setCommandFromQuery( sListSource
);
811 m_aListRowSet
.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH
!= m_eListSourceType
);
812 m_aListRowSet
.setCommand( sListSource
);
819 if ( !_bForce
&& !m_aListRowSet
.isDirty() )
821 // if none of the settings of the row set changed, compared to the last
822 // invocation of loadData, then don't re-fill the list. Instead, assume
823 // the list entries are the same.
824 m_nNULLPos
= nNULLPosBackup
;
825 m_nBoundColumnType
= nBoundColumnTypeBackup
;
828 xListCursor
.reset( m_aListRowSet
.execute() );
831 catch(const SQLException
& eSQL
)
833 onError(eSQL
, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST
));
836 catch(const Exception
& eUnknown
)
842 // Fill display and value lists
843 ValueList aDisplayList
, aValueList
;
844 bool bUseNULL
= hasField() && !isRequired();
846 // empty BoundColumn is treated as BoundColumn==0,
852 OSL_ENSURE( xListCursor
.is() || ( ListSourceType_TABLEFIELDS
== m_eListSourceType
),
853 "OListBoxModel::loadData: logic error!" );
854 if ( !xListCursor
.is() && ( ListSourceType_TABLEFIELDS
!= m_eListSourceType
) )
857 switch (m_eListSourceType
)
859 #if HAVE_FEATURE_DBCONNECTIVITY
860 case ListSourceType_SQL
:
861 case ListSourceType_SQLPASSTHROUGH
:
862 case ListSourceType_TABLE
:
863 case ListSourceType_QUERY
:
865 // Get field of the ResultSet's 1st column
866 Reference
<XColumnsSupplier
> xSupplyCols(xListCursor
, UNO_QUERY
);
867 DBG_ASSERT(xSupplyCols
.is(), "OListBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
868 Reference
<XIndexAccess
> xColumns
;
869 if (xSupplyCols
.is())
871 xColumns
= Reference
<XIndexAccess
>(xSupplyCols
->getColumns(), UNO_QUERY
);
872 DBG_ASSERT(xColumns
.is(), "OListBoxModel::loadData : no columns supplied by the row set !");
875 Reference
< XPropertySet
> xDataField
;
877 xColumns
->getByIndex(0) >>= xDataField
;
878 if ( !xDataField
.is() )
881 ::dbtools::FormattedColumnValue
aValueFormatter( getContext(), m_xCursor
, xDataField
);
883 // Get the field of BoundColumn of the ResultSet
884 m_nBoundColumnType
= DataType::SQLNULL
;
885 if ( *aBoundColumn
>= 0 )
889 Reference
< XPropertySet
> xBoundField( xColumns
->getByIndex( *aBoundColumn
), UNO_QUERY_THROW
);
890 OSL_VERIFY( xBoundField
->getPropertyValue("Type") >>= m_nBoundColumnType
);
892 catch( const Exception
& )
894 DBG_UNHANDLED_EXCEPTION();
897 else if ( *aBoundColumn
== -1)
898 m_nBoundColumnType
= DataType::SMALLINT
;
900 // If the LB is bound to a field and empty entries are valid, we remember the position
901 // for an empty entry
902 SAL_INFO( "forms.component", "OListBoxModel::loadData: string collection" );
904 sal_Int16 entryPos
= 0;
905 ORowSetValue aBoundValue
;
906 Reference
< XRow
> xCursorRow( xListCursor
, UNO_QUERY_THROW
);
907 while ( xListCursor
->next() && ( entryPos
++ < SHRT_MAX
) ) // SHRT_MAX is the maximum number of entries
909 aStr
= aValueFormatter
.getFormattedValue();
910 aDisplayList
.push_back( aStr
);
912 if(*aBoundColumn
>= 0)
913 aBoundValue
.fill( *aBoundColumn
+ 1, m_nBoundColumnType
, xCursorRow
);
915 // -1 because getRow() is 1-indexed, but ListBox positions are 0-indexed
916 aBoundValue
= static_cast<sal_Int16
>(xListCursor
->getRow()-1);
917 aValueList
.push_back( aBoundValue
);
919 if ( m_nNULLPos
== -1 && aBoundValue
.isNull() )
920 m_nNULLPos
= sal_Int16( aDisplayList
.size() - 1 );
921 if ( bUseNULL
&& ( m_nNULLPos
== -1 ) && aStr
.isEmpty() )
922 // There is already a non-NULL entry with empty display string;
923 // adding another one for NULL would make things confusing,
930 case ListSourceType_TABLEFIELDS
:
932 Reference
<XNameAccess
> xFieldNames
= getTableFields(xConnection
, sListSource
);
933 if (xFieldNames
.is())
935 StringSequence seqNames
= xFieldNames
->getElementNames();
937 seqNames
.getConstArray(),
938 seqNames
.getConstArray() + seqNames
.getLength(),
939 ::std::insert_iterator
< ValueList
>( aDisplayList
, aDisplayList
.end() )
941 if(*aBoundColumn
== -1)
943 // the type of i matters! It will be the type of the ORowSetValue pushed to aValueList!
944 for(sal_Int16 i
=0; static_cast<ValueList::size_type
>(i
) < aDisplayList
.size(); ++i
)
946 aValueList
.push_back(i
);
951 aValueList
= aDisplayList
;
957 SAL_WARN( "forms.component", "OListBoxModel::loadData: unreachable!" );
961 catch(const SQLException
& eSQL
)
963 onError(eSQL
, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST
));
966 catch( const Exception
& )
968 DBG_UNHANDLED_EXCEPTION();
973 // Create Values sequence
975 if (bUseNULL
&& m_nNULLPos
== -1)
977 aValueList
.insert( aValueList
.begin(), ORowSetValue() );
979 aDisplayList
.insert( aDisplayList
.begin(), ORowSetValue( OUString() ) );
983 setBoundValues(aValueList
);
985 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, makeAny( lcl_convertToStringSequence( aDisplayList
) ) );
989 void OListBoxModel::onConnectedDbColumn( const Reference
< XInterface
>& /*_rxForm*/ )
991 // list boxes which are bound to a db column don't have multi selection
992 // - this would be unable to reflect in the db column
995 setFastPropertyValue( PROPERTY_ID_MULTISELECTION
, css::uno::Any(false) );
998 if ( !hasExternalListSource() )
999 impl_refreshDbEntryList( false );
1003 void OListBoxModel::onDisconnectedDbColumn()
1007 m_nBoundColumnType
= DataType::SQLNULL
;
1009 if ( m_eListSourceType
!= ListSourceType_VALUELIST
)
1011 if ( !hasExternalListSource() )
1012 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST
, makeAny( StringSequence() ) );
1014 m_aListRowSet
.dispose();
1019 void OListBoxModel::setBoundValues(const ValueList
&l
)
1021 m_aConvertedBoundValues
.clear();
1026 void OListBoxModel::clearBoundValues()
1028 ValueList().swap(m_aConvertedBoundValues
);
1029 ValueList().swap(m_aBoundValues
);
1033 void OListBoxModel::convertBoundValues(const sal_Int32 nFieldType
) const
1035 assert(s_aEmptyValue
.isNull());
1037 m_aConvertedBoundValues
.resize(m_aBoundValues
.size());
1038 ValueList::const_iterator src
= m_aBoundValues
.begin();
1039 const ValueList::const_iterator end
= m_aBoundValues
.end();
1040 ValueList::iterator dst
= m_aConvertedBoundValues
.begin();
1041 for (; src
!= end
; ++src
, ++dst
)
1043 if(m_nNULLPos
== -1 &&
1045 (*src
== s_aEmptyStringValue
|| *src
== s_aEmptyValue
|| src
->isNull()) )
1047 m_nNULLPos
= src
- m_aBoundValues
.begin();
1054 dst
->setTypeKind(nFieldType
);
1056 m_nConvertedBoundValuesType
= nFieldType
;
1057 OSL_ENSURE(dst
== m_aConvertedBoundValues
.end(), "OListBoxModel::convertBoundValues expected to have overwritten all of m_aConvertedBoundValues, but did not.");
1058 assert(dst
== m_aConvertedBoundValues
.end());
1061 sal_Int32
OListBoxModel::getValueType() const
1063 return impl_hasBoundComponent() ? m_nBoundColumnType
: getFieldType();
1066 ValueList
OListBoxModel::impl_getValues() const
1068 const sal_Int32 nFieldType
= getValueType();
1070 if ( !m_aConvertedBoundValues
.empty() && m_nConvertedBoundValuesType
== nFieldType
)
1071 return m_aConvertedBoundValues
;
1073 if ( !m_aBoundValues
.empty() )
1075 convertBoundValues(nFieldType
);
1076 return m_aConvertedBoundValues
;
1079 Sequence
< OUString
> aStringItems( getStringItemList() );
1080 ValueList
aValues( aStringItems
.getLength() );
1081 ValueList::iterator dst
= aValues
.begin();
1082 const OUString
*src (aStringItems
.getConstArray());
1083 const OUString
* const end
= src
+ aStringItems
.getLength();
1084 for (; src
< end
; ++src
, ++dst
)
1087 dst
->setTypeKind(nFieldType
);
1089 m_nConvertedBoundValuesType
= nFieldType
;
1090 OSL_ENSURE(dst
== aValues
.end(), "OListBoxModel::impl_getValues expected to have set all of aValues, but did not.");
1091 assert(dst
== aValues
.end());
1095 ORowSetValue
OListBoxModel::getFirstSelectedValue() const
1097 DBG_ASSERT( m_xAggregateFastSet
.is(), "OListBoxModel::getFirstSelectedValue: invalid aggregate!" );
1098 if ( !m_xAggregateFastSet
.is() )
1099 return s_aEmptyValue
;
1101 Sequence
< sal_Int16
> aSelectedIndices
;
1102 OSL_VERIFY( m_xAggregateFastSet
->getFastPropertyValue( getValuePropertyAggHandle() ) >>= aSelectedIndices
);
1103 if ( !aSelectedIndices
.getLength() )
1104 // nothing selected at all
1105 return s_aEmptyValue
;
1107 if ( ( m_nNULLPos
!= -1 ) && ( aSelectedIndices
[0] == m_nNULLPos
) )
1108 // the dedicated "NULL" entry is selected
1109 return s_aEmptyValue
;
1111 ValueList
aValues( impl_getValues() );
1113 size_t selectedValue
= aSelectedIndices
[0];
1114 if ( selectedValue
>= aValues
.size() )
1116 SAL_WARN( "forms.component", "OListBoxModel::getFirstSelectedValue: inconsistent selection/valuelist!" );
1117 return s_aEmptyValue
;
1120 return aValues
[ selectedValue
];
1124 bool OListBoxModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
1126 // current selection list
1127 const ORowSetValue
aCurrentValue( getFirstSelectedValue() );
1128 if ( aCurrentValue
!= m_aSaveValue
)
1130 if ( aCurrentValue
.isNull() )
1131 m_xColumnUpdate
->updateNull();
1136 m_xColumnUpdate
->updateObject( aCurrentValue
.makeAny() );
1138 catch ( const Exception
& )
1143 m_aSaveValue
= aCurrentValue
;
1149 Sequence
< sal_Int16
> OListBoxModel::translateDbValueToControlValue(const ORowSetValue
&i_aValue
) const
1151 Sequence
< sal_Int16
> aSelectionIndicies
;
1153 // reset selection for NULL values
1154 if ( i_aValue
.isNull() )
1156 if ( m_nNULLPos
!= -1 )
1158 aSelectionIndicies
.realloc(1);
1159 aSelectionIndicies
[0] = m_nNULLPos
;
1164 ValueList
aValues( impl_getValues() );
1165 assert( m_nConvertedBoundValuesType
== getValueType());
1166 ORowSetValue
v(i_aValue
);
1167 v
.setTypeKind( m_nConvertedBoundValuesType
);
1168 ValueList::const_iterator curValuePos
= ::std::find( aValues
.begin(), aValues
.end(), v
);
1169 if ( curValuePos
!= aValues
.end() )
1171 aSelectionIndicies
.realloc( 1 );
1172 aSelectionIndicies
[0] = curValuePos
- aValues
.begin();
1176 return aSelectionIndicies
;
1179 Sequence
< sal_Int16
> OListBoxModel::translateBindingValuesToControlValue(const Sequence
< const Any
> &i_aValues
) const
1181 const ValueList
aValues( impl_getValues() );
1182 assert( m_nConvertedBoundValuesType
== getValueType());
1183 Sequence
< sal_Int16
> aSelectionIndicies(i_aValues
.getLength());
1185 sal_Int32
nCount(0);
1187 #if HAVE_FEATURE_DBCONNECTIVITY
1188 sal_Int16
*pIndex
= aSelectionIndicies
.getArray();
1189 const Any
*pValue
= i_aValues
.getConstArray();
1190 const Any
* const pValueEnd
= i_aValues
.getConstArray() + i_aValues
.getLength();
1191 for (;pValue
< pValueEnd
; ++pValue
)
1193 if ( pValue
->hasValue() )
1197 v
.setTypeKind( m_nConvertedBoundValuesType
);
1198 ValueList::const_iterator curValuePos
= ::std::find( aValues
.begin(), aValues
.end(), v
);
1199 if ( curValuePos
!= aValues
.end() )
1201 *pIndex
= curValuePos
- aValues
.begin();
1208 if ( m_nNULLPos
!= -1 )
1210 *pIndex
= m_nNULLPos
;
1216 assert(aSelectionIndicies
.getArray() + nCount
== pIndex
);
1218 aSelectionIndicies
.realloc(nCount
);
1219 return aSelectionIndicies
;
1222 Any
OListBoxModel::translateDbColumnToControlValue()
1224 #if HAVE_FEATURE_DBCONNECTIVITY
1225 Reference
< XPropertySet
> xBoundField( getField() );
1226 if ( !xBoundField
.is() )
1228 SAL_WARN( "forms.component", "OListBoxModel::translateDbColumnToControlValue: no field? How could that happen?!" );
1232 ORowSetValue aCurrentValue
;
1233 aCurrentValue
.fill( getValueType(), m_xColumn
);
1235 m_aSaveValue
= aCurrentValue
;
1237 return makeAny( translateDbValueToControlValue(aCurrentValue
) );
1245 Any
OListBoxModel::getDefaultForReset() const
1248 if (m_aDefaultSelectSeq
.getLength())
1249 aValue
<<= m_aDefaultSelectSeq
;
1250 else if (m_nNULLPos
!= -1) // bound Listbox
1252 Sequence
<sal_Int16
> aSeq(1);
1253 aSeq
.getArray()[0] = m_nNULLPos
;
1258 Sequence
<sal_Int16
> aSeq
;
1266 void OListBoxModel::resetNoBroadcast()
1268 OBoundControlModel::resetNoBroadcast();
1269 m_aSaveValue
.setNull();
1273 void SAL_CALL
OListBoxModel::disposing( const EventObject
& _rSource
) throw ( RuntimeException
, std::exception
)
1275 if ( !OEntryListHelper::handleDisposing( _rSource
) )
1276 OBoundControlModel::disposing( _rSource
);
1282 // The type of how we should transfer our selection to external value bindings
1285 eIndexList
, /// as list of indexes of selected entries
1286 eIndex
, /// as index of the selected entry
1287 eEntryList
, /// as list of string representations of selected *display* entries
1288 eEntry
, /// as string representation of the selected *display* entry
1289 eValueList
, /// as list of string representations of selected values
1290 eValue
/// as string representation of the selected value
1294 ExchangeType
lcl_getCurrentExchangeType( const Type
& _rExchangeType
)
1296 switch ( _rExchangeType
.getTypeClass() )
1300 case TypeClass_STRING
:
1302 case TypeClass_LONG
:
1304 case TypeClass_SEQUENCE
:
1306 Type aElementType
= ::comphelper::getSequenceElementType( _rExchangeType
);
1307 switch ( aElementType
.getTypeClass() )
1311 case TypeClass_STRING
:
1313 case TypeClass_LONG
:
1322 SAL_WARN( "forms.component", "lcl_getCurrentExchangeType: unsupported (unexpected) exchange type!" );
1328 Any
OListBoxModel::translateExternalValueToControlValue( const Any
& _rExternalValue
) const
1330 Sequence
< sal_Int16
> aSelectIndexes
;
1332 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1336 Sequence
< const Any
> aExternalValues
;
1337 OSL_VERIFY( _rExternalValue
>>= aExternalValues
);
1338 aSelectIndexes
= translateBindingValuesToControlValue( aExternalValues
);
1343 #if HAVE_FEATURE_DBCONNECTIVITY
1346 v
.fill(_rExternalValue
);
1347 aSelectIndexes
= translateDbValueToControlValue(v
);
1354 // unfortunately, our select sequence is a sequence<short>, while the external binding
1355 // supplies sequence<int> only -> transform this
1356 Sequence
< sal_Int32
> aSelectIndexesPure
;
1357 OSL_VERIFY( _rExternalValue
>>= aSelectIndexesPure
);
1358 aSelectIndexes
.realloc( aSelectIndexesPure
.getLength() );
1360 aSelectIndexesPure
.getConstArray(),
1361 aSelectIndexesPure
.getConstArray() + aSelectIndexesPure
.getLength(),
1362 aSelectIndexes
.getArray()
1369 sal_Int32 nSelectIndex
= -1;
1370 OSL_VERIFY( _rExternalValue
>>= nSelectIndex
);
1371 if ( ( nSelectIndex
>= 0 ) && ( nSelectIndex
< getStringItemList().getLength() ) )
1373 aSelectIndexes
.realloc( 1 );
1374 aSelectIndexes
[ 0 ] = static_cast< sal_Int16
>( nSelectIndex
);
1381 // we can retrieve a string list from the binding for multiple selection
1382 Sequence
< OUString
> aSelectEntries
;
1383 OSL_VERIFY( _rExternalValue
>>= aSelectEntries
);
1385 ::std::set
< sal_Int16
> aSelectionSet
;
1387 // find the selection entries in our item list
1388 const OUString
* pSelectEntries
= aSelectEntries
.getArray();
1389 const OUString
* pSelectEntriesEnd
= pSelectEntries
+ aSelectEntries
.getLength();
1390 while ( pSelectEntries
!= pSelectEntriesEnd
)
1392 // the indexes where the current string appears in our string items
1393 Sequence
< sal_Int16
> aThisEntryIndexes
;
1394 aThisEntryIndexes
= findValue( getStringItemList(), *pSelectEntries
++, false );
1396 // insert all the indexes of this entry into our set
1398 aThisEntryIndexes
.getConstArray(),
1399 aThisEntryIndexes
.getConstArray() + aThisEntryIndexes
.getLength(),
1400 ::std::insert_iterator
< ::std::set
< sal_Int16
> >( aSelectionSet
, aSelectionSet
.begin() )
1404 // copy the indexes to the sequence
1405 aSelectIndexes
.realloc( aSelectionSet
.size() );
1407 aSelectionSet
.begin(),
1408 aSelectionSet
.end(),
1409 aSelectIndexes
.getArray()
1416 OUString sStringToSelect
;
1417 OSL_VERIFY( _rExternalValue
>>= sStringToSelect
);
1419 aSelectIndexes
= findValue( getStringItemList(), sStringToSelect
, false );
1424 return makeAny( aSelectIndexes
);
1431 struct ExtractStringFromSequence_Safe
: public ::std::unary_function
< sal_Int16
, OUString
>
1434 const Sequence
< OUString
>& m_rList
;
1437 ExtractStringFromSequence_Safe( const Sequence
< OUString
>& _rList
) : m_rList( _rList
) { }
1439 OUString
operator ()( sal_Int16 _nIndex
)
1441 OSL_ENSURE( _nIndex
< m_rList
.getLength(), "ExtractStringFromSequence_Safe: inconsistence!" );
1442 if ( _nIndex
< m_rList
.getLength() )
1443 return m_rList
[ _nIndex
];
1449 Any
lcl_getSingleSelectedEntry( const Sequence
< sal_Int16
>& _rSelectSequence
, const Sequence
< OUString
>& _rStringList
)
1453 // by definition, multiple selected entries are transferred as NULL if the
1454 // binding does not support string lists
1455 if ( _rSelectSequence
.getLength() <= 1 )
1457 OUString sSelectedEntry
;
1459 if ( _rSelectSequence
.getLength() == 1 )
1460 sSelectedEntry
= ExtractStringFromSequence_Safe( _rStringList
)( _rSelectSequence
[0] );
1462 aReturn
<<= sSelectedEntry
;
1469 Any
lcl_getMultiSelectedEntries( const Sequence
< sal_Int16
>& _rSelectSequence
, const Sequence
< OUString
>& _rStringList
)
1471 Sequence
< OUString
> aSelectedEntriesTexts( _rSelectSequence
.getLength() );
1473 _rSelectSequence
.getConstArray(),
1474 _rSelectSequence
.getConstArray() + _rSelectSequence
.getLength(),
1475 aSelectedEntriesTexts
.getArray(),
1476 ExtractStringFromSequence_Safe( _rStringList
)
1478 return makeAny( aSelectedEntriesTexts
);
1482 struct ExtractAnyFromValueList_Safe
: public ::std::unary_function
< sal_Int16
, Any
>
1485 const ValueList
& m_rList
;
1488 ExtractAnyFromValueList_Safe( const ValueList
& _rList
) : m_rList( _rList
) { }
1490 Any
operator ()( sal_Int16 _nIndex
)
1492 OSL_ENSURE( static_cast<ValueList::size_type
>(_nIndex
) < m_rList
.size(), "ExtractAnyFromValueList: inconsistence!" );
1493 if ( static_cast<ValueList::size_type
>(_nIndex
) < m_rList
.size() )
1494 return m_rList
[ _nIndex
].makeAny();
1500 Any
lcl_getSingleSelectedEntryAny( const Sequence
< sal_Int16
>& _rSelectSequence
, const ValueList
& _rStringList
)
1504 // by definition, multiple selected entries are transferred as NULL if the
1505 // binding does not support string lists
1506 if ( _rSelectSequence
.getLength() <= 1 )
1508 if ( _rSelectSequence
.getLength() == 1 )
1509 aReturn
= ExtractAnyFromValueList_Safe( _rStringList
)( _rSelectSequence
[0] );
1516 Any
lcl_getMultiSelectedEntriesAny( const Sequence
< sal_Int16
>& _rSelectSequence
, const ValueList
& _rStringList
)
1518 Sequence
< Any
> aSelectedEntriesValues( _rSelectSequence
.getLength() );
1520 _rSelectSequence
.getConstArray(),
1521 _rSelectSequence
.getConstArray() + _rSelectSequence
.getLength(),
1522 aSelectedEntriesValues
.getArray(),
1523 ExtractAnyFromValueList_Safe( _rStringList
)
1525 return makeAny( aSelectedEntriesValues
);
1530 Any
OListBoxModel::translateControlValueToExternalValue( ) const
1532 OSL_PRECOND( hasExternalValueBinding(), "OListBoxModel::translateControlValueToExternalValue: no binding!" );
1534 Sequence
< sal_Int16
> aSelectSequence
;
1535 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1538 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1541 aReturn
= getCurrentMultiValue();
1545 aReturn
= getCurrentSingleValue();
1550 // unfortunately, the select sequence is a sequence<short>, but our binding
1552 Sequence
< sal_Int32
> aTransformed( aSelectSequence
.getLength() );
1554 aSelectSequence
.getConstArray(),
1555 aSelectSequence
.getConstArray() + aSelectSequence
.getLength(),
1556 aTransformed
.getArray()
1558 aReturn
<<= aTransformed
;
1563 if ( aSelectSequence
.getLength() <= 1 )
1565 sal_Int32 nIndex
= -1;
1567 if ( aSelectSequence
.getLength() == 1 )
1568 nIndex
= aSelectSequence
[0];
1575 aReturn
= lcl_getMultiSelectedEntries( aSelectSequence
, getStringItemList() );
1579 aReturn
= lcl_getSingleSelectedEntry( aSelectSequence
, getStringItemList() );
1587 Any
OListBoxModel::translateControlValueToValidatableValue( ) const
1589 OSL_PRECOND( hasValidator(), "OListBoxModel::translateControlValueToValidatableValue: no validator, so why should I?" );
1590 return getCurrentFormComponentValue();
1594 Any
OListBoxModel::getCurrentSingleValue() const
1600 Sequence
< sal_Int16
> aSelectSequence
;
1601 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1602 aCurrentValue
= lcl_getSingleSelectedEntryAny( aSelectSequence
, impl_getValues() );
1604 catch( const Exception
& )
1606 DBG_UNHANDLED_EXCEPTION();
1609 return aCurrentValue
;
1612 Any
OListBoxModel::getCurrentMultiValue() const
1618 Sequence
< sal_Int16
> aSelectSequence
;
1619 OSL_VERIFY( getControlValue() >>= aSelectSequence
);
1620 aCurrentValue
= lcl_getMultiSelectedEntriesAny( aSelectSequence
, impl_getValues() );
1622 catch( const Exception
& )
1624 DBG_UNHANDLED_EXCEPTION();
1627 return aCurrentValue
;
1630 Any
OListBoxModel::getCurrentFormComponentValue() const
1633 Reference
< com::sun::star::form::validation::XValidator
> vtor (const_cast<OListBoxModel
*>(this)->getValidator());
1634 Reference
< XValueBinding
> extBinding (const_cast<OListBoxModel
*>(this)->getValueBinding());
1635 if ( vtor
.is() && vtor
== extBinding
)
1636 return translateControlValueToExternalValue();
1643 bool bMultiSelection( false );
1644 OSL_VERIFY( const_cast< OListBoxModel
* >( this )->getPropertyValue( PROPERTY_MULTISELECTION
) >>= bMultiSelection
);
1646 if ( bMultiSelection
)
1647 aCurrentValue
= getCurrentMultiValue();
1649 aCurrentValue
= getCurrentSingleValue();
1651 catch( const Exception
& )
1653 DBG_UNHANDLED_EXCEPTION();
1656 return aCurrentValue
;
1660 Sequence
< Type
> OListBoxModel::getSupportedBindingTypes()
1662 Sequence
< Type
> aTypes(6);
1663 aTypes
[0] = cppu::UnoType
<Sequence
< Any
>>::get();
1664 aTypes
[1] = cppu::UnoType
<Any
>::get();
1665 aTypes
[2] = cppu::UnoType
<Sequence
< sal_Int32
>>::get();
1666 aTypes
[3] = cppu::UnoType
<sal_Int32
>::get();
1667 aTypes
[4] = cppu::UnoType
<Sequence
< OUString
>>::get();
1668 aTypes
[5] = cppu::UnoType
<OUString
>::get();
1673 void OListBoxModel::stringItemListChanged( ControlModelLock
& _rInstanceLock
)
1675 if ( !m_xAggregateSet
.is() )
1678 suspendValueListening();
1681 m_xAggregateSet
->setPropertyValue( PROPERTY_STRINGITEMLIST
, makeAny( getStringItemList() ) );
1683 catch( const Exception
& )
1685 DBG_UNHANDLED_EXCEPTION();
1687 resumeValueListening();
1689 // update the selection here
1690 if ( hasExternalValueBinding( ) )
1691 transferExternalValueToControl( _rInstanceLock
);
1696 // TODO: update the selection in case we're bound to a database column
1700 if ( m_aDefaultSelectSeq
.getLength() )
1701 setControlValue( makeAny( m_aDefaultSelectSeq
), eOther
);
1707 void OListBoxModel::connectedExternalListSource( )
1713 void OListBoxModel::disconnectedExternalListSource( )
1715 // TODO: in case we're part of an already loaded form, we should probably simulate
1716 // an onConnectedDbColumn, so our list get's filled with the data as indicated
1717 // by our SQL-binding related properties
1721 void OListBoxModel::impl_refreshDbEntryList( bool _bForce
)
1723 DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::impl_refreshDbEntryList: invalid call!" );
1725 if ( !hasExternalListSource( )
1726 && ( m_eListSourceType
!= ListSourceType_VALUELIST
)
1727 && ( m_xCursor
.is() )
1730 loadData( _bForce
);
1735 void OListBoxModel::refreshInternalEntryList()
1737 impl_refreshDbEntryList( true );
1738 if ( hasField() && m_xCursor
.is() )
1739 initFromField( m_xCursor
);
1745 Sequence
< Type
> OListBoxControl::_getTypes()
1748 OBoundControl::_getTypes(),
1749 OListBoxControl_BASE::getTypes()
1754 Any SAL_CALL
OListBoxControl::queryAggregation(const Type
& _rType
) throw (RuntimeException
, std::exception
)
1756 Any aReturn
= OListBoxControl_BASE::queryInterface( _rType
);
1758 if ( !aReturn
.hasValue()
1759 || _rType
.equals( cppu::UnoType
<XTypeProvider
>::get() )
1761 aReturn
= OBoundControl::queryAggregation( _rType
);
1767 OListBoxControl::OListBoxControl(const Reference
<XComponentContext
>& _rxFactory
)
1768 :OBoundControl( _rxFactory
, VCL_CONTROL_LISTBOX
, false )
1769 ,m_aChangeListeners( m_aMutex
)
1770 ,m_aItemListeners( m_aMutex
)
1773 osl_atomic_increment(&m_refCount
);
1775 // Register as FocusListener
1776 Reference
<XWindow
> xComp
;
1777 if (query_aggregation(m_xAggregate
, xComp
))
1778 xComp
->addFocusListener(this);
1780 // Register as ItemListener
1781 if ( query_aggregation( m_xAggregate
, m_xAggregateListBox
) )
1782 m_xAggregateListBox
->addItemListener(this);
1784 // Refcount at 2 for registered Listener
1785 osl_atomic_decrement(&m_refCount
);
1789 m_aChangeIdle
.SetPriority(SchedulerPriority::LOWEST
);
1790 m_aChangeIdle
.SetIdleHdl(LINK(this,OListBoxControl
,OnTimeout
));
1794 OListBoxControl::~OListBoxControl()
1796 if (!OComponentHelper::rBHelper
.bDisposed
)
1803 m_xAggregateListBox
.clear();
1808 StringSequence SAL_CALL
OListBoxControl::getSupportedServiceNames() throw(RuntimeException
, std::exception
)
1810 StringSequence aSupported
= OBoundControl::getSupportedServiceNames();
1811 aSupported
.realloc(aSupported
.getLength() + 2);
1813 OUString
* pArray
= aSupported
.getArray();
1814 pArray
[aSupported
.getLength()-2] = FRM_SUN_CONTROL_LISTBOX
;
1815 pArray
[aSupported
.getLength()-1] = STARDIV_ONE_FORM_CONTROL_LISTBOX
;
1822 void SAL_CALL
OListBoxControl::focusGained(const FocusEvent
& /*_rEvent*/) throw(RuntimeException
, std::exception
)
1824 ::osl::MutexGuard
aGuard(m_aMutex
);
1825 if ( m_aChangeListeners
.getLength() ) // only if there are listeners
1827 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1830 // memorize the current selection for posting the change event
1831 m_aCurrentSelection
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1837 void SAL_CALL
OListBoxControl::focusLost(const FocusEvent
& /*_rEvent*/) throw(RuntimeException
, std::exception
)
1839 m_aCurrentSelection
.clear();
1844 void SAL_CALL
OListBoxControl::itemStateChanged(const ItemEvent
& _rEvent
) throw(RuntimeException
, std::exception
)
1846 // forward this to our listeners
1847 Reference
< XChild
> xChild( getModel(), UNO_QUERY
);
1848 if ( xChild
.is() && xChild
->getParent().is() )
1850 ::osl::MutexGuard
aGuard( m_aMutex
);
1851 if ( m_aItemListeners
.getLength() )
1853 if ( !m_pItemBroadcaster
.is() )
1855 m_pItemBroadcaster
.set(
1856 new ::comphelper::AsyncEventNotifier("ListBox"));
1857 m_pItemBroadcaster
->launch();
1859 m_pItemBroadcaster
->addEvent( new ItemEventDescription( _rEvent
), this );
1863 m_aItemListeners
.notifyEach( &XItemListener::itemStateChanged
, _rEvent
);
1865 // and do the handling for the ChangeListeners
1866 ::osl::ClearableMutexGuard
aGuard(m_aMutex
);
1867 if ( m_aChangeIdle
.IsActive() )
1869 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1870 m_aCurrentSelection
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1872 m_aChangeIdle
.Stop();
1873 m_aChangeIdle
.Start();
1877 if ( m_aChangeListeners
.getLength() && m_aCurrentSelection
.hasValue() )
1879 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
1882 // Has the selection been changed?
1883 bool bModified(false);
1884 Any aValue
= xSet
->getPropertyValue(PROPERTY_SELECT_SEQ
);
1886 Sequence
<sal_Int16
> const & rSelection
= *static_cast<Sequence
<sal_Int16
> const *>(aValue
.getValue());
1887 Sequence
<sal_Int16
> const & rOldSelection
= *static_cast<Sequence
<sal_Int16
> const *>(m_aCurrentSelection
.getValue());
1888 sal_Int32 nLen
= rSelection
.getLength();
1889 if (nLen
!= rOldSelection
.getLength())
1893 const sal_Int16
* pVal
= rSelection
.getConstArray();
1894 const sal_Int16
* pCompVal
= rOldSelection
.getConstArray();
1896 while (nLen
-- && !bModified
)
1897 bModified
= pVal
[nLen
] != pCompVal
[nLen
];
1902 m_aCurrentSelection
= aValue
;
1903 m_aChangeIdle
.Start();
1907 else if (m_aCurrentSelection
.hasValue())
1908 m_aCurrentSelection
.clear();
1914 void SAL_CALL
OListBoxControl::disposing(const EventObject
& _rSource
) throw (RuntimeException
, std::exception
)
1916 OBoundControl::disposing(_rSource
);
1919 // XChangeBroadcaster
1921 void SAL_CALL
OListBoxControl::addChangeListener(const Reference
<XChangeListener
>& _rxListener
) throw(RuntimeException
, std::exception
)
1923 m_aChangeListeners
.addInterface( _rxListener
);
1927 void SAL_CALL
OListBoxControl::removeChangeListener(const Reference
<XChangeListener
>& _rxListener
) throw(RuntimeException
, std::exception
)
1929 m_aChangeListeners
.removeInterface( _rxListener
);
1934 void OListBoxControl::disposing()
1936 if (m_aChangeIdle
.IsActive())
1937 m_aChangeIdle
.Stop();
1939 EventObject
aEvent( *this );
1940 m_aChangeListeners
.disposeAndClear( aEvent
);
1941 m_aItemListeners
.disposeAndClear( aEvent
);
1943 rtl::Reference
< comphelper::AsyncEventNotifier
> t
;
1945 ::osl::MutexGuard
aGuard( m_aMutex
);
1946 if ( m_pItemBroadcaster
.is() )
1948 t
= m_pItemBroadcaster
;
1949 m_pItemBroadcaster
->removeEventsForProcessor( this );
1950 m_pItemBroadcaster
->terminate();
1951 m_pItemBroadcaster
= NULL
;
1958 OBoundControl::disposing();
1962 void OListBoxControl::processEvent( const AnyEvent
& _rEvent
)
1964 Reference
< XListBox
> xKeepAlive( this );
1966 ::osl::MutexGuard
aGuard( m_aMutex
);
1967 if ( OComponentHelper::rBHelper
.bDisposed
)
1970 const ItemEventDescription
& rItemEvent
= static_cast< const ItemEventDescription
& >( _rEvent
);
1971 m_aItemListeners
.notifyEach( &XItemListener::itemStateChanged
, rItemEvent
.getEventObject() );
1975 IMPL_LINK_NOARG_TYPED(OListBoxControl
, OnTimeout
, Idle
*, void)
1977 m_aChangeListeners
.notifyEach( &XChangeListener::changed
, EventObject( *this ) );
1981 void SAL_CALL
OListBoxControl::addItemListener( const Reference
< XItemListener
>& l
) throw (RuntimeException
, std::exception
)
1983 m_aItemListeners
.addInterface( l
);
1987 void SAL_CALL
OListBoxControl::removeItemListener( const Reference
< XItemListener
>& l
) throw (RuntimeException
, std::exception
)
1989 m_aItemListeners
.removeInterface( l
);
1993 void SAL_CALL
OListBoxControl::addActionListener( const Reference
< XActionListener
>& l
) throw (RuntimeException
, std::exception
)
1995 if ( m_xAggregateListBox
.is() )
1996 m_xAggregateListBox
->addActionListener( l
);
2000 void SAL_CALL
OListBoxControl::removeActionListener( const Reference
< XActionListener
>& l
) throw (RuntimeException
, std::exception
)
2002 if ( m_xAggregateListBox
.is() )
2003 m_xAggregateListBox
->removeActionListener( l
);
2007 void SAL_CALL
OListBoxControl::addItem( const OUString
& aItem
, ::sal_Int16 nPos
) throw (RuntimeException
, std::exception
)
2009 if ( m_xAggregateListBox
.is() )
2010 m_xAggregateListBox
->addItem( aItem
, nPos
);
2014 void SAL_CALL
OListBoxControl::addItems( const Sequence
< OUString
>& aItems
, ::sal_Int16 nPos
) throw (RuntimeException
, std::exception
)
2016 if ( m_xAggregateListBox
.is() )
2017 m_xAggregateListBox
->addItems( aItems
, nPos
);
2021 void SAL_CALL
OListBoxControl::removeItems( ::sal_Int16 nPos
, ::sal_Int16 nCount
) throw (RuntimeException
, std::exception
)
2023 if ( m_xAggregateListBox
.is() )
2024 m_xAggregateListBox
->removeItems( nPos
, nCount
);
2028 ::sal_Int16 SAL_CALL
OListBoxControl::getItemCount( ) throw (RuntimeException
, std::exception
)
2030 if ( m_xAggregateListBox
.is() )
2031 return m_xAggregateListBox
->getItemCount();
2036 OUString SAL_CALL
OListBoxControl::getItem( ::sal_Int16 nPos
) throw (RuntimeException
, std::exception
)
2038 if ( m_xAggregateListBox
.is() )
2039 return m_xAggregateListBox
->getItem( nPos
);
2044 Sequence
< OUString
> SAL_CALL
OListBoxControl::getItems( ) throw (RuntimeException
, std::exception
)
2046 if ( m_xAggregateListBox
.is() )
2047 return m_xAggregateListBox
->getItems();
2048 return Sequence
< OUString
>( );
2052 ::sal_Int16 SAL_CALL
OListBoxControl::getSelectedItemPos( ) throw (RuntimeException
, std::exception
)
2054 if ( m_xAggregateListBox
.is() )
2055 return m_xAggregateListBox
->getSelectedItemPos();
2060 Sequence
< ::sal_Int16
> SAL_CALL
OListBoxControl::getSelectedItemsPos( ) throw (RuntimeException
, std::exception
)
2062 if ( m_xAggregateListBox
.is() )
2063 return m_xAggregateListBox
->getSelectedItemsPos();
2064 return Sequence
< ::sal_Int16
>( );
2068 OUString SAL_CALL
OListBoxControl::getSelectedItem( ) throw (RuntimeException
, std::exception
)
2070 if ( m_xAggregateListBox
.is() )
2071 return m_xAggregateListBox
->getSelectedItem();
2076 Sequence
< OUString
> SAL_CALL
OListBoxControl::getSelectedItems( ) throw (RuntimeException
, std::exception
)
2078 if ( m_xAggregateListBox
.is() )
2079 return m_xAggregateListBox
->getSelectedItems();
2080 return Sequence
< OUString
>( );
2084 void SAL_CALL
OListBoxControl::selectItemPos( ::sal_Int16 nPos
, sal_Bool bSelect
) throw (RuntimeException
, std::exception
)
2086 if ( m_xAggregateListBox
.is() )
2087 m_xAggregateListBox
->selectItemPos( nPos
, bSelect
);
2091 void SAL_CALL
OListBoxControl::selectItemsPos( const Sequence
< ::sal_Int16
>& aPositions
, sal_Bool bSelect
) throw (RuntimeException
, std::exception
)
2093 if ( m_xAggregateListBox
.is() )
2094 m_xAggregateListBox
->selectItemsPos( aPositions
, bSelect
);
2098 void SAL_CALL
OListBoxControl::selectItem( const OUString
& aItem
, sal_Bool bSelect
) throw (RuntimeException
, std::exception
)
2100 if ( m_xAggregateListBox
.is() )
2101 m_xAggregateListBox
->selectItem( aItem
, bSelect
);
2105 sal_Bool SAL_CALL
OListBoxControl::isMutipleMode( ) throw (RuntimeException
, std::exception
)
2107 if ( m_xAggregateListBox
.is() )
2108 return m_xAggregateListBox
->isMutipleMode();
2113 void SAL_CALL
OListBoxControl::setMultipleMode( sal_Bool bMulti
) throw (RuntimeException
, std::exception
)
2115 if ( m_xAggregateListBox
.is() )
2116 m_xAggregateListBox
->setMultipleMode( bMulti
);
2120 ::sal_Int16 SAL_CALL
OListBoxControl::getDropDownLineCount( ) throw (RuntimeException
, std::exception
)
2122 if ( m_xAggregateListBox
.is() )
2123 return m_xAggregateListBox
->getDropDownLineCount();
2128 void SAL_CALL
OListBoxControl::setDropDownLineCount( ::sal_Int16 nLines
) throw (RuntimeException
, std::exception
)
2130 if ( m_xAggregateListBox
.is() )
2131 m_xAggregateListBox
->setDropDownLineCount( nLines
);
2135 void SAL_CALL
OListBoxControl::makeVisible( ::sal_Int16 nEntry
) throw (RuntimeException
, std::exception
)
2137 if ( m_xAggregateListBox
.is() )
2138 m_xAggregateListBox
->makeVisible( nEntry
);
2143 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface
* SAL_CALL
2144 com_sun_star_form_OListBoxModel_get_implementation(::com::sun::star::uno::XComponentContext
* component
,
2145 ::com::sun::star::uno::Sequence
<css::uno::Any
> const &)
2147 return cppu::acquire(new frm::OListBoxModel(component
));
2150 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface
* SAL_CALL
2151 com_sun_star_form_OListBoxControl_get_implementation(::com::sun::star::uno::XComponentContext
* component
,
2152 ::com::sun::star::uno::Sequence
<css::uno::Any
> const &)
2154 return cppu::acquire(new frm::OListBoxControl(component
));
2157 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */