merge the formfield patch from ooo-build
[ooovba.git] / forms / source / component / ListBox.cxx
blobdae92c15d951d50dba0310d712adaefa7162122a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ListBox.cxx,v $
10 * $Revision: 1.62 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_forms.hxx"
34 #include "ListBox.hxx"
35 #include "property.hxx"
36 #include "property.hrc"
37 #include "services.hxx"
38 #include "frm_resource.hxx"
39 #include "frm_resource.hrc"
40 #include "BaseListBox.hxx"
41 #include "listenercontainers.hxx"
42 #include "componenttools.hxx"
44 /** === begin UNO includes === **/
45 #include <com/sun/star/util/XNumberFormatTypes.hpp>
46 #include <com/sun/star/sdbc/XRowSet.hpp>
47 #include <com/sun/star/sdbc/DataType.hpp>
48 #include <com/sun/star/container/XIndexAccess.hpp>
49 #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
50 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
51 #include <com/sun/star/util/NumberFormat.hpp>
52 #include <com/sun/star/awt/XWindow.hpp>
53 #include <com/sun/star/sdbc/XConnection.hpp>
54 #include <com/sun/star/sdb/CommandType.hpp>
55 /** === end UNO includes === **/
57 #include <comphelper/basicio.hxx>
58 #include <comphelper/container.hxx>
59 #include <comphelper/numbers.hxx>
60 #include <comphelper/listenernotification.hxx>
61 #include <connectivity/dbtools.hxx>
62 #include <connectivity/formattedcolumnvalue.hxx>
63 #include <connectivity/dbconversion.hxx>
64 #include <cppuhelper/queryinterface.hxx>
65 #include <rtl/logfile.hxx>
66 #include <tools/debug.hxx>
67 #include <tools/diagnose_ex.h>
68 #include <unotools/sharedunocomponent.hxx>
69 #include <vcl/svapp.hxx>
71 #include <algorithm>
72 #include <functional>
75 //.........................................................................
76 namespace frm
78 using namespace ::com::sun::star::uno;
79 using namespace ::com::sun::star::sdb;
80 using namespace ::com::sun::star::sdbc;
81 using namespace ::com::sun::star::sdbcx;
82 using namespace ::com::sun::star::beans;
83 using namespace ::com::sun::star::container;
84 using namespace ::com::sun::star::form;
85 using namespace ::com::sun::star::awt;
86 using namespace ::com::sun::star::io;
87 using namespace ::com::sun::star::lang;
88 using namespace ::com::sun::star::util;
89 using namespace ::com::sun::star::form::binding;
90 using namespace ::dbtools;
92 using ::connectivity::ORowSetValue;
94 //==============================================================================
95 //= helper
96 //==============================================================================
97 namespace
99 //--------------------------------------------------------------------------
100 struct RowSetValueToString : public ::std::unary_function< ORowSetValue, ::rtl::OUString >
102 ::rtl::OUString operator()( const ORowSetValue& _value ) const
104 return _value.getString();
108 //--------------------------------------------------------------------------
109 struct AppendRowSetValueString : public ::std::unary_function< ::rtl::OUString, void >
111 AppendRowSetValueString( ::rtl::OUString& _string )
112 :m_string( _string )
116 void operator()( const ::rtl::OUString _append )
118 m_string += _append;
121 private:
122 ::rtl::OUString& m_string;
125 //--------------------------------------------------------------------------
126 Sequence< ::rtl::OUString > lcl_convertToStringSequence( const ValueList& _values )
128 Sequence< ::rtl::OUString > aStrings( _values.size() );
129 ::std::transform(
130 _values.begin(),
131 _values.end(),
132 aStrings.getArray(),
133 RowSetValueToString()
135 return aStrings;
139 //==============================================================================
140 //= ItemEventDescription
141 //==============================================================================
142 typedef ::comphelper::EventHolder< ItemEvent > ItemEventDescription;
144 //==============================================================================
145 //= OListBoxModel
146 //==============================================================================
147 //------------------------------------------------------------------
148 InterfaceRef SAL_CALL OListBoxModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) throw (RuntimeException)
150 return *(new OListBoxModel(_rxFactory));
153 //------------------------------------------------------------------------------
154 Sequence< Type> OListBoxModel::_getTypes()
156 return TypeBag(
157 OBoundControlModel::_getTypes(),
158 OEntryListHelper::getTypes(),
159 OErrorBroadcaster::getTypes()
160 ).getTypes();
164 DBG_NAME(OListBoxModel);
165 //------------------------------------------------------------------
166 OListBoxModel::OListBoxModel(const Reference<XMultiServiceFactory>& _rxFactory)
167 :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_LISTBOX, FRM_SUN_CONTROL_LISTBOX, sal_True, sal_True, sal_True )
168 // use the old control name for compytibility reasons
169 ,OEntryListHelper( (OControlModel&)*this )
170 ,OErrorBroadcaster( OComponentHelper::rBHelper )
171 ,m_aListRowSet( getContext() )
172 ,m_nNULLPos(-1)
173 ,m_bBoundComponent(sal_False)
175 DBG_CTOR(OListBoxModel,NULL);
177 m_nClassId = FormComponentType::LISTBOX;
178 m_eListSourceType = ListSourceType_VALUELIST;
179 m_aBoundColumn <<= (sal_Int16)1;
180 initValueProperty( PROPERTY_SELECT_SEQ, PROPERTY_ID_SELECT_SEQ);
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_bBoundComponent(sal_False)
197 DBG_CTOR(OListBoxModel,NULL);
200 //------------------------------------------------------------------
201 OListBoxModel::~OListBoxModel()
203 if (!OComponentHelper::rBHelper.bDisposed)
205 acquire();
206 dispose();
209 DBG_DTOR(OListBoxModel,NULL);
212 // XCloneable
213 //------------------------------------------------------------------------------
214 IMPLEMENT_DEFAULT_CLONING( OListBoxModel )
216 // XServiceInfo
217 //------------------------------------------------------------------------------
218 StringSequence SAL_CALL OListBoxModel::getSupportedServiceNames() throw(RuntimeException)
220 StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();
222 sal_Int32 nOldLen = aSupported.getLength();
223 aSupported.realloc( nOldLen + 8 );
224 ::rtl::OUString* pStoreTo = aSupported.getArray() + nOldLen;
226 *pStoreTo++ = BINDABLE_CONTROL_MODEL;
227 *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
228 *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;
230 *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL;
231 *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL;
233 *pStoreTo++ = FRM_SUN_COMPONENT_LISTBOX;
234 *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_LISTBOX;
235 *pStoreTo++ = BINDABLE_DATABASE_LIST_BOX;
237 return aSupported;
240 //------------------------------------------------------------------------------
241 Any SAL_CALL OListBoxModel::queryAggregation(const Type& _rType) throw (RuntimeException)
243 Any aReturn = OBoundControlModel::queryAggregation( _rType );
244 if ( !aReturn.hasValue() )
245 aReturn = OEntryListHelper::queryInterface( _rType );
246 if ( !aReturn.hasValue() )
247 aReturn = OErrorBroadcaster::queryInterface( _rType );
248 return aReturn;
251 // OComponentHelper
252 //------------------------------------------------------------------------------
253 void OListBoxModel::disposing()
255 OBoundControlModel::disposing();
256 OEntryListHelper::disposing();
257 OErrorBroadcaster::disposing();
260 //------------------------------------------------------------------------------
261 void OListBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
263 switch (_nHandle)
265 case PROPERTY_ID_BOUNDCOLUMN:
266 _rValue <<= m_aBoundColumn;
267 break;
269 case PROPERTY_ID_LISTSOURCETYPE:
270 _rValue <<= m_eListSourceType;
271 break;
273 case PROPERTY_ID_LISTSOURCE:
274 _rValue <<= lcl_convertToStringSequence( m_aListSourceValues );
275 break;
277 case PROPERTY_ID_VALUE_SEQ:
278 _rValue <<= lcl_convertToStringSequence( m_aBoundValues );
279 break;
281 case PROPERTY_ID_DEFAULT_SELECT_SEQ:
282 _rValue <<= m_aDefaultSelectSeq;
283 break;
285 case PROPERTY_ID_STRINGITEMLIST:
286 _rValue <<= getStringItemList();
287 break;
289 default:
290 OBoundControlModel::getFastPropertyValue(_rValue, _nHandle);
294 //------------------------------------------------------------------------------
295 void OListBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) throw (com::sun::star::uno::Exception)
297 switch (_nHandle)
299 case PROPERTY_ID_BOUNDCOLUMN :
300 DBG_ASSERT((_rValue.getValueType().getTypeClass() == TypeClass_SHORT) || (_rValue.getValueType().getTypeClass() == TypeClass_VOID),
301 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
302 m_aBoundColumn = _rValue;
303 break;
305 case PROPERTY_ID_LISTSOURCETYPE :
306 DBG_ASSERT(_rValue.getValueType().equals(::getCppuType(reinterpret_cast<ListSourceType*>(NULL))),
307 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
308 _rValue >>= m_eListSourceType;
309 break;
311 case PROPERTY_ID_LISTSOURCE:
313 // extract
314 Sequence< ::rtl::OUString > aListSource;
315 OSL_VERIFY( _rValue >>= aListSource );
317 // copy to member
318 ValueList().swap(m_aListSourceValues);
319 ::std::copy(
320 aListSource.getConstArray(),
321 aListSource.getConstArray() + aListSource.getLength(),
322 ::std::insert_iterator< ValueList >( m_aListSourceValues, m_aListSourceValues.end() )
325 // propagate
326 if ( m_eListSourceType == ListSourceType_VALUELIST )
328 m_aBoundValues = m_aListSourceValues;
330 else
332 if ( m_xCursor.is() && !hasField() && !hasExternalListSource() )
333 // listbox is already connected to a database, and no external list source
334 // data source changed -> refresh
335 loadData( false );
338 break;
340 case PROPERTY_ID_VALUE_SEQ :
341 OSL_ENSURE( false, "ValueItemList is read-only!" );
342 throw PropertyVetoException();
344 case PROPERTY_ID_DEFAULT_SELECT_SEQ :
345 DBG_ASSERT(_rValue.getValueType().equals(::getCppuType(reinterpret_cast< Sequence<sal_Int16>*>(NULL))),
346 "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
347 _rValue >>= m_aDefaultSelectSeq;
349 DBG_ASSERT(m_xAggregateFastSet.is(), "OListBoxModel::setFastPropertyValue_NoBroadcast(DEFAULT_SELECT_SEQ) : invalid aggregate !");
350 if ( m_xAggregateFastSet.is() )
351 setControlValue( _rValue, eOther );
352 break;
354 case PROPERTY_ID_STRINGITEMLIST:
356 ControlModelLock aLock( *this );
357 setNewStringItemList( _rValue, aLock );
358 // TODO: this is bogus. setNewStringItemList expects a guard which has the *only*
359 // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
360 // a lock - so we effectively has two locks here, of which setNewStringItemList can
361 // only control one.
363 resetNoBroadcast();
364 break;
366 default:
367 OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
371 //------------------------------------------------------------------------------
372 sal_Bool OListBoxModel::convertFastPropertyValue(
373 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
374 throw (IllegalArgumentException)
376 sal_Bool bModified(sal_False);
377 switch (_nHandle)
379 case PROPERTY_ID_BOUNDCOLUMN :
380 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aBoundColumn, ::getCppuType(reinterpret_cast<sal_Int16*>(NULL)));
381 break;
383 case PROPERTY_ID_LISTSOURCETYPE:
384 bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType);
385 break;
387 case PROPERTY_ID_LISTSOURCE:
388 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, lcl_convertToStringSequence( m_aListSourceValues ) );
389 break;
391 case PROPERTY_ID_VALUE_SEQ :
392 OSL_ENSURE( false, "ValueItemList is read-only!" );
393 throw PropertyVetoException();
395 case PROPERTY_ID_DEFAULT_SELECT_SEQ :
396 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultSelectSeq);
397 break;
399 case PROPERTY_ID_STRINGITEMLIST:
400 bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue );
401 break;
403 default:
404 return OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
406 return bModified;
409 //------------------------------------------------------------------------------
410 void SAL_CALL OListBoxModel::setPropertyValues( const Sequence< ::rtl::OUString >& _rPropertyNames, const Sequence< Any >& _rValues ) throw(PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
412 // if both SelectedItems and StringItemList are set, care for this
413 // #i27024# / 2004-04-05 / fs@openoffice.org
414 const Any* pSelectSequenceValue = NULL;
416 const ::rtl::OUString* pStartPos = _rPropertyNames.getConstArray();
417 const ::rtl::OUString* pEndPos = _rPropertyNames.getConstArray() + _rPropertyNames.getLength();
418 const ::rtl::OUString* pSelectedItemsPos = ::std::find_if(
419 pStartPos, pEndPos,
420 ::std::bind2nd( ::std::equal_to< ::rtl::OUString >(), PROPERTY_SELECT_SEQ )
422 const ::rtl::OUString* pStringItemListPos = ::std::find_if(
423 pStartPos, pEndPos,
424 ::std::bind2nd( ::std::equal_to< ::rtl::OUString >(), PROPERTY_STRINGITEMLIST )
426 if ( ( pSelectedItemsPos != pEndPos ) && ( pStringItemListPos != pEndPos ) )
428 // both properties are present
429 // -> remember the value for the select sequence
430 pSelectSequenceValue = _rValues.getConstArray() + ( pSelectedItemsPos - pStartPos );
433 OBoundControlModel::setPropertyValues( _rPropertyNames, _rValues );
435 if ( pSelectSequenceValue )
437 setPropertyValue( PROPERTY_SELECT_SEQ, *pSelectSequenceValue );
438 // Note that this is the only reliable way, since one of the properties is implemented
439 // by ourself, and one is implemented by the aggregate, we cannot rely on any particular
440 // results when setting them both - too many undocumented behavior in all the involved
441 // classes
445 //------------------------------------------------------------------------------
446 void OListBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const
448 BEGIN_DESCRIBE_PROPERTIES( 7, OBoundControlModel )
449 DECL_PROP1(TABINDEX, sal_Int16, BOUND);
450 DECL_PROP2(BOUNDCOLUMN, sal_Int16, BOUND, MAYBEVOID);
451 DECL_PROP1(LISTSOURCETYPE, ListSourceType, BOUND);
452 DECL_PROP1(LISTSOURCE, StringSequence, BOUND);
453 DECL_PROP3(VALUE_SEQ, StringSequence, BOUND, READONLY, TRANSIENT);
454 DECL_PROP1(DEFAULT_SELECT_SEQ, Sequence<sal_Int16>, BOUND);
455 DECL_PROP1(STRINGITEMLIST, Sequence< ::rtl::OUString >, BOUND);
456 END_DESCRIBE_PROPERTIES();
459 //------------------------------------------------------------------------------
460 void OListBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const
462 OBoundControlModel::describeAggregateProperties( _rAggregateProps );
464 // superseded properties:
465 RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST );
468 //------------------------------------------------------------------------------
469 ::rtl::OUString SAL_CALL OListBoxModel::getServiceName() throw(RuntimeException)
471 return FRM_COMPONENT_LISTBOX; // old (non-sun) name for compatibility !
474 //------------------------------------------------------------------------------
475 void SAL_CALL OListBoxModel::write(const Reference<XObjectOutputStream>& _rxOutStream)
476 throw(IOException, RuntimeException)
478 OBoundControlModel::write(_rxOutStream);
480 // Dummy-Seq, um Kompatible zu bleiben, wenn SelectSeq nicht mehr gespeichert wird
481 Sequence<sal_Int16> aDummySeq;
483 // Version
484 // Version 0x0002: ListSource wird StringSeq
485 _rxOutStream->writeShort(0x0004);
487 // Maskierung fuer any
488 sal_uInt16 nAnyMask = 0;
489 if (m_aBoundColumn.getValueType().getTypeClass() != TypeClass_VOID)
490 nAnyMask |= BOUNDCOLUMN;
492 _rxOutStream << nAnyMask;
494 _rxOutStream << lcl_convertToStringSequence( m_aListSourceValues );
495 _rxOutStream << (sal_Int16)m_eListSourceType;
496 _rxOutStream << aDummySeq;
497 _rxOutStream << m_aDefaultSelectSeq;
499 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
501 sal_Int16 nBoundColumn = 0;
502 m_aBoundColumn >>= nBoundColumn;
503 _rxOutStream << nBoundColumn;
505 writeHelpTextCompatibly(_rxOutStream);
507 // from version 0x0004 : common properties
508 writeCommonProperties(_rxOutStream);
511 //------------------------------------------------------------------------------
512 void SAL_CALL OListBoxModel::read(const Reference<XObjectInputStream>& _rxInStream) throw(IOException, RuntimeException)
514 // Bei manchen Variblen muessen Abhaengigkeiten beruecksichtigt werden.
515 // Deshalb muessen sie explizit ueber setPropertyValue() gesetzt werden.
517 OBoundControlModel::read(_rxInStream);
518 ControlModelLock aLock( *this );
520 // since we are "overwriting" the StringItemList of our aggregate (means we have
521 // an own place to store the value, instead of relying on our aggregate storing it),
522 // we need to respect what the aggregate just read for the StringItemList property.
525 if ( m_xAggregateSet.is() )
526 setNewStringItemList( m_xAggregateSet->getPropertyValue( PROPERTY_STRINGITEMLIST ), aLock );
528 catch( const Exception& )
530 OSL_ENSURE( sal_False, "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" );
533 // Version
534 sal_uInt16 nVersion = _rxInStream->readShort();
535 DBG_ASSERT(nVersion > 0, "OListBoxModel::read : version 0 ? this should never have been written !");
537 if (nVersion > 0x0004)
539 DBG_ERROR("OListBoxModel::read : invalid (means unknown) version !");
540 ValueList().swap(m_aListSourceValues);
541 m_aBoundColumn <<= (sal_Int16)0;
542 ValueList().swap(m_aBoundValues);
543 m_eListSourceType = ListSourceType_VALUELIST;
544 m_aDefaultSelectSeq.realloc(0);
545 defaultCommonProperties();
546 return;
549 // Maskierung fuer any
550 sal_uInt16 nAnyMask;
551 _rxInStream >> nAnyMask;
553 // ListSourceSeq
554 StringSequence aListSourceSeq;
555 if (nVersion == 0x0001)
557 // ListSourceSeq aus String zusammenstellen;
558 ::rtl::OUString sListSource;
559 _rxInStream >> sListSource;
561 sal_Int32 nTokens = 1;
562 const sal_Unicode* pStr = sListSource.getStr();
563 while ( *pStr )
565 if ( *pStr == ';' )
566 nTokens++;
567 pStr++;
569 aListSourceSeq.realloc( nTokens );
570 for (sal_uInt16 i=0; i<nTokens; ++i)
572 sal_Int32 nTmp = 0;
573 aListSourceSeq.getArray()[i] = sListSource.getToken(i,';',nTmp);
576 else
577 _rxInStream >> aListSourceSeq;
579 sal_Int16 nListSourceType;
580 _rxInStream >> nListSourceType;
581 m_eListSourceType = (ListSourceType)nListSourceType;
582 Any aListSourceSeqAny;
583 aListSourceSeqAny <<= aListSourceSeq;
585 setFastPropertyValue(PROPERTY_ID_LISTSOURCE, aListSourceSeqAny );
587 // Dummy-Seq, um Kompatible zu bleiben, wenn SelectSeq nicht mehr gespeichert wird
588 Sequence<sal_Int16> aDummySeq;
589 _rxInStream >> aDummySeq;
591 // DefaultSelectSeq
592 Sequence<sal_Int16> aDefaultSelectSeq;
593 _rxInStream >> aDefaultSelectSeq;
594 Any aDefaultSelectSeqAny;
595 aDefaultSelectSeqAny <<= aDefaultSelectSeq;
596 setFastPropertyValue(PROPERTY_ID_DEFAULT_SELECT_SEQ, aDefaultSelectSeqAny);
598 // BoundColumn
599 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
601 sal_Int16 nValue;
602 _rxInStream >> nValue;
603 m_aBoundColumn <<= nValue;
606 if (nVersion > 2)
607 readHelpTextCompatibly(_rxInStream);
609 // if our string list is not filled from the value list, we must empty it
610 // this can be the case when somebody saves in alive mode
611 if ( ( m_eListSourceType != ListSourceType_VALUELIST )
612 && !hasExternalListSource()
615 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) );
618 if (nVersion > 3)
619 readCommonProperties(_rxInStream);
621 // Nach dem Lesen die Defaultwerte anzeigen
622 if ( getControlSource().getLength() )
623 // (not if we don't have a control source - the "State" property acts like it is persistent, then
624 resetNoBroadcast();
627 //------------------------------------------------------------------------------
628 void OListBoxModel::loadData( bool _bForce )
630 RTL_LOGFILE_CONTEXT( aLogContext, "OListBoxModel::loadData" );
631 DBG_ASSERT( m_eListSourceType != ListSourceType_VALUELIST, "OListBoxModel::loadData: cannot load value list from DB!" );
632 DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::loadData: cannot load from DB when I have an external list source!" );
634 m_nNULLPos = -1;
635 m_bBoundComponent = sal_False;
637 // pre-requisites:
638 // PRE1: connection
639 Reference< XConnection > xConnection;
640 // is the active connection of our form
641 Reference< XPropertySet > xFormProps( m_xCursor, UNO_QUERY );
642 if ( xFormProps.is() )
643 xFormProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection;
645 // PRE2: list source
646 ::rtl::OUString sListSource;
647 // if our list source type is no value list, we need to concatenate
648 // the single list source elements
649 ::std::for_each(
650 m_aListSourceValues.begin(),
651 m_aListSourceValues.end(),
652 AppendRowSetValueString( sListSource )
655 // outta here if we don't have all pre-requisites
656 if ( !xConnection.is() || !sListSource.getLength() )
658 ValueList().swap(m_aBoundValues);
659 return;
662 sal_Int16 nBoundColumn = 0;
663 if (m_aBoundColumn.getValueType().getTypeClass() == TypeClass_SHORT)
664 m_aBoundColumn >>= nBoundColumn;
666 ::utl::SharedUNOComponent< XResultSet > xListCursor;
669 m_aListRowSet.setConnection( xConnection );
671 sal_Bool bExecute = sal_False;
672 switch (m_eListSourceType)
674 case ListSourceType_TABLEFIELDS:
675 // don't work with a statement here, the fields will be collected below
676 break;
678 case ListSourceType_TABLE:
680 Reference<XNameAccess> xFieldsByName = getTableFields(xConnection, sListSource);
681 Reference<XIndexAccess> xFieldsByIndex(xFieldsByName, UNO_QUERY);
683 // do we have a bound column if yes we have to select it
684 // and the displayed column is the first column othwhise we act as a combobox
685 ::rtl::OUString aFieldName;
686 ::rtl::OUString aBoundFieldName;
688 if ((nBoundColumn > 0) && xFieldsByIndex.is())
690 if (xFieldsByIndex->getCount() <= nBoundColumn)
691 break;
693 Reference<XPropertySet> xFieldAsSet(xFieldsByIndex->getByIndex(nBoundColumn),UNO_QUERY);
694 xFieldAsSet->getPropertyValue(PROPERTY_NAME) >>= aBoundFieldName;
695 nBoundColumn = 1;
697 xFieldAsSet.set(xFieldsByIndex->getByIndex(0),UNO_QUERY);
698 xFieldAsSet->getPropertyValue(PROPERTY_NAME) >>= aFieldName;
700 else if (xFieldsByName.is())
702 if ( xFieldsByName->hasByName( getControlSource() ) )
703 aFieldName = getControlSource();
704 else
706 // otherwise look for the alias
707 Reference<XSQLQueryComposerFactory> xFactory(xConnection, UNO_QUERY);
708 if (!xFactory.is())
709 break;
711 Reference<XSQLQueryComposer> xComposer = xFactory->createQueryComposer();
714 ::rtl::OUString aStatement;
715 xFormProps->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= aStatement;
716 xComposer->setQuery( aStatement );
718 catch(Exception&)
720 disposeComponent(xComposer);
721 break;
724 // search the field
725 Reference<XColumnsSupplier> xSupplyFields(xComposer, UNO_QUERY);
726 DBG_ASSERT(xSupplyFields.is(), "OListBoxModel::loadData : invalid query composer !");
728 Reference<XNameAccess> xFieldNames = xSupplyFields->getColumns();
729 if ( xFieldNames->hasByName( getControlSource() ) )
731 Reference<XPropertySet> xComposerFieldAsSet;
732 xFieldNames->getByName( getControlSource() ) >>= xComposerFieldAsSet;
733 if (hasProperty(PROPERTY_FIELDSOURCE, xComposerFieldAsSet))
734 xComposerFieldAsSet->getPropertyValue(PROPERTY_FIELDSOURCE) >>= aFieldName;
736 disposeComponent(xComposer);
739 if (!aFieldName.getLength())
740 break;
742 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
743 ::rtl::OUString aQuote = xMeta->getIdentifierQuoteString();
744 ::rtl::OUString aStatement = ::rtl::OUString::createFromAscii("SELECT ");
745 if (!aBoundFieldName.getLength()) // act like a combobox
746 aStatement += ::rtl::OUString::createFromAscii("DISTINCT ");
748 aStatement += quoteName(aQuote,aFieldName);
749 if (aBoundFieldName.getLength())
751 aStatement += ::rtl::OUString::createFromAscii(", ");
752 aStatement += quoteName(aQuote, aBoundFieldName);
754 aStatement += ::rtl::OUString::createFromAscii(" FROM ");
756 ::rtl::OUString sCatalog, sSchema, sTable;
757 qualifiedNameComponents( xMeta, sListSource, sCatalog, sSchema, sTable, eInDataManipulation );
758 aStatement += composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable );
760 m_aListRowSet.setEscapeProcessing( sal_False );
761 m_aListRowSet.setCommand( aStatement );
762 bExecute = sal_True;
764 break;
766 case ListSourceType_QUERY:
767 m_aListRowSet.setCommandFromQuery( sListSource );
768 bExecute = sal_True;
769 break;
771 default:
772 m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType );
773 m_aListRowSet.setCommand( sListSource );
774 bExecute = sal_True;
775 break;
778 if (bExecute)
780 if ( !_bForce && !m_aListRowSet.isDirty() )
782 // if none of the settings of the row set changed, compared to the last
783 // invocation of loadData, then don't re-fill the list. Instead, assume
784 // the list entries are the same.
785 return;
787 xListCursor.reset( m_aListRowSet.execute() );
790 catch(SQLException& eSQL)
792 onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
793 return;
795 catch(const Exception& eUnknown)
797 (void)eUnknown;
798 return;
801 // Anzeige- und Werteliste fuellen
802 ValueList aDisplayList, aValueList;
803 sal_Bool bUseNULL = hasField() && !isRequired();
807 OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ),
808 "OListBoxModel::loadData: logic error!" );
809 if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) )
810 return;
812 switch (m_eListSourceType)
814 case ListSourceType_SQL:
815 case ListSourceType_SQLPASSTHROUGH:
816 case ListSourceType_TABLE:
817 case ListSourceType_QUERY:
819 // Feld der 1. Column des ResultSets holen
820 Reference<XColumnsSupplier> xSupplyCols(xListCursor, UNO_QUERY);
821 DBG_ASSERT(xSupplyCols.is(), "OListBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
822 Reference<XIndexAccess> xColumns;
823 if (xSupplyCols.is())
825 xColumns = Reference<XIndexAccess>(xSupplyCols->getColumns(), UNO_QUERY);
826 DBG_ASSERT(xColumns.is(), "OListBoxModel::loadData : no columns supplied by the row set !");
829 Reference< XPropertySet > xDataField;
830 if ( xColumns.is() )
831 xColumns->getByIndex(0) >>= xDataField;
832 if ( !xDataField.is() )
833 return;
835 ::dbtools::FormattedColumnValue aValueFormatter( getContext(), m_xCursor, xDataField );
837 // Feld der BoundColumn des ResultSets holen
838 sal_Int32 nBoundColumnType = DataType::SQLNULL;
839 if ( ( nBoundColumn > 0 ) && m_xColumn.is() )
840 { // don't look for a bound column if we're not connected to a field
843 Reference< XPropertySet > xBoundField( xColumns->getByIndex( nBoundColumn ), UNO_QUERY_THROW );
844 OSL_VERIFY( xBoundField->getPropertyValue( ::rtl::OUString::createFromAscii( "Type" ) ) >>= nBoundColumnType );
846 catch( const Exception& )
848 DBG_UNHANDLED_EXCEPTION();
851 m_bBoundComponent = ( nBoundColumnType != DataType::SQLNULL );
853 // Ist die LB an ein Feld gebunden und sind Leereintraege zulaessig
854 // dann wird die Position fuer einen Leereintrag gemerkt
856 RTL_LOGFILE_CONTEXT( aLogContext, "OListBoxModel::loadData: string collection" );
857 ::rtl::OUString aStr;
858 sal_Int16 entryPos = 0;
859 ORowSetValue aBoundValue;
860 Reference< XRow > xCursorRow( xListCursor, UNO_QUERY_THROW );
861 while ( xListCursor->next() && ( entryPos++ < SHRT_MAX ) ) // SHRT_MAX is the maximum number of entries
863 aStr = aValueFormatter.getFormattedValue();
864 aDisplayList.push_back( aStr );
866 if ( m_bBoundComponent )
868 aBoundValue.fill( nBoundColumn + 1, nBoundColumnType, xCursorRow );
869 aValueList.push_back( aBoundValue );
872 if ( bUseNULL && ( m_nNULLPos == -1 ) && !aStr.getLength() )
873 m_nNULLPos = sal_Int16( aDisplayList.size() - 1 );
876 break;
878 case ListSourceType_TABLEFIELDS:
880 Reference<XNameAccess> xFieldNames = getTableFields(xConnection, sListSource);
881 if (xFieldNames.is())
883 StringSequence seqNames = xFieldNames->getElementNames();
884 ::std::copy(
885 seqNames.getConstArray(),
886 seqNames.getConstArray() + seqNames.getLength(),
887 ::std::insert_iterator< ValueList >( aDisplayList, aDisplayList.end() )
891 break;
892 default:
893 OSL_ENSURE( false, "OListBoxModel::loadData: unreachable!" );
894 break;
897 catch(SQLException& eSQL)
899 onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
900 return;
902 catch( const Exception& )
904 DBG_UNHANDLED_EXCEPTION();
905 return;
909 // Value-Sequence erzeugen
910 // NULL eintrag hinzufuegen
911 if (bUseNULL && m_nNULLPos == -1)
913 if ( m_bBoundComponent )
914 aValueList.insert( aValueList.begin(), ORowSetValue() );
916 aDisplayList.insert( aDisplayList.begin(), ORowSetValue( ::rtl::OUString() ) );
917 m_nNULLPos = 0;
920 m_aBoundValues = aValueList;
922 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( lcl_convertToStringSequence( aDisplayList ) ) );
925 //------------------------------------------------------------------------------
926 void OListBoxModel::onConnectedDbColumn( const Reference< XInterface >& /*_rxForm*/ )
928 // list boxes which are bound to a db column don't have multi selection
929 // - this would be unable to reflect in the db column
930 if ( hasField() )
932 setFastPropertyValue( PROPERTY_ID_MULTISELECTION, ::cppu::bool2any( ( sal_False ) ) );
935 if ( !hasExternalListSource() )
936 impl_refreshDbEntryList( false );
939 //------------------------------------------------------------------------------
940 void OListBoxModel::onDisconnectedDbColumn()
942 if ( m_eListSourceType != ListSourceType_VALUELIST )
944 ValueList().swap(m_aBoundValues);
945 m_nNULLPos = -1;
946 m_bBoundComponent = sal_False;
948 if ( !hasExternalListSource() )
949 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) );
951 m_aListRowSet.dispose();
955 //------------------------------------------------------------------------------
956 ValueList OListBoxModel::impl_getValues() const
958 if ( !m_aBoundValues.empty() )
959 return m_aBoundValues;
961 Sequence< ::rtl::OUString > aStringItems( getStringItemList() );
962 ValueList aValues( aStringItems.getLength() );
963 ::std::copy(
964 aStringItems.getConstArray(),
965 aStringItems.getConstArray() + aStringItems.getLength(),
966 aValues.begin()
969 return aValues;
971 //------------------------------------------------------------------------------
972 ORowSetValue OListBoxModel::getFirstSelectedValue() const
974 static const ORowSetValue s_aEmptyVaue;
976 DBG_ASSERT( m_xAggregateFastSet.is(), "OListBoxModel::getFirstSelectedValue: invalid aggregate!" );
977 if ( !m_xAggregateFastSet.is() )
978 return s_aEmptyVaue;
980 Sequence< sal_Int16 > aSelectedIndices;
981 OSL_VERIFY( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) >>= aSelectedIndices );
982 if ( !aSelectedIndices.getLength() )
983 // nothing selected at all
984 return s_aEmptyVaue;
986 if ( ( m_nNULLPos != -1 ) && ( aSelectedIndices[0] == m_nNULLPos ) )
987 // the dedicated "NULL" entry is selected
988 return s_aEmptyVaue;
990 ValueList aValues( impl_getValues() );
992 size_t selectedValue = aSelectedIndices[0];
993 if ( selectedValue >= aValues.size() )
995 OSL_ENSURE( false, "OListBoxModel::getFirstSelectedValue: inconsistent selection/valuelist!" );
996 return s_aEmptyVaue;
999 return aValues[ selectedValue ];
1002 //------------------------------------------------------------------------------
1003 sal_Bool OListBoxModel::commitControlValueToDbColumn( bool /*_bPostReset*/ )
1005 // current selektion list
1006 const ORowSetValue rCurrentValue( getFirstSelectedValue() );
1007 if ( rCurrentValue != m_aSaveValue )
1009 if ( rCurrentValue.isNull() )
1010 m_xColumnUpdate->updateNull();
1011 else
1015 m_xColumnUpdate->updateObject( rCurrentValue.makeAny() );
1017 catch ( const Exception& )
1019 return sal_False;
1022 m_aSaveValue = rCurrentValue;
1024 return sal_True;
1027 // XPropertiesChangeListener
1028 //------------------------------------------------------------------------------
1029 Any OListBoxModel::translateDbColumnToControlValue()
1031 Reference< XPropertySet > xBoundField( getField() );
1032 if ( !xBoundField.is() )
1034 OSL_ENSURE( false, "OListBoxModel::translateDbColumnToControlValue: no field? How could that happen?!" );
1035 return Any();
1038 Sequence< sal_Int16 > aSelectionIndicies;
1040 // Bei NULL-Eintraegen Selektion aufheben!
1041 ORowSetValue aCurrentValue;
1042 aCurrentValue.fill( xBoundField->getPropertyValue( PROPERTY_VALUE ) );
1044 if ( aCurrentValue.isNull() )
1046 if ( m_nNULLPos != -1 )
1048 aSelectionIndicies.realloc(1);
1049 aSelectionIndicies[0] = m_nNULLPos;
1052 else
1054 ValueList aValues( impl_getValues() );
1055 ValueList::const_iterator curValuePos = ::std::find( aValues.begin(), aValues.end(), aCurrentValue );
1056 if ( curValuePos != aValues.end() )
1058 aSelectionIndicies.realloc( 1 );
1059 aSelectionIndicies[0] = curValuePos - aValues.begin();
1063 m_aSaveValue = aCurrentValue;
1065 return makeAny( aSelectionIndicies );
1068 // XReset
1069 //------------------------------------------------------------------------------
1070 Any OListBoxModel::getDefaultForReset() const
1072 Any aValue;
1073 if (m_aDefaultSelectSeq.getLength())
1074 aValue <<= m_aDefaultSelectSeq;
1075 else if (m_nNULLPos != -1) // gebundene Listbox
1077 Sequence<sal_Int16> aSeq(1);
1078 aSeq.getArray()[0] = m_nNULLPos;
1079 aValue <<= aSeq;
1081 else
1083 Sequence<sal_Int16> aSeq;
1084 aValue <<= aSeq;
1087 return aValue;
1090 //--------------------------------------------------------------------
1091 void SAL_CALL OListBoxModel::disposing( const EventObject& _rSource ) throw ( RuntimeException )
1093 if ( !OEntryListHelper::handleDisposing( _rSource ) )
1094 OBoundControlModel::disposing( _rSource );
1097 //--------------------------------------------------------------------
1098 namespace
1100 /** type how we should transfer our selection to external value bindings
1102 enum ExchangeType
1104 eIndexList, /// as list of indexes of selected entries
1105 eIndex, /// as index of the selected entry
1106 eEntryList, /// as list of string representations of selected entries
1107 eEntry /// as string representation of the selected entry
1110 //--------------------------------------------------------------------
1111 ExchangeType lcl_getCurrentExchangeType( const Type& _rExchangeType )
1113 switch ( _rExchangeType.getTypeClass() )
1115 case TypeClass_STRING:
1116 return eEntry;
1117 case TypeClass_LONG:
1118 return eIndex;
1119 case TypeClass_SEQUENCE:
1121 Type aElementType = ::comphelper::getSequenceElementType( _rExchangeType );
1122 switch ( aElementType.getTypeClass() )
1124 case TypeClass_STRING:
1125 return eEntryList;
1126 case TypeClass_LONG:
1127 return eIndexList;
1128 default:
1129 break;
1132 default:
1133 break;
1135 OSL_ENSURE( false, "lcl_getCurrentExchangeType: unsupported (unexpected) exchange type!" );
1136 return eEntry;
1140 //--------------------------------------------------------------------
1141 Any OListBoxModel::translateExternalValueToControlValue( const Any& _rExternalValue ) const
1143 Sequence< sal_Int16 > aSelectIndexes;
1145 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1147 case eIndexList:
1149 // unfortunately, our select sequence is a sequence<short>, while the external binding
1150 // supplies sequence<int> only -> transform this
1151 Sequence< sal_Int32 > aSelectIndexesPure;
1152 OSL_VERIFY( _rExternalValue >>= aSelectIndexesPure );
1153 aSelectIndexes.realloc( aSelectIndexesPure.getLength() );
1154 ::std::copy(
1155 aSelectIndexesPure.getConstArray(),
1156 aSelectIndexesPure.getConstArray() + aSelectIndexesPure.getLength(),
1157 aSelectIndexes.getArray()
1160 break;
1162 case eIndex:
1164 sal_Int32 nSelectIndex = -1;
1165 OSL_VERIFY( _rExternalValue >>= nSelectIndex );
1166 if ( ( nSelectIndex >= 0 ) && ( nSelectIndex < getStringItemList().getLength() ) )
1168 aSelectIndexes.realloc( 1 );
1169 aSelectIndexes[ 0 ] = static_cast< sal_Int16 >( nSelectIndex );
1172 break;
1174 case eEntryList:
1176 // we can retrieve a string list from the binding for multiple selection
1177 Sequence< ::rtl::OUString > aSelectEntries;
1178 OSL_VERIFY( _rExternalValue >>= aSelectEntries );
1180 ::std::set< sal_Int16 > aSelectionSet;
1182 // find the selection entries in our item list
1183 const ::rtl::OUString* pSelectEntries = aSelectEntries.getArray();
1184 const ::rtl::OUString* pSelectEntriesEnd = pSelectEntries + aSelectEntries.getLength();
1185 while ( pSelectEntries != pSelectEntriesEnd )
1187 // the indexes where the current string appears in our string items
1188 Sequence< sal_Int16 > aThisEntryIndexes;
1189 aThisEntryIndexes = findValue( getStringItemList(), *pSelectEntries++, sal_False );
1191 // insert all the indexes of this entry into our set
1192 ::std::copy(
1193 aThisEntryIndexes.getConstArray(),
1194 aThisEntryIndexes.getConstArray() + aThisEntryIndexes.getLength(),
1195 ::std::insert_iterator< ::std::set< sal_Int16 > >( aSelectionSet, aSelectionSet.begin() )
1199 // copy the indexes to the sequence
1200 aSelectIndexes.realloc( aSelectionSet.size() );
1201 ::std::copy(
1202 aSelectionSet.begin(),
1203 aSelectionSet.end(),
1204 aSelectIndexes.getArray()
1207 break;
1209 case eEntry:
1211 ::rtl::OUString sStringToSelect;
1212 OSL_VERIFY( _rExternalValue >>= sStringToSelect );
1214 aSelectIndexes = findValue( getStringItemList(), sStringToSelect, sal_False );
1216 break;
1219 return makeAny( aSelectIndexes );
1222 //--------------------------------------------------------------------
1223 namespace
1225 //................................................................
1226 struct ExtractStringFromSequence_Safe : public ::std::unary_function< sal_Int16, ::rtl::OUString >
1228 protected:
1229 const Sequence< ::rtl::OUString >& m_rList;
1231 public:
1232 ExtractStringFromSequence_Safe( const Sequence< ::rtl::OUString >& _rList ) : m_rList( _rList ) { }
1234 ::rtl::OUString operator ()( sal_Int16 _nIndex )
1236 OSL_ENSURE( _nIndex < m_rList.getLength(), "ExtractStringFromSequence_Safe: inconsistence!" );
1237 if ( _nIndex < m_rList.getLength() )
1238 return m_rList[ _nIndex ];
1239 return ::rtl::OUString();
1243 //................................................................
1244 Any lcl_getSingleSelectedEntry( const Sequence< sal_Int16 >& _rSelectSequence, const Sequence< ::rtl::OUString >& _rStringList )
1246 Any aReturn;
1248 // by definition, multiple selected entries are transfered as NULL if the
1249 // binding does not support string lists
1250 if ( _rSelectSequence.getLength() <= 1 )
1252 ::rtl::OUString sSelectedEntry;
1254 if ( _rSelectSequence.getLength() == 1 )
1255 sSelectedEntry = ExtractStringFromSequence_Safe( _rStringList )( _rSelectSequence[0] );
1257 aReturn <<= sSelectedEntry;
1260 return aReturn;
1263 //................................................................
1264 Any lcl_getMultiSelectedEntries( const Sequence< sal_Int16 >& _rSelectSequence, const Sequence< ::rtl::OUString >& _rStringList )
1266 Sequence< ::rtl::OUString > aSelectedEntriesTexts( _rSelectSequence.getLength() );
1267 ::std::transform(
1268 _rSelectSequence.getConstArray(),
1269 _rSelectSequence.getConstArray() + _rSelectSequence.getLength(),
1270 aSelectedEntriesTexts.getArray(),
1271 ExtractStringFromSequence_Safe( _rStringList )
1273 return makeAny( aSelectedEntriesTexts );
1277 //--------------------------------------------------------------------
1278 Any OListBoxModel::translateControlValueToExternalValue( ) const
1280 OSL_PRECOND( hasExternalValueBinding(), "OListBoxModel::translateControlValueToExternalValue: no binding!" );
1282 Sequence< sal_Int16 > aSelectSequence;
1283 const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence;
1285 Any aReturn;
1286 switch ( lcl_getCurrentExchangeType( getExternalValueType() ) )
1288 case eIndexList:
1290 // unfortunately, the select sequence is a sequence<short>, but our binding
1291 // expects int's
1292 Sequence< sal_Int32 > aTransformed( aSelectSequence.getLength() );
1293 ::std::copy(
1294 aSelectSequence.getConstArray(),
1295 aSelectSequence.getConstArray() + aSelectSequence.getLength(),
1296 aTransformed.getArray()
1298 aReturn <<= aTransformed;
1300 break;
1302 case eIndex:
1303 if ( aSelectSequence.getLength() <= 1 )
1305 sal_Int32 nIndex = -1;
1307 if ( aSelectSequence.getLength() == 1 )
1308 nIndex = aSelectSequence[0];
1310 aReturn <<= nIndex;
1312 break;
1314 case eEntryList:
1315 aReturn = lcl_getMultiSelectedEntries( aSelectSequence, getStringItemList() );
1316 break;
1318 case eEntry:
1319 aReturn = lcl_getSingleSelectedEntry( aSelectSequence, getStringItemList() );
1320 break;
1323 return aReturn;
1326 //--------------------------------------------------------------------
1327 Any OListBoxModel::getCurrentFormComponentValue() const
1329 if ( hasValidator() )
1330 return OBoundControlModel::getCurrentFormComponentValue();
1332 Any aCurretnValue;
1336 Sequence< sal_Int16 > aSelectSequence;
1337 OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence );
1339 sal_Bool bMultiSelection( sal_False );
1340 OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection );
1342 if ( bMultiSelection )
1343 aCurretnValue = lcl_getMultiSelectedEntries( aSelectSequence, getStringItemList() );
1344 else
1345 aCurretnValue = lcl_getSingleSelectedEntry( aSelectSequence, getStringItemList() );
1347 catch( const Exception& )
1349 DBG_UNHANDLED_EXCEPTION();
1352 return aCurretnValue;
1355 //--------------------------------------------------------------------
1356 Sequence< Type > OListBoxModel::getSupportedBindingTypes()
1358 Sequence< Type > aTypes(4);
1359 aTypes[0] = ::getCppuType( static_cast< Sequence< sal_Int32 >* >( NULL ) );
1360 aTypes[1] = ::getCppuType( static_cast< sal_Int32* >( NULL ) );
1361 aTypes[2] = ::getCppuType( static_cast< Sequence< ::rtl::OUString >* >( NULL ) );
1362 aTypes[3] = ::getCppuType( static_cast< ::rtl::OUString* >( NULL ) );
1363 return aTypes;
1366 //--------------------------------------------------------------------
1367 void OListBoxModel::stringItemListChanged( ControlModelLock& _rInstanceLock )
1369 if ( !m_xAggregateSet.is() )
1370 return;
1372 suspendValueListening();
1375 m_xAggregateSet->setPropertyValue( PROPERTY_STRINGITEMLIST, makeAny( getStringItemList() ) );
1377 catch( const Exception& )
1379 DBG_UNHANDLED_EXCEPTION();
1381 resumeValueListening();
1383 // update the selection here
1384 if ( hasExternalValueBinding( ) )
1385 transferExternalValueToControl( _rInstanceLock );
1386 else
1388 if ( hasField() )
1390 // TODO: update the selection in case we're bound to a database column
1392 else
1394 if ( m_aDefaultSelectSeq.getLength() )
1395 setControlValue( makeAny( m_aDefaultSelectSeq ), eOther );
1400 //--------------------------------------------------------------------
1401 void OListBoxModel::connectedExternalListSource( )
1403 // TODO?
1406 //--------------------------------------------------------------------
1407 void OListBoxModel::disconnectedExternalListSource( )
1409 // TODO: in case we're part of an already loaded form, we should probably simulate
1410 // an onConnectedDbColumn, so our list get's filled with the data as indicated
1411 // by our SQL-binding related properties
1414 //--------------------------------------------------------------------
1415 void OListBoxModel::impl_refreshDbEntryList( bool _bForce )
1417 DBG_ASSERT( !hasExternalListSource(), "OListBoxModel::impl_refreshDbEntryList: invalid call!" );
1419 if ( !hasExternalListSource( )
1420 && ( m_eListSourceType != ListSourceType_VALUELIST )
1421 && ( m_xCursor.is() )
1424 loadData( _bForce );
1428 //--------------------------------------------------------------------
1429 void OListBoxModel::refreshInternalEntryList()
1431 impl_refreshDbEntryList( true );
1432 if ( hasField() && m_xCursor.is() )
1433 initFromField( m_xCursor );
1436 //==================================================================
1437 // OListBoxControl
1438 //==================================================================
1440 //------------------------------------------------------------------
1441 InterfaceRef SAL_CALL OListBoxControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) throw (RuntimeException)
1443 return *(new OListBoxControl(_rxFactory));
1446 //------------------------------------------------------------------------------
1447 Sequence< Type> OListBoxControl::_getTypes()
1449 return TypeBag(
1450 OBoundControl::_getTypes(),
1451 OListBoxControl_BASE::getTypes()
1452 ).getTypes();
1455 //------------------------------------------------------------------
1456 Any SAL_CALL OListBoxControl::queryAggregation(const Type& _rType) throw (RuntimeException)
1458 Any aReturn = OListBoxControl_BASE::queryInterface( _rType );
1460 if ( !aReturn.hasValue()
1461 || _rType.equals( XTypeProvider::static_type() )
1463 aReturn = OBoundControl::queryAggregation( _rType );
1465 return aReturn;
1468 DBG_NAME(OListBoxControl);
1469 //------------------------------------------------------------------------------
1470 OListBoxControl::OListBoxControl(const Reference<XMultiServiceFactory>& _rxFactory)
1471 :OBoundControl( _rxFactory, VCL_CONTROL_LISTBOX, sal_False )
1472 ,m_aChangeListeners( m_aMutex )
1473 ,m_aItemListeners( m_aMutex )
1474 ,m_pItemBroadcaster( NULL )
1476 DBG_CTOR(OListBoxControl,NULL);
1478 increment(m_refCount);
1480 // als FocusListener anmelden
1481 Reference<XWindow> xComp;
1482 if (query_aggregation(m_xAggregate, xComp))
1483 xComp->addFocusListener(this);
1485 // als ItemListener anmelden
1486 if ( query_aggregation( m_xAggregate, m_xAggregateListBox ) )
1487 m_xAggregateListBox->addItemListener(this);
1489 // Refcount bei 2 fuer angemeldete Listener
1490 decrement(m_refCount);
1492 doSetDelegator();
1494 m_aChangeTimer.SetTimeout(500);
1495 m_aChangeTimer.SetTimeoutHdl(LINK(this,OListBoxControl,OnTimeout));
1498 //------------------------------------------------------------------------------
1499 OListBoxControl::~OListBoxControl()
1501 if (!OComponentHelper::rBHelper.bDisposed)
1503 acquire();
1504 dispose();
1507 doResetDelegator();
1508 m_xAggregateListBox.clear();
1510 DBG_DTOR(OListBoxControl,NULL);
1513 //------------------------------------------------------------------------------
1514 StringSequence SAL_CALL OListBoxControl::getSupportedServiceNames() throw(RuntimeException)
1516 StringSequence aSupported = OBoundControl::getSupportedServiceNames();
1517 aSupported.realloc(aSupported.getLength() + 1);
1519 ::rtl::OUString* pArray = aSupported.getArray();
1520 pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_LISTBOX;
1521 return aSupported;
1525 // XFocusListener
1526 //------------------------------------------------------------------------------
1527 void SAL_CALL OListBoxControl::focusGained(const FocusEvent& /*_rEvent*/) throw(RuntimeException)
1529 ::osl::MutexGuard aGuard(m_aMutex);
1530 if ( m_aChangeListeners.getLength() ) // only if there are listeners
1532 Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1533 if (xSet.is())
1535 // memorize the current selection for posting the change event
1536 m_aCurrentSelection = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1541 //------------------------------------------------------------------------------
1542 void SAL_CALL OListBoxControl::focusLost(const FocusEvent& /*_rEvent*/) throw(RuntimeException)
1544 m_aCurrentSelection.clear();
1547 // XItemListener
1548 //------------------------------------------------------------------------------
1549 void SAL_CALL OListBoxControl::itemStateChanged(const ItemEvent& _rEvent) throw(RuntimeException)
1551 // forward this to our listeners
1552 Reference< XChild > xChild( getModel(), UNO_QUERY );
1553 if ( xChild.is() && xChild->getParent().is() )
1555 ::osl::MutexGuard aGuard( m_aMutex );
1556 if ( m_aItemListeners.getLength() )
1558 if ( !m_pItemBroadcaster.is() )
1560 m_pItemBroadcaster.set( new ::comphelper::AsyncEventNotifier );
1561 m_pItemBroadcaster->create();
1563 m_pItemBroadcaster->addEvent( new ItemEventDescription( _rEvent ), this );
1566 else
1567 m_aItemListeners.notifyEach( &XItemListener::itemStateChanged, _rEvent );
1569 // and do the handling for the ChangeListeners
1570 ::osl::ClearableMutexGuard aGuard(m_aMutex);
1571 if ( m_aChangeTimer.IsActive() )
1573 Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1574 m_aCurrentSelection = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1576 m_aChangeTimer.Stop();
1577 m_aChangeTimer.Start();
1579 else
1581 if ( m_aChangeListeners.getLength() && m_aCurrentSelection.hasValue() )
1583 Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
1584 if (xSet.is())
1586 // Has the selection been changed?
1587 sal_Bool bModified(sal_False);
1588 Any aValue = xSet->getPropertyValue(PROPERTY_SELECT_SEQ);
1590 Sequence<sal_Int16>& rSelection = *(Sequence<sal_Int16> *)aValue.getValue();
1591 Sequence<sal_Int16>& rOldSelection = *(Sequence<sal_Int16> *)m_aCurrentSelection.getValue();
1592 sal_Int32 nLen = rSelection.getLength();
1593 if (nLen != rOldSelection.getLength())
1594 bModified = sal_True;
1595 else
1597 const sal_Int16* pVal = rSelection.getConstArray();
1598 const sal_Int16* pCompVal = rOldSelection.getConstArray();
1600 while (nLen-- && !bModified)
1601 bModified = pVal[nLen] != pCompVal[nLen];
1604 if (bModified)
1606 m_aCurrentSelection = aValue;
1607 m_aChangeTimer.Start();
1611 else if (m_aCurrentSelection.hasValue())
1612 m_aCurrentSelection.clear();
1616 // XEventListener
1617 //------------------------------------------------------------------------------
1618 void SAL_CALL OListBoxControl::disposing(const EventObject& _rSource) throw (RuntimeException)
1620 OBoundControl::disposing(_rSource);
1623 // XChangeBroadcaster
1624 //------------------------------------------------------------------------------
1625 void SAL_CALL OListBoxControl::addChangeListener(const Reference<XChangeListener>& _rxListener) throw(RuntimeException)
1627 m_aChangeListeners.addInterface( _rxListener );
1630 //------------------------------------------------------------------------------
1631 void SAL_CALL OListBoxControl::removeChangeListener(const Reference<XChangeListener>& _rxListener) throw(RuntimeException)
1633 m_aChangeListeners.removeInterface( _rxListener );
1636 // OComponentHelper
1637 //------------------------------------------------------------------------------
1638 void OListBoxControl::disposing()
1640 if (m_aChangeTimer.IsActive())
1641 m_aChangeTimer.Stop();
1643 EventObject aEvent( *this );
1644 m_aChangeListeners.disposeAndClear( aEvent );
1645 m_aItemListeners.disposeAndClear( aEvent );
1648 ::osl::MutexGuard aGuard( m_aMutex );
1649 if ( m_pItemBroadcaster.is() )
1651 m_pItemBroadcaster->removeEventsForProcessor( this );
1652 m_pItemBroadcaster->terminate();
1653 m_pItemBroadcaster = NULL;
1657 OBoundControl::disposing();
1660 //------------------------------------------------------------------------------
1661 void OListBoxControl::processEvent( const AnyEvent& _rEvent )
1663 Reference< XListBox > xKeepAlive( this );
1665 ::osl::MutexGuard aGuard( m_aMutex );
1666 if ( OComponentHelper::rBHelper.bDisposed )
1667 return;
1669 const ItemEventDescription& rItemEvent = static_cast< const ItemEventDescription& >( _rEvent );
1670 m_aItemListeners.notifyEach( &XItemListener::itemStateChanged, rItemEvent.getEventObject() );
1673 //------------------------------------------------------------------------------
1674 IMPL_LINK(OListBoxControl, OnTimeout, void*, /*EMPTYTAG*/)
1676 m_aChangeListeners.notifyEach( &XChangeListener::changed, EventObject( *this ) );
1677 return 0L;
1680 //--------------------------------------------------------------------
1681 void SAL_CALL OListBoxControl::addItemListener( const Reference< XItemListener >& l ) throw (RuntimeException)
1683 m_aItemListeners.addInterface( l );
1686 //--------------------------------------------------------------------
1687 void SAL_CALL OListBoxControl::removeItemListener( const Reference< XItemListener >& l ) throw (RuntimeException)
1689 m_aItemListeners.removeInterface( l );
1692 //--------------------------------------------------------------------
1693 void SAL_CALL OListBoxControl::addActionListener( const Reference< XActionListener >& l ) throw (RuntimeException)
1695 if ( m_xAggregateListBox.is() )
1696 m_xAggregateListBox->addActionListener( l );
1699 //--------------------------------------------------------------------
1700 void SAL_CALL OListBoxControl::removeActionListener( const Reference< XActionListener >& l ) throw (RuntimeException)
1702 if ( m_xAggregateListBox.is() )
1703 m_xAggregateListBox->removeActionListener( l );
1706 //--------------------------------------------------------------------
1707 void SAL_CALL OListBoxControl::addItem( const ::rtl::OUString& aItem, ::sal_Int16 nPos ) throw (RuntimeException)
1709 if ( m_xAggregateListBox.is() )
1710 m_xAggregateListBox->addItem( aItem, nPos );
1713 //--------------------------------------------------------------------
1714 void SAL_CALL OListBoxControl::addItems( const Sequence< ::rtl::OUString >& aItems, ::sal_Int16 nPos ) throw (RuntimeException)
1716 if ( m_xAggregateListBox.is() )
1717 m_xAggregateListBox->addItems( aItems, nPos );
1720 //--------------------------------------------------------------------
1721 void SAL_CALL OListBoxControl::removeItems( ::sal_Int16 nPos, ::sal_Int16 nCount ) throw (RuntimeException)
1723 if ( m_xAggregateListBox.is() )
1724 m_xAggregateListBox->removeItems( nPos, nCount );
1727 //--------------------------------------------------------------------
1728 ::sal_Int16 SAL_CALL OListBoxControl::getItemCount( ) throw (RuntimeException)
1730 if ( m_xAggregateListBox.is() )
1731 return m_xAggregateListBox->getItemCount();
1732 return 0;
1735 //--------------------------------------------------------------------
1736 ::rtl::OUString SAL_CALL OListBoxControl::getItem( ::sal_Int16 nPos ) throw (RuntimeException)
1738 if ( m_xAggregateListBox.is() )
1739 return m_xAggregateListBox->getItem( nPos );
1740 return ::rtl::OUString( );
1743 //--------------------------------------------------------------------
1744 Sequence< ::rtl::OUString > SAL_CALL OListBoxControl::getItems( ) throw (RuntimeException)
1746 if ( m_xAggregateListBox.is() )
1747 return m_xAggregateListBox->getItems();
1748 return Sequence< ::rtl::OUString >( );
1751 //--------------------------------------------------------------------
1752 ::sal_Int16 SAL_CALL OListBoxControl::getSelectedItemPos( ) throw (RuntimeException)
1754 if ( m_xAggregateListBox.is() )
1755 return m_xAggregateListBox->getSelectedItemPos();
1756 return 0;
1759 //--------------------------------------------------------------------
1760 Sequence< ::sal_Int16 > SAL_CALL OListBoxControl::getSelectedItemsPos( ) throw (RuntimeException)
1762 if ( m_xAggregateListBox.is() )
1763 return m_xAggregateListBox->getSelectedItemsPos();
1764 return Sequence< ::sal_Int16 >( );
1767 //--------------------------------------------------------------------
1768 ::rtl::OUString SAL_CALL OListBoxControl::getSelectedItem( ) throw (RuntimeException)
1770 if ( m_xAggregateListBox.is() )
1771 return m_xAggregateListBox->getSelectedItem();
1772 return ::rtl::OUString( );
1775 //--------------------------------------------------------------------
1776 Sequence< ::rtl::OUString > SAL_CALL OListBoxControl::getSelectedItems( ) throw (RuntimeException)
1778 if ( m_xAggregateListBox.is() )
1779 return m_xAggregateListBox->getSelectedItems();
1780 return Sequence< ::rtl::OUString >( );
1783 //--------------------------------------------------------------------
1784 void SAL_CALL OListBoxControl::selectItemPos( ::sal_Int16 nPos, ::sal_Bool bSelect ) throw (RuntimeException)
1786 if ( m_xAggregateListBox.is() )
1787 m_xAggregateListBox->selectItemPos( nPos, bSelect );
1790 //--------------------------------------------------------------------
1791 void SAL_CALL OListBoxControl::selectItemsPos( const Sequence< ::sal_Int16 >& aPositions, ::sal_Bool bSelect ) throw (RuntimeException)
1793 if ( m_xAggregateListBox.is() )
1794 m_xAggregateListBox->selectItemsPos( aPositions, bSelect );
1797 //--------------------------------------------------------------------
1798 void SAL_CALL OListBoxControl::selectItem( const ::rtl::OUString& aItem, ::sal_Bool bSelect ) throw (RuntimeException)
1800 if ( m_xAggregateListBox.is() )
1801 m_xAggregateListBox->selectItem( aItem, bSelect );
1804 //--------------------------------------------------------------------
1805 ::sal_Bool SAL_CALL OListBoxControl::isMutipleMode( ) throw (RuntimeException)
1807 if ( m_xAggregateListBox.is() )
1808 return m_xAggregateListBox->isMutipleMode();
1809 return sal_False;
1812 //--------------------------------------------------------------------
1813 void SAL_CALL OListBoxControl::setMultipleMode( ::sal_Bool bMulti ) throw (RuntimeException)
1815 if ( m_xAggregateListBox.is() )
1816 m_xAggregateListBox->setMultipleMode( bMulti );
1819 //--------------------------------------------------------------------
1820 ::sal_Int16 SAL_CALL OListBoxControl::getDropDownLineCount( ) throw (RuntimeException)
1822 if ( m_xAggregateListBox.is() )
1823 return m_xAggregateListBox->getDropDownLineCount();
1824 return 0;
1827 //--------------------------------------------------------------------
1828 void SAL_CALL OListBoxControl::setDropDownLineCount( ::sal_Int16 nLines ) throw (RuntimeException)
1830 if ( m_xAggregateListBox.is() )
1831 m_xAggregateListBox->setDropDownLineCount( nLines );
1834 //--------------------------------------------------------------------
1835 void SAL_CALL OListBoxControl::makeVisible( ::sal_Int16 nEntry ) throw (RuntimeException)
1837 if ( m_xAggregateListBox.is() )
1838 m_xAggregateListBox->makeVisible( nEntry );
1841 //.........................................................................
1843 //.........................................................................