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