xref: /aoo42x/main/forms/source/component/ListBox.cxx (revision cdf0e10c)
1 /*************************************************************************
2 *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26 ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_forms.hxx"
30 
31 #include "ListBox.hxx"
32 #include "property.hxx"
33 #include "property.hrc"
34 #include "services.hxx"
35 #include "frm_resource.hxx"
36 #include "frm_resource.hrc"
37 #include "BaseListBox.hxx"
38 #include "listenercontainers.hxx"
39 #include "componenttools.hxx"
40 
41 /** === begin UNO includes === **/
42 #include <com/sun/star/util/XNumberFormatTypes.hpp>
43 #include <com/sun/star/sdbc/XRowSet.hpp>
44 #include <com/sun/star/container/XIndexAccess.hpp>
45 #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
46 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
47 #include <com/sun/star/util/NumberFormat.hpp>
48 #include <com/sun/star/awt/XWindow.hpp>
49 #include <com/sun/star/sdbc/XConnection.hpp>
50 #include <com/sun/star/sdb/CommandType.hpp>
51 /** === end UNO includes === **/
52 
53 #include <comphelper/basicio.hxx>
54 #include <comphelper/container.hxx>
55 #include <comphelper/numbers.hxx>
56 #include <comphelper/listenernotification.hxx>
57 #include <connectivity/dbtools.hxx>
58 #include <connectivity/formattedcolumnvalue.hxx>
59 #include <connectivity/dbconversion.hxx>
60 #include <cppuhelper/queryinterface.hxx>
61 #include <rtl/logfile.hxx>
62 #include <tools/debug.hxx>
63 #include <tools/diagnose_ex.h>
64 #include <unotools/sharedunocomponent.hxx>
65 #include <vcl/svapp.hxx>
66 
67 #include <boost/optional.hpp>
68 
69 #include <algorithm>
70 #include <functional>
71 
72 
73 //.........................................................................
74 namespace frm
75 {
76     using namespace ::com::sun::star::uno;
77     using namespace ::com::sun::star::sdb;
78     using namespace ::com::sun::star::sdbc;
79     using namespace ::com::sun::star::sdbcx;
80     using namespace ::com::sun::star::beans;
81     using namespace ::com::sun::star::container;
82     using namespace ::com::sun::star::form;
83     using namespace ::com::sun::star::awt;
84     using namespace ::com::sun::star::io;
85     using namespace ::com::sun::star::lang;
86     using namespace ::com::sun::star::util;
87     using namespace ::com::sun::star::form::binding;
88     using namespace ::dbtools;
89 
90     using ::connectivity::ORowSetValue;
91 
92     //==============================================================================
93     //= helper
94     //==============================================================================
95     namespace
96     {
97         //--------------------------------------------------------------------------
98         struct RowSetValueToString : public ::std::unary_function< ORowSetValue, ::rtl::OUString >
99         {
100             ::rtl::OUString operator()( const ORowSetValue& _value ) const
101             {
102                 return _value.getString();
103             }
104         };
105 
106         //--------------------------------------------------------------------------
107         struct AppendRowSetValueString : public ::std::unary_function< ::rtl::OUString, void >
108         {
109             AppendRowSetValueString( ::rtl::OUString& _string )
110                 :m_string( _string )
111             {
112             }
113 
114             void operator()( const ::rtl::OUString _append )
115             {
116                 m_string += _append;
117             }
118 
119         private:
120             ::rtl::OUString&    m_string;
121         };
122 
123         //--------------------------------------------------------------------------
124         Sequence< ::rtl::OUString > lcl_convertToStringSequence( const ValueList& _values )
125         {
126             Sequence< ::rtl::OUString > aStrings( _values.size() );
127             ::std::transform(
128                 _values.begin(),
129                 _values.end(),
130                 aStrings.getArray(),
131                 RowSetValueToString()
132             );
133             return aStrings;
134         }
135     }
136 
137     //==============================================================================
138     //= ItemEventDescription
139     //==============================================================================
140     typedef ::comphelper::EventHolder< ItemEvent >    ItemEventDescription;
141 
142     //==============================================================================
143     //= OListBoxModel
144     //==============================================================================
145     //------------------------------------------------------------------
146     InterfaceRef SAL_CALL OListBoxModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) throw (RuntimeException)
147     {
148         return *(new OListBoxModel(_rxFactory));
149     }
150 
151     //------------------------------------------------------------------------------
152     Sequence< Type> OListBoxModel::_getTypes()
153     {
154         return TypeBag(
155             OBoundControlModel::_getTypes(),
156             OEntryListHelper::getTypes(),
157             OErrorBroadcaster::getTypes()
158         ).getTypes();
159     }
160 
161 
162     DBG_NAME(OListBoxModel);
163     //------------------------------------------------------------------
164     OListBoxModel::OListBoxModel(const Reference<XMultiServiceFactory>& _rxFactory)
165         :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_LISTBOX, FRM_SUN_CONTROL_LISTBOX, sal_True, sal_True, sal_True )
166         // use the old control name for compytibility reasons
167         ,OEntryListHelper( (OControlModel&)*this )
168         ,OErrorBroadcaster( OComponentHelper::rBHelper )
169         ,m_aListRowSet( getContext() )
170         ,m_nNULLPos(-1)
171         ,m_nBoundColumnType( DataType::SQLNULL )
172     {
173         DBG_CTOR(OListBoxModel,NULL);
174 
175         m_nClassId = FormComponentType::LISTBOX;
176         m_eListSourceType = ListSourceType_VALUELIST;
177         m_aBoundColumn <<= (sal_Int16)1;
178         initValueProperty( PROPERTY_SELECT_SEQ, PROPERTY_ID_SELECT_SEQ);
179 
180         startAggregatePropertyListening( PROPERTY_STRINGITEMLIST );
181     }
182 
183     //------------------------------------------------------------------
184     OListBoxModel::OListBoxModel( const OListBoxModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory )
185         :OBoundControlModel( _pOriginal, _rxFactory )
186         ,OEntryListHelper( *_pOriginal, (OControlModel&)*this )
187         ,OErrorBroadcaster( OComponentHelper::rBHelper )
188         ,m_aListRowSet( getContext() )
189         ,m_eListSourceType( _pOriginal->m_eListSourceType )
190         ,m_aBoundColumn( _pOriginal->m_aBoundColumn )
191         ,m_aListSourceValues( _pOriginal->m_aListSourceValues )
192         ,m_aBoundValues( _pOriginal->m_aBoundValues )
193         ,m_aDefaultSelectSeq( _pOriginal->m_aDefaultSelectSeq )
194         ,m_nNULLPos(-1)
195         ,m_nBoundColumnType( DataType::SQLNULL )
196     {
197         DBG_CTOR(OListBoxModel,NULL);
198 
199         startAggregatePropertyListening( PROPERTY_STRINGITEMLIST );
200     }
201 
202     //------------------------------------------------------------------
203     OListBoxModel::~OListBoxModel()
204     {
205         if (!OComponentHelper::rBHelper.bDisposed)
206         {
207             acquire();
208             dispose();
209         }
210 
211         DBG_DTOR(OListBoxModel,NULL);
212     }
213 
214     // XCloneable
215     //------------------------------------------------------------------------------
216     IMPLEMENT_DEFAULT_CLONING( OListBoxModel )
217 
218     // XServiceInfo
219     //------------------------------------------------------------------------------
220     StringSequence SAL_CALL OListBoxModel::getSupportedServiceNames() throw(RuntimeException)
221     {
222         StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();
223 
224         sal_Int32 nOldLen = aSupported.getLength();
225 	    aSupported.realloc( nOldLen + 8 );
226 	    ::rtl::OUString* pStoreTo = aSupported.getArray() + nOldLen;
227 
228         *pStoreTo++ = BINDABLE_CONTROL_MODEL;
229         *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
230         *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;
231 
232         *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL;
233         *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL;
234 
235         *pStoreTo++ = FRM_SUN_COMPONENT_LISTBOX;
236         *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_LISTBOX;
237         *pStoreTo++ = BINDABLE_DATABASE_LIST_BOX;
238 
239         return aSupported;
240     }
241 
242     //------------------------------------------------------------------------------
243     Any SAL_CALL OListBoxModel::queryAggregation(const Type& _rType) throw (RuntimeException)
244     {
245         Any aReturn = OBoundControlModel::queryAggregation( _rType );
246         if ( !aReturn.hasValue() )
247             aReturn = OEntryListHelper::queryInterface( _rType );
248         if ( !aReturn.hasValue() )
249             aReturn = OErrorBroadcaster::queryInterface( _rType );
250         return aReturn;
251     }
252 
253     // OComponentHelper
254     //------------------------------------------------------------------------------
255     void OListBoxModel::disposing()
256     {
257         OBoundControlModel::disposing();
258         OEntryListHelper::disposing();
259         OErrorBroadcaster::disposing();
260     }
261 
262     //------------------------------------------------------------------------------
263     void OListBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
264     {
265         switch (_nHandle)
266         {
267         case PROPERTY_ID_BOUNDCOLUMN:
268             _rValue <<= m_aBoundColumn;
269             break;
270 
271         case PROPERTY_ID_LISTSOURCETYPE:
272             _rValue <<= m_eListSourceType;
273             break;
274 
275         case PROPERTY_ID_LISTSOURCE:
276             _rValue <<= lcl_convertToStringSequence( m_aListSourceValues );
277             break;
278 
279         case PROPERTY_ID_VALUE_SEQ:
280             _rValue <<= lcl_convertToStringSequence( m_aBoundValues );
281             break;
282 
283         case PROPERTY_ID_DEFAULT_SELECT_SEQ:
284             _rValue <<= m_aDefaultSelectSeq;
285             break;
286 
287         case PROPERTY_ID_STRINGITEMLIST:
288             _rValue <<= getStringItemList();
289             break;
290 
291         default:
292             OBoundControlModel::getFastPropertyValue(_rValue, _nHandle);
293         }
294     }
295 
296     //------------------------------------------------------------------------------
297     void OListBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) throw (com::sun::star::uno::Exception)
298     {
299         switch (_nHandle)
300         {
301         case PROPERTY_ID_BOUNDCOLUMN :
302             DBG_ASSERT((_rValue.getValueType().getTypeClass() == TypeClass_SHORT) || (_rValue.getValueType().getTypeClass() == TypeClass_VOID),
303                 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
304             m_aBoundColumn = _rValue;
305             break;
306 
307         case PROPERTY_ID_LISTSOURCETYPE :
308             DBG_ASSERT(_rValue.getValueType().equals(::getCppuType(reinterpret_cast<ListSourceType*>(NULL))),
309                 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
310             _rValue >>= m_eListSourceType;
311             break;
312 
313         case PROPERTY_ID_LISTSOURCE:
314         {
315             // extract
316             Sequence< ::rtl::OUString > aListSource;
317             OSL_VERIFY( _rValue >>= aListSource );
318 
319             // copy to member
320             ValueList().swap(m_aListSourceValues);
321             ::std::copy(
322                 aListSource.getConstArray(),
323                 aListSource.getConstArray() + aListSource.getLength(),
324                 ::std::insert_iterator< ValueList >( m_aListSourceValues, m_aListSourceValues.end() )
325             );
326 
327             // propagate
328             if ( m_eListSourceType == ListSourceType_VALUELIST )
329             {
330                 m_aBoundValues = m_aListSourceValues;
331             }
332             else
333             {
334                 if ( m_xCursor.is() && !hasField() && !hasExternalListSource() )
335                     // listbox is already connected to a database, and no external list source
336                     // data source changed -> refresh
337                     loadData( false );
338             }
339         }
340         break;
341 
342         case PROPERTY_ID_VALUE_SEQ :
343             OSL_ENSURE( false, "ValueItemList is read-only!" );
344             throw PropertyVetoException();
345 
346         case PROPERTY_ID_DEFAULT_SELECT_SEQ :
347             DBG_ASSERT(_rValue.getValueType().equals(::getCppuType(reinterpret_cast< Sequence<sal_Int16>*>(NULL))),
348                 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
349             _rValue >>= m_aDefaultSelectSeq;
350 
351             DBG_ASSERT(m_xAggregateFastSet.is(), "OListBoxModel::setFastPropertyValue_NoBroadcast(DEFAULT_SELECT_SEQ) : invalid aggregate !");
352             if ( m_xAggregateFastSet.is() )
353                 setControlValue( _rValue, eOther );
354             break;
355 
356         case PROPERTY_ID_STRINGITEMLIST:
357         {
358 			ControlModelLock aLock( *this );
359             setNewStringItemList( _rValue, aLock );
360                 // TODO: this is bogus. setNewStringItemList expects a guard which has the *only*
361                 // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
362                 // a lock - so we effectively has two locks here, of which setNewStringItemList can
363                 // only control one.
364         }
365         resetNoBroadcast();
366         break;
367 
368         default:
369             OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
370         }
371     }
372 
373     //------------------------------------------------------------------------------
374     sal_Bool OListBoxModel::convertFastPropertyValue(
375         Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
376         throw (IllegalArgumentException)
377     {
378         sal_Bool bModified(sal_False);
379         switch (_nHandle)
380         {
381         case PROPERTY_ID_BOUNDCOLUMN :
382             bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aBoundColumn, ::getCppuType(reinterpret_cast<sal_Int16*>(NULL)));
383             break;
384 
385         case PROPERTY_ID_LISTSOURCETYPE:
386             bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType);
387             break;
388 
389         case PROPERTY_ID_LISTSOURCE:
390             bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, lcl_convertToStringSequence( m_aListSourceValues ) );
391             break;
392 
393         case PROPERTY_ID_VALUE_SEQ :
394             OSL_ENSURE( false, "ValueItemList is read-only!" );
395             throw PropertyVetoException();
396 
397         case PROPERTY_ID_DEFAULT_SELECT_SEQ :
398             bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultSelectSeq);
399             break;
400 
401         case PROPERTY_ID_STRINGITEMLIST:
402             bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue );
403             break;
404 
405         default:
406             return OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
407         }
408         return bModified;
409     }
410 
411     //------------------------------------------------------------------------------
412     void SAL_CALL OListBoxModel::setPropertyValues( const Sequence< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues ) throw(PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
413     {
414         // if both SelectedItems and StringItemList are set, care for this
415         // #i27024# / 2004-04-05 / fs@openoffice.org
416         const Any* pSelectSequenceValue = NULL;
417 
418         const ::rtl::OUString* pStartPos = _rPropertyNames.getConstArray();
419         const ::rtl::OUString* pEndPos   = _rPropertyNames.getConstArray() + _rPropertyNames.getLength();
420         const ::rtl::OUString* pSelectedItemsPos = ::std::find_if(
421             pStartPos, pEndPos,
422              ::std::bind2nd( ::std::equal_to< ::rtl::OUString >(), PROPERTY_SELECT_SEQ )
423         );
424         const ::rtl::OUString* pStringItemListPos = ::std::find_if(
425             pStartPos, pEndPos,
426              ::std::bind2nd( ::std::equal_to< ::rtl::OUString >(), PROPERTY_STRINGITEMLIST )
427         );
428         if ( ( pSelectedItemsPos != pEndPos ) && ( pStringItemListPos != pEndPos ) )
429         {
430             // both properties are present
431             // -> remember the value for the select sequence
432             pSelectSequenceValue = _rValues.getConstArray() + ( pSelectedItemsPos - pStartPos );
433         }
434 
435         OBoundControlModel::setPropertyValues( _rPropertyNames, _rValues );
436 
437         if ( pSelectSequenceValue )
438         {
439             setPropertyValue( PROPERTY_SELECT_SEQ, *pSelectSequenceValue );
440             // Note that this is the only reliable way, since one of the properties is implemented
441             // by ourself, and one is implemented by the aggregate, we cannot rely on any particular
442             // results when setting them both - too many undocumented behavior in all the involved
443             // classes
444         }
445     }
446 
447     //------------------------------------------------------------------------------
448     void OListBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const
449     {
450         BEGIN_DESCRIBE_PROPERTIES( 7, OBoundControlModel )
451             DECL_PROP1(TABINDEX,            sal_Int16,                      BOUND);
452             DECL_PROP2(BOUNDCOLUMN,         sal_Int16,                      BOUND, MAYBEVOID);
453             DECL_PROP1(LISTSOURCETYPE,      ListSourceType,                 BOUND);
454             DECL_PROP1(LISTSOURCE,          StringSequence,                 BOUND);
455             DECL_PROP3(VALUE_SEQ,           StringSequence,                 BOUND, READONLY, TRANSIENT);
456             DECL_PROP1(DEFAULT_SELECT_SEQ,  Sequence<sal_Int16>,            BOUND);
457             DECL_PROP1(STRINGITEMLIST,      Sequence< ::rtl::OUString >,    BOUND);
458         END_DESCRIBE_PROPERTIES();
459     }
460 
461     //------------------------------------------------------------------------------
462     void OListBoxModel::_propertyChanged( const PropertyChangeEvent& i_rEvent ) throw ( RuntimeException )
463     {
464         if ( i_rEvent.PropertyName == PROPERTY_STRINGITEMLIST )
465         {
466             ControlModelLock aLock( *this );
467             // SYNCHRONIZED ----->
468             // our aggregate internally changed its StringItemList property - reflect this in our "overridden"
469             // version of the property
470             setNewStringItemList( i_rEvent.NewValue, aLock );
471             // <----- SYNCHRONIZED
472             return;
473         }
474         OBoundControlModel::_propertyChanged( i_rEvent );
475     }
476 
477     //------------------------------------------------------------------------------
478     void OListBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const
479     {
480         OBoundControlModel::describeAggregateProperties( _rAggregateProps );
481 
482         // superseded properties:
483         RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST );
484     }
485 
486     //------------------------------------------------------------------------------
487     ::rtl::OUString SAL_CALL OListBoxModel::getServiceName() throw(RuntimeException)
488     {
489         return FRM_COMPONENT_LISTBOX;   // old (non-sun) name for compatibility !
490     }
491 
492     //------------------------------------------------------------------------------
493     void SAL_CALL OListBoxModel::write(const Reference<XObjectOutputStream>& _rxOutStream)
494         throw(IOException, RuntimeException)
495     {
496         OBoundControlModel::write(_rxOutStream);
497 
498         // Dummy-Seq, um Kompatible zu bleiben, wenn SelectSeq nicht mehr gespeichert wird
499         Sequence<sal_Int16> aDummySeq;
500 
501         // Version
502         // Version 0x0002: ListSource wird StringSeq
503         _rxOutStream->writeShort(0x0004);
504 
505         // Maskierung fuer any
506         sal_uInt16 nAnyMask = 0;
507         if (m_aBoundColumn.getValueType().getTypeClass() != TypeClass_VOID)
508             nAnyMask |= BOUNDCOLUMN;
509 
510         _rxOutStream << nAnyMask;
511 
512         _rxOutStream << lcl_convertToStringSequence( m_aListSourceValues );
513         _rxOutStream << (sal_Int16)m_eListSourceType;
514         _rxOutStream << aDummySeq;
515         _rxOutStream << m_aDefaultSelectSeq;
516 
517         if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
518         {
519             sal_Int16 nBoundColumn = 0;
520             m_aBoundColumn >>= nBoundColumn;
521             _rxOutStream << nBoundColumn;
522         }
523         writeHelpTextCompatibly(_rxOutStream);
524 
525         // from version 0x0004 : common properties
526         writeCommonProperties(_rxOutStream);
527     }
528 
529     //------------------------------------------------------------------------------
530     void SAL_CALL OListBoxModel::read(const Reference<XObjectInputStream>& _rxInStream) throw(IOException, RuntimeException)
531     {
532         // Bei manchen Variblen muessen Abhaengigkeiten beruecksichtigt werden.
533         // Deshalb muessen sie explizit ueber setPropertyValue() gesetzt werden.
534 
535         OBoundControlModel::read(_rxInStream);
536         ControlModelLock aLock( *this );
537 
538         // since we are "overwriting" the StringItemList of our aggregate (means we have
539         // an own place to store the value, instead of relying on our aggregate storing it),
540         // we need to respect what the aggregate just read for the StringItemList property.
541         try
542         {
543             if ( m_xAggregateSet.is() )
544                 setNewStringItemList( m_xAggregateSet->getPropertyValue( PROPERTY_STRINGITEMLIST ), aLock );
545         }
546         catch( const Exception& )
547         {
548     	    OSL_ENSURE( sal_False, "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" );
549         }
550 
551         // Version
552         sal_uInt16 nVersion = _rxInStream->readShort();
553         DBG_ASSERT(nVersion > 0, "OListBoxModel::read : version 0 ? this should never have been written !");
554 
555         if (nVersion > 0x0004)
556         {
557             DBG_ERROR("OListBoxModel::read : invalid (means unknown) version !");
558             ValueList().swap(m_aListSourceValues);
559             m_aBoundColumn <<= (sal_Int16)0;
560             ValueList().swap(m_aBoundValues);
561             m_eListSourceType = ListSourceType_VALUELIST;
562             m_aDefaultSelectSeq.realloc(0);
563             defaultCommonProperties();
564             return;
565         }
566 
567         // Maskierung fuer any
568         sal_uInt16 nAnyMask;
569         _rxInStream >> nAnyMask;
570 
571         // ListSourceSeq
572         StringSequence aListSourceSeq;
573         if (nVersion == 0x0001)
574         {
575             // ListSourceSeq aus String zusammenstellen;
576             ::rtl::OUString sListSource;
577             _rxInStream >> sListSource;
578 
579             sal_Int32 nTokens = 1;
580             const sal_Unicode* pStr = sListSource.getStr();
581             while ( *pStr )
582             {
583                 if ( *pStr == ';' )
584                     nTokens++;
585                 pStr++;
586             }
587             aListSourceSeq.realloc( nTokens );
588             for (sal_uInt16 i=0; i<nTokens; ++i)
589             {
590                 sal_Int32 nTmp = 0;
591                 aListSourceSeq.getArray()[i] = sListSource.getToken(i,';',nTmp);
592             }
593         }
594         else
595             _rxInStream >> aListSourceSeq;
596 
597         sal_Int16 nListSourceType;
598         _rxInStream >> nListSourceType;
599         m_eListSourceType = (ListSourceType)nListSourceType;
600         Any aListSourceSeqAny;
601         aListSourceSeqAny <<= aListSourceSeq;
602 
603         setFastPropertyValue(PROPERTY_ID_LISTSOURCE, aListSourceSeqAny );
604 
605         // Dummy-Seq, um Kompatible zu bleiben, wenn SelectSeq nicht mehr gespeichert wird
606         Sequence<sal_Int16> aDummySeq;
607         _rxInStream >> aDummySeq;
608 
609         // DefaultSelectSeq
610         Sequence<sal_Int16> aDefaultSelectSeq;
611         _rxInStream >> aDefaultSelectSeq;
612         Any aDefaultSelectSeqAny;
613         aDefaultSelectSeqAny <<= aDefaultSelectSeq;
614         setFastPropertyValue(PROPERTY_ID_DEFAULT_SELECT_SEQ, aDefaultSelectSeqAny);
615 
616         // BoundColumn
617         if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
618         {
619             sal_Int16 nValue;
620             _rxInStream >> nValue;
621             m_aBoundColumn <<= nValue;
622         }
623 
624         if (nVersion > 2)
625             readHelpTextCompatibly(_rxInStream);
626 
627         // if our string list is not filled from the value list, we must empty it
628         // this can be the case when somebody saves in alive mode
629         if  (   ( m_eListSourceType != ListSourceType_VALUELIST )
630             &&  !hasExternalListSource()
631             )
632         {
633             setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) );
634         }
635 
636         if (nVersion > 3)
637             readCommonProperties(_rxInStream);
638 
639         // Nach dem Lesen die Defaultwerte anzeigen
640         if ( getControlSource().getLength() )
641             // (not if we don't have a control source - the "State" property acts like it is persistent, then
642             resetNoBroadcast();
643     }
644 
645     //------------------------------------------------------------------------------
646     void OListBoxModel::loadData( bool _bForce )
647     {
648         RTL_LOGFILE_CONTEXT( aLogContext, "OListBoxModel::loadData" );
649         DBG_ASSERT( m_eListSourceType != ListSourceType_VALUELIST, "OListBoxModel::loadData: cannot load value list from DB!" );
650         DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::loadData: cannot load from DB when I have an external list source!" );
651 
652         const sal_Int16 nNULLPosBackup( m_nNULLPos );
653         const sal_Int32 nBoundColumnTypeBackup( m_nBoundColumnType );
654         m_nNULLPos = -1;
655         m_nBoundColumnType = DataType::SQLNULL;
656 
657         // pre-requisites:
658         // PRE1: connection
659         Reference< XConnection > xConnection;
660         // is the active connection of our form
661         Reference< XPropertySet > xFormProps( m_xCursor, UNO_QUERY );
662         if ( xFormProps.is() )
663             xFormProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
664 
665         // PRE2: list source
666         ::rtl::OUString sListSource;
667         // if our list source type is no value list, we need to concatenate
668         // the single list source elements
669         ::std::for_each(
670             m_aListSourceValues.begin(),
671             m_aListSourceValues.end(),
672             AppendRowSetValueString( sListSource )
673         );
674 
675         // outta here if we don't have all pre-requisites
676         if ( !xConnection.is() || !sListSource.getLength() )
677         {
678             ValueList().swap(m_aBoundValues);
679             return;
680         }
681 
682         ::boost::optional< sal_Int16 > aBoundColumn;
683         if ( m_aBoundColumn.getValueType().getTypeClass() == TypeClass_SHORT )
684         {
685             sal_Int16 nBoundColumn( 0 );
686             m_aBoundColumn >>= nBoundColumn;
687             aBoundColumn.reset( nBoundColumn );
688         }
689 
690         ::utl::SharedUNOComponent< XResultSet > xListCursor;
691         try
692         {
693             m_aListRowSet.setConnection( xConnection );
694 
695             sal_Bool bExecute = sal_False;
696             switch (m_eListSourceType)
697             {
698             case ListSourceType_TABLEFIELDS:
699                 // don't work with a statement here, the fields will be collected below
700                 break;
701 
702             case ListSourceType_TABLE:
703                 {
704                     Reference<XNameAccess> xFieldsByName = getTableFields(xConnection, sListSource);
705                     Reference<XIndexAccess> xFieldsByIndex(xFieldsByName, UNO_QUERY);
706 
707                     // do we have a bound column if yes we have to select it
708                     // and the displayed column is the first column othwhise we act as a combobox
709                     ::rtl::OUString aFieldName;
710                     ::rtl::OUString aBoundFieldName;
711 
712                     if ( !!aBoundColumn && ( *aBoundColumn >= 0 ) && xFieldsByIndex.is() )
713                     {
714                         if ( *aBoundColumn >= xFieldsByIndex->getCount() )
715                             break;
716 
717 						Reference<XPropertySet> xFieldAsSet(xFieldsByIndex->getByIndex( *aBoundColumn ),UNO_QUERY);
718                         xFieldAsSet->getPropertyValue(PROPERTY_NAME) >>= aBoundFieldName;
719                         aBoundColumn.reset( 1 );
720 
721 						xFieldAsSet.set(xFieldsByIndex->getByIndex(0),UNO_QUERY);
722                         xFieldAsSet->getPropertyValue(PROPERTY_NAME) >>= aFieldName;
723                     }
724                     else if (xFieldsByName.is())
725                     {
726                         if ( xFieldsByName->hasByName( getControlSource() ) )
727                             aFieldName = getControlSource();
728                         else
729                         {
730                             // otherwise look for the alias
731                             Reference< XColumnsSupplier > xSupplyFields;
732                             xFormProps->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SingleSelectQueryComposer"))) >>= xSupplyFields;
733 
734                             // search the field
735                             DBG_ASSERT(xSupplyFields.is(), "OListBoxModel::loadData : invalid query composer !");
736 
737                             Reference<XNameAccess> xFieldNames = xSupplyFields->getColumns();
738                             if ( xFieldNames->hasByName( getControlSource() ) )
739                             {
740                                 Reference<XPropertySet> xComposerFieldAsSet;
741                                 xFieldNames->getByName( getControlSource() ) >>= xComposerFieldAsSet;
742                                 if (hasProperty(PROPERTY_FIELDSOURCE, xComposerFieldAsSet))
743                                     xComposerFieldAsSet->getPropertyValue(PROPERTY_FIELDSOURCE) >>= aFieldName;
744                             }
745                         }
746                     }
747                     if (!aFieldName.getLength())
748                         break;
749 
750                     Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
751                     ::rtl::OUString aQuote = xMeta->getIdentifierQuoteString();
752                     ::rtl::OUString aStatement = ::rtl::OUString::createFromAscii("SELECT ");
753                     if (!aBoundFieldName.getLength())   // act like a combobox
754                         aStatement += ::rtl::OUString::createFromAscii("DISTINCT ");
755 
756                     aStatement += quoteName(aQuote,aFieldName);
757                     if (aBoundFieldName.getLength())
758                     {
759                         aStatement += ::rtl::OUString::createFromAscii(", ");
760                         aStatement += quoteName(aQuote, aBoundFieldName);
761                     }
762                     aStatement += ::rtl::OUString::createFromAscii(" FROM ");
763 
764                     ::rtl::OUString sCatalog, sSchema, sTable;
765 	                qualifiedNameComponents( xMeta, sListSource, sCatalog, sSchema, sTable, eInDataManipulation );
766                     aStatement += composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable );
767 
768                     m_aListRowSet.setEscapeProcessing( sal_False );
769                     m_aListRowSet.setCommand( aStatement );
770                     bExecute = sal_True;
771                 }
772                 break;
773 
774             case ListSourceType_QUERY:
775                 m_aListRowSet.setCommandFromQuery( sListSource );
776                 bExecute = sal_True;
777                 break;
778 
779             default:
780                 m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType );
781                 m_aListRowSet.setCommand( sListSource );
782                 bExecute = sal_True;
783                 break;
784             }
785 
786             if (bExecute)
787             {
788                 if ( !_bForce && !m_aListRowSet.isDirty() )
789                 {
790                     // if none of the settings of the row set changed, compared to the last
791                     // invocation of loadData, then don't re-fill the list. Instead, assume
792                     // the list entries are the same.
793                     m_nNULLPos = nNULLPosBackup;
794                     m_nBoundColumnType = nBoundColumnTypeBackup;
795                     return;
796                 }
797                 xListCursor.reset( m_aListRowSet.execute() );
798             }
799         }
800         catch(SQLException& eSQL)
801         {
802             onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
803             return;
804         }
805         catch(const Exception& eUnknown)
806         {
807             (void)eUnknown;
808             return;
809         }
810 
811         // Anzeige- und Werteliste fuellen
812         ValueList aDisplayList, aValueList;
813         sal_Bool bUseNULL = hasField() && !isRequired();
814 
815         try
816         {
817             OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ),
818                 "OListBoxModel::loadData: logic error!" );
819             if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) )
820                 return;
821 
822             switch (m_eListSourceType)
823             {
824             case ListSourceType_SQL:
825             case ListSourceType_SQLPASSTHROUGH:
826             case ListSourceType_TABLE:
827             case ListSourceType_QUERY:
828                 {
829                     // Feld der 1. Column des ResultSets holen
830                     Reference<XColumnsSupplier> xSupplyCols(xListCursor, UNO_QUERY);
831                     DBG_ASSERT(xSupplyCols.is(), "OListBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
832                     Reference<XIndexAccess> xColumns;
833                     if (xSupplyCols.is())
834                     {
835                         xColumns = Reference<XIndexAccess>(xSupplyCols->getColumns(), UNO_QUERY);
836                         DBG_ASSERT(xColumns.is(), "OListBoxModel::loadData : no columns supplied by the row set !");
837                     }
838 
839                     Reference< XPropertySet > xDataField;
840                     if ( xColumns.is() )
841                         xColumns->getByIndex(0) >>= xDataField;
842                     if ( !xDataField.is() )
843                         return;
844 
845                     ::dbtools::FormattedColumnValue aValueFormatter( getContext(), m_xCursor, xDataField );
846 
847                     // Feld der BoundColumn des ResultSets holen
848                     m_nBoundColumnType = DataType::SQLNULL;
849                     if ( !!aBoundColumn && ( *aBoundColumn >= 0 ) && m_xColumn.is() )
850                     {   // don't look for a bound column if we're not connected to a field
851                         try
852                         {
853                             Reference< XPropertySet > xBoundField( xColumns->getByIndex( *aBoundColumn ), UNO_QUERY_THROW );
854                             OSL_VERIFY( xBoundField->getPropertyValue( ::rtl::OUString::createFromAscii( "Type" ) ) >>= m_nBoundColumnType );
855                         }
856                         catch( const Exception& )
857                         {
858                             DBG_UNHANDLED_EXCEPTION();
859                         }
860                     }
861 
862                     //  Ist die LB an ein Feld gebunden und sind Leereintraege zulaessig
863                     //  dann wird die Position fuer einen Leereintrag gemerkt
864 
865                     RTL_LOGFILE_CONTEXT( aLogContext, "OListBoxModel::loadData: string collection" );
866                     ::rtl::OUString aStr;
867                     sal_Int16 entryPos = 0;
868                     ORowSetValue aBoundValue;
869                     Reference< XRow > xCursorRow( xListCursor, UNO_QUERY_THROW );
870                     while ( xListCursor->next() && ( entryPos++ < SHRT_MAX ) ) // SHRT_MAX is the maximum number of entries
871                     {
872                         aStr = aValueFormatter.getFormattedValue();
873                         aDisplayList.push_back( aStr );
874 
875                         if ( impl_hasBoundComponent() )
876                         {
877                             aBoundValue.fill( *aBoundColumn + 1, m_nBoundColumnType, xCursorRow );
878                             aValueList.push_back( aBoundValue );
879                         }
880 
881                         if ( bUseNULL && ( m_nNULLPos == -1 ) && !aStr.getLength() )
882                             m_nNULLPos = sal_Int16( aDisplayList.size() - 1 );
883                     }
884                 }
885                 break;
886 
887             case ListSourceType_TABLEFIELDS:
888                 {
889                     Reference<XNameAccess> xFieldNames = getTableFields(xConnection, sListSource);
890                     if (xFieldNames.is())
891                     {
892                         StringSequence seqNames = xFieldNames->getElementNames();
893                         ::std::copy(
894                             seqNames.getConstArray(),
895                             seqNames.getConstArray() + seqNames.getLength(),
896                             ::std::insert_iterator< ValueList >( aDisplayList, aDisplayList.end() )
897                         );
898                     }
899                 }
900                 break;
901                 default:
902                     OSL_ENSURE( false, "OListBoxModel::loadData: unreachable!" );
903                     break;
904             }
905         }
906         catch(SQLException& eSQL)
907         {
908             onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
909             return;
910         }
911         catch( const Exception& )
912         {
913             DBG_UNHANDLED_EXCEPTION();
914             return;
915         }
916 
917 
918         // Value-Sequence erzeugen
919         // NULL eintrag hinzufuegen
920         if (bUseNULL && m_nNULLPos == -1)
921         {
922             if ( impl_hasBoundComponent() )
923                 aValueList.insert( aValueList.begin(), ORowSetValue() );
924 
925             aDisplayList.insert( aDisplayList.begin(), ORowSetValue( ::rtl::OUString() ) );
926             m_nNULLPos = 0;
927         }
928 
929         m_aBoundValues = aValueList;
930 
931         setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( lcl_convertToStringSequence( aDisplayList ) ) );
932     }
933 
934     //------------------------------------------------------------------------------
935     void OListBoxModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ )
936     {
937         // list boxes which are bound to a db column don't have multi selection
938         // - this would be unable to reflect in the db column
939         if ( hasField() )
940         {
941             setFastPropertyValue( PROPERTY_ID_MULTISELECTION, ::cppu::bool2any( ( sal_False ) ) );
942         }
943 
944         if ( !hasExternalListSource() )
945             impl_refreshDbEntryList( false );
946     }
947 
948     //------------------------------------------------------------------------------
949     void OListBoxModel::onDisconnectedDbColumn()
950     {
951         if ( m_eListSourceType != ListSourceType_VALUELIST )
952         {
953             ValueList().swap(m_aBoundValues);
954             m_nNULLPos = -1;
955             m_nBoundColumnType = DataType::SQLNULL;
956 
957             if ( !hasExternalListSource() )
958                 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) );
959 
960             m_aListRowSet.dispose();
961         }
962     }
963 
964     //------------------------------------------------------------------------------
965     ValueList OListBoxModel::impl_getValues() const
966     {
967         if ( !m_aBoundValues.empty() )
968             return m_aBoundValues;
969 
970         Sequence< ::rtl::OUString > aStringItems( getStringItemList() );
971         ValueList aValues( aStringItems.getLength() );
972         ::std::copy(
973             aStringItems.getConstArray(),
974             aStringItems.getConstArray() + aStringItems.getLength(),
975             aValues.begin()
976         );
977 
978         return aValues;
979     }
980     //------------------------------------------------------------------------------
981     ORowSetValue OListBoxModel::getFirstSelectedValue() const
982     {
983         static const ORowSetValue s_aEmptyVaue;
984 
985         DBG_ASSERT( m_xAggregateFastSet.is(), "OListBoxModel::getFirstSelectedValue: invalid aggregate!" );
986         if ( !m_xAggregateFastSet.is() )
987             return s_aEmptyVaue;
988 
989         Sequence< sal_Int16 > aSelectedIndices;
990         OSL_VERIFY( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) >>= aSelectedIndices );
991         if ( !aSelectedIndices.getLength() )
992             // nothing selected at all
993             return s_aEmptyVaue;
994 
995         if ( ( m_nNULLPos != -1 ) && ( aSelectedIndices[0] == m_nNULLPos ) )
996             // the dedicated "NULL" entry is selected
997             return s_aEmptyVaue;
998 
999         ValueList aValues( impl_getValues() );
1000 
1001         size_t selectedValue = aSelectedIndices[0];
1002         if ( selectedValue >= aValues.size() )
1003         {
1004             OSL_ENSURE( false, "OListBoxModel::getFirstSelectedValue: inconsistent selection/valuelist!" );
1005             return s_aEmptyVaue;
1006         }
1007 
1008         return aValues[ selectedValue ];
1009     }
1010 
1011     //------------------------------------------------------------------------------
1012     sal_Bool OListBoxModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
1013     {
1014         // current selektion list
1015         const ORowSetValue aCurrentValue( getFirstSelectedValue() );
1016         if ( aCurrentValue != m_aSaveValue )
1017         {
1018             if ( aCurrentValue.isNull() )
1019                 m_xColumnUpdate->updateNull();
1020             else
1021             {
1022                 try
1023                 {
1024                     m_xColumnUpdate->updateObject( aCurrentValue.makeAny() );
1025                 }
1026                 catch ( const Exception& )
1027                 {
1028                     return sal_False;
1029                 }
1030             }
1031             m_aSaveValue = aCurrentValue;
1032         }
1033         return sal_True;
1034     }
1035 
1036     // XPropertiesChangeListener
1037     //------------------------------------------------------------------------------
1038     Any OListBoxModel::translateDbColumnToControlValue()
1039     {
1040         Reference< XPropertySet > xBoundField( getField() );
1041         if ( !xBoundField.is() )
1042         {
1043             OSL_ENSURE( false, "OListBoxModel::translateDbColumnToControlValue: no field? How could that happen?!" );
1044             return Any();
1045         }
1046 
1047         Sequence< sal_Int16 > aSelectionIndicies;
1048 
1049         ORowSetValue aCurrentValue;
1050         aCurrentValue.fill( impl_hasBoundComponent() ? m_nBoundColumnType : getFieldType(), m_xColumn );
1051 
1052         // reset selection for NULL values
1053         if ( aCurrentValue.isNull() )
1054         {
1055             if ( m_nNULLPos != -1 )
1056             {
1057                 aSelectionIndicies.realloc(1);
1058                 aSelectionIndicies[0] = m_nNULLPos;
1059             }
1060         }
1061         else
1062         {
1063             ValueList aValues( impl_getValues() );
1064             ValueList::const_iterator curValuePos = ::std::find( aValues.begin(), aValues.end(), aCurrentValue );
1065             if ( curValuePos != aValues.end() )
1066             {
1067                 aSelectionIndicies.realloc( 1 );
1068                 aSelectionIndicies[0] = curValuePos - aValues.begin();
1069             }
1070         }
1071 
1072         m_aSaveValue = aCurrentValue;
1073 
1074         return makeAny( aSelectionIndicies );
1075     }
1076 
1077     // XReset
1078     //------------------------------------------------------------------------------
1079     Any OListBoxModel::getDefaultForReset() const
1080     {
1081         Any aValue;
1082         if (m_aDefaultSelectSeq.getLength())
1083             aValue <<= m_aDefaultSelectSeq;
1084         else if (m_nNULLPos != -1)  // gebundene Listbox
1085         {
1086             Sequence<sal_Int16> aSeq(1);
1087             aSeq.getArray()[0] = m_nNULLPos;
1088             aValue <<= aSeq;
1089         }
1090         else
1091         {
1092             Sequence<sal_Int16> aSeq;
1093             aValue <<= aSeq;
1094         }
1095 
1096         return aValue;
1097     }
1098 
1099     //--------------------------------------------------------------------
1100     void OListBoxModel::resetNoBroadcast()
1101     {
1102         OBoundControlModel::resetNoBroadcast();
1103         m_aSaveValue.setNull();
1104     }
1105 
1106     //--------------------------------------------------------------------
1107     void SAL_CALL OListBoxModel::disposing( const EventObject& _rSource ) throw ( RuntimeException )
1108     {
1109         if ( !OEntryListHelper::handleDisposing( _rSource ) )
1110             OBoundControlModel::disposing( _rSource );
1111     }
1112 
1113     //--------------------------------------------------------------------
1114     namespace
1115     {
1116         /** type how we should transfer our selection to external value bindings
1117         */
1118         enum ExchangeType
1119         {
1120             eIndexList,     /// as list of indexes of selected entries
1121             eIndex,         /// as index of the selected entry
1122             eEntryList,     /// as list of string representations of selected entries
1123             eEntry          /// as string representation of the selected entry
1124         };
1125 
1126         //--------------------------------------------------------------------
1127         ExchangeType lcl_getCurrentExchangeType( const Type& _rExchangeType )
1128         {
1129             switch ( _rExchangeType.getTypeClass() )
1130             {
1131             case TypeClass_STRING:
1132                 return eEntry;
1133             case TypeClass_LONG:
1134                 return eIndex;
1135             case TypeClass_SEQUENCE:
1136             {
1137                 Type aElementType = ::comphelper::getSequenceElementType( _rExchangeType );
1138                 switch ( aElementType.getTypeClass() )
1139                 {
1140                 case TypeClass_STRING:
1141                     return eEntryList;
1142                 case TypeClass_LONG:
1143                     return eIndexList;
1144                 default:
1145                     break;
1146                 }
1147             }
1148             default:
1149                 break;
1150             }
1151             OSL_ENSURE( false, "lcl_getCurrentExchangeType: unsupported (unexpected) exchange type!" );
1152             return eEntry;
1153         }
1154     }
1155 
1156     //--------------------------------------------------------------------
1157     Any OListBoxModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
1158     {
1159         Sequence< sal_Int16 > aSelectIndexes;
1160 
1161         switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1162         {
1163         case eIndexList:
1164         {
1165             // unfortunately, our select sequence is a sequence<short>, while the external binding
1166             // supplies sequence<int> only -> transform this
1167             Sequence< sal_Int32 > aSelectIndexesPure;
1168             OSL_VERIFY( _rExternalValue >>= aSelectIndexesPure );
1169             aSelectIndexes.realloc( aSelectIndexesPure.getLength() );
1170             ::std::copy(
1171                 aSelectIndexesPure.getConstArray(),
1172                 aSelectIndexesPure.getConstArray() + aSelectIndexesPure.getLength(),
1173                 aSelectIndexes.getArray()
1174             );
1175         }
1176         break;
1177 
1178         case eIndex:
1179         {
1180             sal_Int32 nSelectIndex = -1;
1181             OSL_VERIFY( _rExternalValue >>= nSelectIndex );
1182             if ( ( nSelectIndex >= 0 ) && ( nSelectIndex < getStringItemList().getLength() ) )
1183             {
1184                 aSelectIndexes.realloc( 1 );
1185                 aSelectIndexes[ 0 ] = static_cast< sal_Int16 >( nSelectIndex );
1186             }
1187         }
1188         break;
1189 
1190         case eEntryList:
1191         {
1192             // we can retrieve a string list from the binding for multiple selection
1193             Sequence< ::rtl::OUString > aSelectEntries;
1194             OSL_VERIFY( _rExternalValue >>= aSelectEntries );
1195 
1196             ::std::set< sal_Int16 > aSelectionSet;
1197 
1198             // find the selection entries in our item list
1199             const ::rtl::OUString* pSelectEntries = aSelectEntries.getArray();
1200             const ::rtl::OUString* pSelectEntriesEnd = pSelectEntries + aSelectEntries.getLength();
1201             while ( pSelectEntries != pSelectEntriesEnd )
1202             {
1203                 // the indexes where the current string appears in our string items
1204                 Sequence< sal_Int16 > aThisEntryIndexes;
1205                 aThisEntryIndexes = findValue( getStringItemList(), *pSelectEntries++, sal_False );
1206 
1207                 // insert all the indexes of this entry into our set
1208                 ::std::copy(
1209                     aThisEntryIndexes.getConstArray(),
1210                     aThisEntryIndexes.getConstArray() + aThisEntryIndexes.getLength(),
1211                     ::std::insert_iterator< ::std::set< sal_Int16 > >( aSelectionSet, aSelectionSet.begin() )
1212                 );
1213             }
1214 
1215             // copy the indexes to the sequence
1216             aSelectIndexes.realloc( aSelectionSet.size() );
1217             ::std::copy(
1218                 aSelectionSet.begin(),
1219                 aSelectionSet.end(),
1220                 aSelectIndexes.getArray()
1221             );
1222         }
1223         break;
1224 
1225         case eEntry:
1226         {
1227             ::rtl::OUString sStringToSelect;
1228             OSL_VERIFY( _rExternalValue >>= sStringToSelect );
1229 
1230             aSelectIndexes = findValue( getStringItemList(), sStringToSelect, sal_False );
1231         }
1232         break;
1233         }
1234 
1235         return makeAny( aSelectIndexes );
1236     }
1237 
1238     //--------------------------------------------------------------------
1239     namespace
1240     {
1241         //................................................................
1242         struct ExtractStringFromSequence_Safe : public ::std::unary_function< sal_Int16, ::rtl::OUString >
1243         {
1244         protected:
1245             const Sequence< ::rtl::OUString >&  m_rList;
1246 
1247         public:
1248             ExtractStringFromSequence_Safe( const Sequence< ::rtl::OUString >& _rList ) : m_rList( _rList ) { }
1249 
1250             ::rtl::OUString operator ()( sal_Int16 _nIndex )
1251             {
1252                 OSL_ENSURE( _nIndex < m_rList.getLength(), "ExtractStringFromSequence_Safe: inconsistence!" );
1253                 if ( _nIndex < m_rList.getLength() )
1254                     return m_rList[ _nIndex ];
1255                 return ::rtl::OUString();
1256             }
1257         };
1258 
1259         //................................................................
1260         Any lcl_getSingleSelectedEntry( const Sequence< sal_Int16 >& _rSelectSequence, const Sequence< ::rtl::OUString >& _rStringList )
1261         {
1262             Any aReturn;
1263 
1264             // by definition, multiple selected entries are transfered as NULL if the
1265             // binding does not support string lists
1266             if ( _rSelectSequence.getLength() <= 1 )
1267             {
1268                 ::rtl::OUString sSelectedEntry;
1269 
1270                 if ( _rSelectSequence.getLength() == 1 )
1271                     sSelectedEntry = ExtractStringFromSequence_Safe( _rStringList )( _rSelectSequence[0] );
1272 
1273                 aReturn <<= sSelectedEntry;
1274             }
1275 
1276             return aReturn;
1277         }
1278 
1279         //................................................................
1280         Any lcl_getMultiSelectedEntries( const Sequence< sal_Int16 >& _rSelectSequence, const Sequence< ::rtl::OUString >& _rStringList )
1281         {
1282             Sequence< ::rtl::OUString > aSelectedEntriesTexts( _rSelectSequence.getLength() );
1283             ::std::transform(
1284                 _rSelectSequence.getConstArray(),
1285                 _rSelectSequence.getConstArray() + _rSelectSequence.getLength(),
1286                 aSelectedEntriesTexts.getArray(),
1287                 ExtractStringFromSequence_Safe( _rStringList )
1288             );
1289             return makeAny( aSelectedEntriesTexts );
1290         }
1291     }
1292 
1293     //--------------------------------------------------------------------
1294     Any OListBoxModel::translateControlValueToExternalValue( ) const
1295     {
1296         OSL_PRECOND( hasExternalValueBinding(), "OListBoxModel::translateControlValueToExternalValue: no binding!" );
1297 
1298         Sequence< sal_Int16 > aSelectSequence;
1299         const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence;
1300 
1301         Any aReturn;
1302         switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1303         {
1304         case eIndexList:
1305         {
1306             // unfortunately, the select sequence is a sequence<short>, but our binding
1307             // expects int's
1308             Sequence< sal_Int32 > aTransformed( aSelectSequence.getLength() );
1309             ::std::copy(
1310                 aSelectSequence.getConstArray(),
1311                 aSelectSequence.getConstArray() + aSelectSequence.getLength(),
1312                 aTransformed.getArray()
1313             );
1314             aReturn <<= aTransformed;
1315         }
1316         break;
1317 
1318         case eIndex:
1319         if ( aSelectSequence.getLength() <= 1 )
1320         {
1321             sal_Int32 nIndex = -1;
1322 
1323             if ( aSelectSequence.getLength() == 1 )
1324                 nIndex = aSelectSequence[0];
1325 
1326             aReturn <<= nIndex;
1327         }
1328         break;
1329 
1330         case eEntryList:
1331             aReturn = lcl_getMultiSelectedEntries( aSelectSequence, getStringItemList() );
1332             break;
1333 
1334         case eEntry:
1335             aReturn = lcl_getSingleSelectedEntry( aSelectSequence, getStringItemList() );
1336             break;
1337         }
1338 
1339         return aReturn;
1340     }
1341 
1342     //--------------------------------------------------------------------
1343     Any OListBoxModel::getCurrentFormComponentValue() const
1344     {
1345         if ( hasValidator() )
1346             return OBoundControlModel::getCurrentFormComponentValue();
1347 
1348         Any aCurretnValue;
1349 
1350         try
1351         {
1352             Sequence< sal_Int16 > aSelectSequence;
1353             OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence );
1354 
1355             sal_Bool bMultiSelection( sal_False );
1356             OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection );
1357 
1358             if ( bMultiSelection )
1359                 aCurretnValue = lcl_getMultiSelectedEntries( aSelectSequence, getStringItemList() );
1360             else
1361                 aCurretnValue = lcl_getSingleSelectedEntry( aSelectSequence, getStringItemList() );
1362         }
1363         catch( const Exception& )
1364         {
1365         	DBG_UNHANDLED_EXCEPTION();
1366         }
1367 
1368         return aCurretnValue;
1369     }
1370 
1371     //--------------------------------------------------------------------
1372     Sequence< Type > OListBoxModel::getSupportedBindingTypes()
1373     {
1374         Sequence< Type > aTypes(4);
1375         aTypes[0] = ::getCppuType( static_cast< Sequence< sal_Int32 >* >( NULL ) );
1376         aTypes[1] = ::getCppuType( static_cast< sal_Int32* >( NULL ) );
1377         aTypes[2] = ::getCppuType( static_cast< Sequence< ::rtl::OUString >* >( NULL ) );
1378         aTypes[3] = ::getCppuType( static_cast< ::rtl::OUString* >( NULL ) );
1379         return aTypes;
1380     }
1381 
1382     //--------------------------------------------------------------------
1383     void OListBoxModel::stringItemListChanged( ControlModelLock& _rInstanceLock )
1384     {
1385         if ( !m_xAggregateSet.is() )
1386             return;
1387 
1388         suspendValueListening();
1389         try
1390         {
1391             m_xAggregateSet->setPropertyValue( PROPERTY_STRINGITEMLIST, makeAny( getStringItemList() ) );
1392         }
1393         catch( const Exception& )
1394         {
1395             DBG_UNHANDLED_EXCEPTION();
1396         }
1397         resumeValueListening();
1398 
1399         // update the selection here
1400         if ( hasExternalValueBinding( ) )
1401             transferExternalValueToControl( _rInstanceLock );
1402         else
1403         {
1404             if ( hasField() )
1405             {
1406                 // TODO: update the selection in case we're bound to a database column
1407             }
1408             else
1409             {
1410                 if ( m_aDefaultSelectSeq.getLength() )
1411                     setControlValue( makeAny( m_aDefaultSelectSeq ), eOther );
1412             }
1413         }
1414     }
1415 
1416     //--------------------------------------------------------------------
1417     void OListBoxModel::connectedExternalListSource( )
1418     {
1419         // TODO?
1420     }
1421 
1422     //--------------------------------------------------------------------
1423     void OListBoxModel::disconnectedExternalListSource( )
1424     {
1425         // TODO: in case we're part of an already loaded form, we should probably simulate
1426         // an onConnectedDbColumn, so our list get's filled with the data as indicated
1427         // by our SQL-binding related properties
1428     }
1429 
1430     //--------------------------------------------------------------------
1431     void OListBoxModel::impl_refreshDbEntryList( bool _bForce )
1432     {
1433         DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::impl_refreshDbEntryList: invalid call!" );
1434 
1435         if  (   !hasExternalListSource( )
1436             &&  ( m_eListSourceType != ListSourceType_VALUELIST )
1437             &&  ( m_xCursor.is() )
1438             )
1439         {
1440             loadData( _bForce );
1441         }
1442     }
1443 
1444     //--------------------------------------------------------------------
1445     void OListBoxModel::refreshInternalEntryList()
1446     {
1447         impl_refreshDbEntryList( true );
1448         if ( hasField() && m_xCursor.is() )
1449             initFromField( m_xCursor );
1450     }
1451 
1452     //==================================================================
1453     // OListBoxControl
1454     //==================================================================
1455 
1456     //------------------------------------------------------------------
1457     InterfaceRef SAL_CALL OListBoxControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) throw (RuntimeException)
1458     {
1459         return *(new OListBoxControl(_rxFactory));
1460     }
1461 
1462     //------------------------------------------------------------------------------
1463     Sequence< Type> OListBoxControl::_getTypes()
1464     {
1465         return TypeBag(
1466             OBoundControl::_getTypes(),
1467             OListBoxControl_BASE::getTypes()
1468         ).getTypes();
1469     }
1470 
1471     //------------------------------------------------------------------
1472     Any SAL_CALL OListBoxControl::queryAggregation(const Type& _rType) throw (RuntimeException)
1473     {
1474         Any aReturn = OListBoxControl_BASE::queryInterface( _rType );
1475 
1476         if  (   !aReturn.hasValue()
1477             ||  _rType.equals( XTypeProvider::static_type() )
1478             )
1479             aReturn = OBoundControl::queryAggregation( _rType );
1480 
1481         return aReturn;
1482     }
1483 
1484     DBG_NAME(OListBoxControl);
1485     //------------------------------------------------------------------------------
1486     OListBoxControl::OListBoxControl(const Reference<XMultiServiceFactory>& _rxFactory)
1487         :OBoundControl( _rxFactory, VCL_CONTROL_LISTBOX, sal_False )
1488         ,m_aChangeListeners( m_aMutex )
1489         ,m_aItemListeners( m_aMutex )
1490         ,m_pItemBroadcaster( NULL )
1491     {
1492         DBG_CTOR(OListBoxControl,NULL);
1493 
1494         increment(m_refCount);
1495         {
1496             // als FocusListener anmelden
1497             Reference<XWindow> xComp;
1498             if (query_aggregation(m_xAggregate, xComp))
1499                 xComp->addFocusListener(this);
1500 
1501             // als ItemListener anmelden
1502             if ( query_aggregation( m_xAggregate, m_xAggregateListBox ) )
1503                 m_xAggregateListBox->addItemListener(this);
1504         }
1505         // Refcount bei 2 fuer angemeldete Listener
1506         decrement(m_refCount);
1507 
1508         doSetDelegator();
1509 
1510         m_aChangeTimer.SetTimeout(500);
1511         m_aChangeTimer.SetTimeoutHdl(LINK(this,OListBoxControl,OnTimeout));
1512     }
1513 
1514     //------------------------------------------------------------------------------
1515     OListBoxControl::~OListBoxControl()
1516     {
1517         if (!OComponentHelper::rBHelper.bDisposed)
1518         {
1519             acquire();
1520             dispose();
1521         }
1522 
1523         doResetDelegator();
1524         m_xAggregateListBox.clear();
1525 
1526         DBG_DTOR(OListBoxControl,NULL);
1527     }
1528 
1529     //------------------------------------------------------------------------------
1530     StringSequence SAL_CALL OListBoxControl::getSupportedServiceNames() throw(RuntimeException)
1531     {
1532         StringSequence aSupported = OBoundControl::getSupportedServiceNames();
1533         aSupported.realloc(aSupported.getLength() + 1);
1534 
1535         ::rtl::OUString* pArray = aSupported.getArray();
1536         pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_LISTBOX;
1537         return aSupported;
1538     }
1539 
1540 
1541     // XFocusListener
1542     //------------------------------------------------------------------------------
1543     void SAL_CALL OListBoxControl::focusGained(const FocusEvent& /*_rEvent*/) throw(RuntimeException)
1544     {
1545         ::osl::MutexGuard aGuard(m_aMutex);
1546         if ( m_aChangeListeners.getLength() ) // only if there are listeners
1547         {
1548             Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1549             if (xSet.is())
1550             {
1551                 // memorize the current selection for posting the change event
1552                 m_aCurrentSelection = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1553             }
1554         }
1555     }
1556 
1557     //------------------------------------------------------------------------------
1558     void SAL_CALL OListBoxControl::focusLost(const FocusEvent& /*_rEvent*/) throw(RuntimeException)
1559     {
1560         m_aCurrentSelection.clear();
1561     }
1562 
1563     // XItemListener
1564     //------------------------------------------------------------------------------
1565     void SAL_CALL OListBoxControl::itemStateChanged(const ItemEvent& _rEvent) throw(RuntimeException)
1566     {
1567         // forward this to our listeners
1568         {
1569             ::osl::MutexGuard aGuard( m_aMutex );
1570             if ( m_aItemListeners.getLength() )
1571             {
1572                 if ( !m_pItemBroadcaster.is() )
1573                 {
1574                     m_pItemBroadcaster.set( new ::comphelper::AsyncEventNotifier );
1575                     m_pItemBroadcaster->create();
1576                 }
1577 		        m_pItemBroadcaster->addEvent( new ItemEventDescription( _rEvent ), this );
1578             }
1579         }
1580 
1581         // and do the handling for the ChangeListeners
1582         ::osl::ClearableMutexGuard aGuard(m_aMutex);
1583         if ( m_aChangeTimer.IsActive() )
1584         {
1585             Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1586             m_aCurrentSelection = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1587 
1588             m_aChangeTimer.Stop();
1589             m_aChangeTimer.Start();
1590         }
1591         else
1592         {
1593             if ( m_aChangeListeners.getLength() && m_aCurrentSelection.hasValue() )
1594             {
1595                 Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1596                 if (xSet.is())
1597                 {
1598                     // Has the selection been changed?
1599                     sal_Bool bModified(sal_False);
1600                     Any aValue = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1601 
1602                     Sequence<sal_Int16>& rSelection = *(Sequence<sal_Int16> *)aValue.getValue();
1603                     Sequence<sal_Int16>& rOldSelection = *(Sequence<sal_Int16> *)m_aCurrentSelection.getValue();
1604                     sal_Int32 nLen = rSelection.getLength();
1605                     if (nLen != rOldSelection.getLength())
1606                         bModified = sal_True;
1607                     else
1608                     {
1609                         const sal_Int16* pVal = rSelection.getConstArray();
1610                         const sal_Int16* pCompVal = rOldSelection.getConstArray();
1611 
1612                         while (nLen-- && !bModified)
1613                             bModified = pVal[nLen] != pCompVal[nLen];
1614                     }
1615 
1616                     if (bModified)
1617                     {
1618                         m_aCurrentSelection = aValue;
1619                         m_aChangeTimer.Start();
1620                     }
1621                 }
1622             }
1623             else if (m_aCurrentSelection.hasValue())
1624                 m_aCurrentSelection.clear();
1625         }
1626     }
1627 
1628     // XEventListener
1629     //------------------------------------------------------------------------------
1630     void SAL_CALL OListBoxControl::disposing(const EventObject& _rSource) throw (RuntimeException)
1631     {
1632         OBoundControl::disposing(_rSource);
1633     }
1634 
1635     // XChangeBroadcaster
1636     //------------------------------------------------------------------------------
1637     void SAL_CALL OListBoxControl::addChangeListener(const Reference<XChangeListener>& _rxListener) throw(RuntimeException)
1638     {
1639         m_aChangeListeners.addInterface( _rxListener );
1640     }
1641 
1642     //------------------------------------------------------------------------------
1643     void SAL_CALL OListBoxControl::removeChangeListener(const Reference<XChangeListener>& _rxListener) throw(RuntimeException)
1644     {
1645         m_aChangeListeners.removeInterface( _rxListener );
1646     }
1647 
1648     // OComponentHelper
1649     //------------------------------------------------------------------------------
1650     void OListBoxControl::disposing()
1651     {
1652         if (m_aChangeTimer.IsActive())
1653             m_aChangeTimer.Stop();
1654 
1655         EventObject aEvent( *this );
1656         m_aChangeListeners.disposeAndClear( aEvent );
1657         m_aItemListeners.disposeAndClear( aEvent );
1658 
1659         {
1660             ::osl::MutexGuard aGuard( m_aMutex );
1661             if ( m_pItemBroadcaster.is() )
1662             {
1663                 m_pItemBroadcaster->removeEventsForProcessor( this );
1664                 m_pItemBroadcaster->terminate();
1665                 m_pItemBroadcaster = NULL;
1666             }
1667         }
1668 
1669         OBoundControl::disposing();
1670     }
1671 
1672     //------------------------------------------------------------------------------
1673     void OListBoxControl::processEvent( const AnyEvent& _rEvent )
1674     {
1675         Reference< XListBox > xKeepAlive( this );
1676         {
1677             ::osl::MutexGuard aGuard( m_aMutex );
1678             if ( OComponentHelper::rBHelper.bDisposed )
1679                 return;
1680         }
1681         const ItemEventDescription& rItemEvent = static_cast< const ItemEventDescription& >( _rEvent );
1682         m_aItemListeners.notifyEach( &XItemListener::itemStateChanged, rItemEvent.getEventObject() );
1683     }
1684 
1685     //------------------------------------------------------------------------------
1686     IMPL_LINK(OListBoxControl, OnTimeout, void*, /*EMPTYTAG*/)
1687     {
1688         m_aChangeListeners.notifyEach( &XChangeListener::changed, EventObject( *this ) );
1689         return 0L;
1690     }
1691 
1692     //--------------------------------------------------------------------
1693     void SAL_CALL OListBoxControl::addItemListener( const Reference< XItemListener >& l ) throw (RuntimeException)
1694     {
1695         m_aItemListeners.addInterface( l );
1696     }
1697 
1698     //--------------------------------------------------------------------
1699     void SAL_CALL OListBoxControl::removeItemListener( const Reference< XItemListener >& l ) throw (RuntimeException)
1700     {
1701         m_aItemListeners.removeInterface( l );
1702     }
1703 
1704     //--------------------------------------------------------------------
1705     void SAL_CALL OListBoxControl::addActionListener( const Reference< XActionListener >& l ) throw (RuntimeException)
1706     {
1707         if ( m_xAggregateListBox.is() )
1708             m_xAggregateListBox->addActionListener( l );
1709     }
1710 
1711     //--------------------------------------------------------------------
1712     void SAL_CALL OListBoxControl::removeActionListener( const Reference< XActionListener >& l ) throw (RuntimeException)
1713     {
1714         if ( m_xAggregateListBox.is() )
1715             m_xAggregateListBox->removeActionListener( l );
1716     }
1717 
1718     //--------------------------------------------------------------------
1719     void SAL_CALL OListBoxControl::addItem( const ::rtl::OUString& aItem, ::sal_Int16 nPos ) throw (RuntimeException)
1720     {
1721         if ( m_xAggregateListBox.is() )
1722             m_xAggregateListBox->addItem( aItem, nPos );
1723     }
1724 
1725     //--------------------------------------------------------------------
1726     void SAL_CALL OListBoxControl::addItems( const Sequence< ::rtl::OUString >& aItems, ::sal_Int16 nPos ) throw (RuntimeException)
1727     {
1728         if ( m_xAggregateListBox.is() )
1729             m_xAggregateListBox->addItems( aItems, nPos );
1730     }
1731 
1732     //--------------------------------------------------------------------
1733     void SAL_CALL OListBoxControl::removeItems( ::sal_Int16 nPos, ::sal_Int16 nCount ) throw (RuntimeException)
1734     {
1735         if ( m_xAggregateListBox.is() )
1736             m_xAggregateListBox->removeItems( nPos, nCount );
1737     }
1738 
1739     //--------------------------------------------------------------------
1740     ::sal_Int16 SAL_CALL OListBoxControl::getItemCount(  ) throw (RuntimeException)
1741     {
1742         if ( m_xAggregateListBox.is() )
1743             return m_xAggregateListBox->getItemCount();
1744         return 0;
1745     }
1746 
1747     //--------------------------------------------------------------------
1748     ::rtl::OUString SAL_CALL OListBoxControl::getItem( ::sal_Int16 nPos ) throw (RuntimeException)
1749     {
1750         if ( m_xAggregateListBox.is() )
1751             return m_xAggregateListBox->getItem( nPos );
1752         return ::rtl::OUString( );
1753     }
1754 
1755     //--------------------------------------------------------------------
1756     Sequence< ::rtl::OUString > SAL_CALL OListBoxControl::getItems(  ) throw (RuntimeException)
1757     {
1758         if ( m_xAggregateListBox.is() )
1759             return m_xAggregateListBox->getItems();
1760         return Sequence< ::rtl::OUString >( );
1761     }
1762 
1763     //--------------------------------------------------------------------
1764     ::sal_Int16 SAL_CALL OListBoxControl::getSelectedItemPos(  ) throw (RuntimeException)
1765     {
1766         if ( m_xAggregateListBox.is() )
1767             return m_xAggregateListBox->getSelectedItemPos();
1768         return 0;
1769     }
1770 
1771     //--------------------------------------------------------------------
1772     Sequence< ::sal_Int16 > SAL_CALL OListBoxControl::getSelectedItemsPos(  ) throw (RuntimeException)
1773     {
1774         if ( m_xAggregateListBox.is() )
1775             return m_xAggregateListBox->getSelectedItemsPos();
1776         return Sequence< ::sal_Int16 >( );
1777     }
1778 
1779     //--------------------------------------------------------------------
1780     ::rtl::OUString SAL_CALL OListBoxControl::getSelectedItem(  ) throw (RuntimeException)
1781     {
1782         if ( m_xAggregateListBox.is() )
1783             return m_xAggregateListBox->getSelectedItem();
1784         return ::rtl::OUString( );
1785     }
1786 
1787     //--------------------------------------------------------------------
1788     Sequence< ::rtl::OUString > SAL_CALL OListBoxControl::getSelectedItems(  ) throw (RuntimeException)
1789     {
1790         if ( m_xAggregateListBox.is() )
1791             return m_xAggregateListBox->getSelectedItems();
1792         return Sequence< ::rtl::OUString >( );
1793     }
1794 
1795     //--------------------------------------------------------------------
1796     void SAL_CALL OListBoxControl::selectItemPos( ::sal_Int16 nPos, ::sal_Bool bSelect ) throw (RuntimeException)
1797     {
1798         if ( m_xAggregateListBox.is() )
1799             m_xAggregateListBox->selectItemPos( nPos, bSelect );
1800     }
1801 
1802     //--------------------------------------------------------------------
1803     void SAL_CALL OListBoxControl::selectItemsPos( const Sequence< ::sal_Int16 >& aPositions, ::sal_Bool bSelect ) throw (RuntimeException)
1804     {
1805         if ( m_xAggregateListBox.is() )
1806             m_xAggregateListBox->selectItemsPos( aPositions, bSelect );
1807     }
1808 
1809     //--------------------------------------------------------------------
1810     void SAL_CALL OListBoxControl::selectItem( const ::rtl::OUString& aItem, ::sal_Bool bSelect ) throw (RuntimeException)
1811     {
1812         if ( m_xAggregateListBox.is() )
1813             m_xAggregateListBox->selectItem( aItem, bSelect );
1814     }
1815 
1816     //--------------------------------------------------------------------
1817     ::sal_Bool SAL_CALL OListBoxControl::isMutipleMode(  ) throw (RuntimeException)
1818     {
1819         if ( m_xAggregateListBox.is() )
1820             return m_xAggregateListBox->isMutipleMode();
1821         return sal_False;
1822     }
1823 
1824     //--------------------------------------------------------------------
1825     void SAL_CALL OListBoxControl::setMultipleMode( ::sal_Bool bMulti ) throw (RuntimeException)
1826     {
1827         if ( m_xAggregateListBox.is() )
1828             m_xAggregateListBox->setMultipleMode( bMulti );
1829     }
1830 
1831     //--------------------------------------------------------------------
1832     ::sal_Int16 SAL_CALL OListBoxControl::getDropDownLineCount(  ) throw (RuntimeException)
1833     {
1834         if ( m_xAggregateListBox.is() )
1835             return m_xAggregateListBox->getDropDownLineCount();
1836         return 0;
1837     }
1838 
1839     //--------------------------------------------------------------------
1840     void SAL_CALL OListBoxControl::setDropDownLineCount( ::sal_Int16 nLines ) throw (RuntimeException)
1841     {
1842         if ( m_xAggregateListBox.is() )
1843             m_xAggregateListBox->setDropDownLineCount( nLines );
1844     }
1845 
1846     //--------------------------------------------------------------------
1847     void SAL_CALL OListBoxControl::makeVisible( ::sal_Int16 nEntry ) throw (RuntimeException)
1848     {
1849         if ( m_xAggregateListBox.is() )
1850             m_xAggregateListBox->makeVisible( nEntry );
1851     }
1852 
1853 //.........................................................................
1854 }
1855 //.........................................................................
1856 
1857