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 { 97 ::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 { 106 AppendRowSetValueString( ::rtl::OUString& _string ) 107 :m_string( _string ) 108 { 109 } 110 111 void operator()( const ::rtl::OUString _append ) 112 { 113 m_string += _append; 114 } 115 116 private: 117 ::rtl::OUString& m_string; 118 }; 119 120 //-------------------------------------------------------------------------- 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 //------------------------------------------------------------------ 143 InterfaceRef SAL_CALL OListBoxModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) 144 { 145 return *(new OListBoxModel(_rxFactory)); 146 } 147 148 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------ 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 //------------------------------------------------------------------ 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 //------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 252 void OListBoxModel::disposing() 253 { 254 OBoundControlModel::disposing(); 255 OEntryListHelper::disposing(); 256 OErrorBroadcaster::disposing(); 257 } 258 259 //------------------------------------------------------------------------------ 260 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 444 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 474 void OListBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const 475 { 476 OBoundControlModel::describeAggregateProperties( _rAggregateProps ); 477 478 // superseded properties: 479 RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST ); 480 } 481 482 //------------------------------------------------------------------------------ 483 ::rtl::OUString SAL_CALL OListBoxModel::getServiceName() 484 { 485 return FRM_COMPONENT_LISTBOX; // old (non-sun) name for compatibility ! 486 } 487 488 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 960 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 //------------------------------------------------------------------------------ 976 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 1074 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 //-------------------------------------------------------------------- 1095 void OListBoxModel::resetNoBroadcast() 1096 { 1097 OBoundControlModel::resetNoBroadcast(); 1098 m_aSaveValue.setNull(); 1099 } 1100 1101 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 1152 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: 1243 ExtractStringFromSequence_Safe( const Sequence< ::rtl::OUString >& _rList ) : m_rList( _rList ) { } 1244 1245 ::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 //................................................................ 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 //................................................................ 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 //-------------------------------------------------------------------- 1289 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 //-------------------------------------------------------------------- 1338 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 1412 void OListBoxModel::connectedExternalListSource( ) 1413 { 1414 // TODO? 1415 } 1416 1417 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //------------------------------------------------------------------ 1452 InterfaceRef SAL_CALL OListBoxControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) 1453 { 1454 return *(new OListBoxControl(_rxFactory)); 1455 } 1456 1457 //------------------------------------------------------------------------------ 1458 Sequence< Type> OListBoxControl::_getTypes() 1459 { 1460 return TypeBag( 1461 OBoundControl::_getTypes(), 1462 OListBoxControl_BASE::getTypes() 1463 ).getTypes(); 1464 } 1465 1466 //------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 1553 void SAL_CALL OListBoxControl::focusLost(const FocusEvent& /*_rEvent*/) 1554 { 1555 m_aCurrentSelection.clear(); 1556 } 1557 1558 // XItemListener 1559 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 1625 void SAL_CALL OListBoxControl::disposing(const EventObject& _rSource) 1626 { 1627 OBoundControl::disposing(_rSource); 1628 } 1629 1630 // XChangeBroadcaster 1631 //------------------------------------------------------------------------------ 1632 void SAL_CALL OListBoxControl::addChangeListener(const Reference<XChangeListener>& _rxListener) 1633 { 1634 m_aChangeListeners.addInterface( _rxListener ); 1635 } 1636 1637 //------------------------------------------------------------------------------ 1638 void SAL_CALL OListBoxControl::removeChangeListener(const Reference<XChangeListener>& _rxListener) 1639 { 1640 m_aChangeListeners.removeInterface( _rxListener ); 1641 } 1642 1643 // OComponentHelper 1644 //------------------------------------------------------------------------------ 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 //------------------------------------------------------------------------------ 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 //-------------------------------------------------------------------- 1688 void SAL_CALL OListBoxControl::addItemListener( const Reference< XItemListener >& l ) 1689 { 1690 m_aItemListeners.addInterface( l ); 1691 } 1692 1693 //-------------------------------------------------------------------- 1694 void SAL_CALL OListBoxControl::removeItemListener( const Reference< XItemListener >& l ) 1695 { 1696 m_aItemListeners.removeInterface( l ); 1697 } 1698 1699 //-------------------------------------------------------------------- 1700 void SAL_CALL OListBoxControl::addActionListener( const Reference< XActionListener >& l ) 1701 { 1702 if ( m_xAggregateListBox.is() ) 1703 m_xAggregateListBox->addActionListener( l ); 1704 } 1705 1706 //-------------------------------------------------------------------- 1707 void SAL_CALL OListBoxControl::removeActionListener( const Reference< XActionListener >& l ) 1708 { 1709 if ( m_xAggregateListBox.is() ) 1710 m_xAggregateListBox->removeActionListener( l ); 1711 } 1712 1713 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 1735 ::sal_Int16 SAL_CALL OListBoxControl::getItemCount( ) 1736 { 1737 if ( m_xAggregateListBox.is() ) 1738 return m_xAggregateListBox->getItemCount(); 1739 return 0; 1740 } 1741 1742 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 1759 ::sal_Int16 SAL_CALL OListBoxControl::getSelectedItemPos( ) 1760 { 1761 if ( m_xAggregateListBox.is() ) 1762 return m_xAggregateListBox->getSelectedItemPos(); 1763 return 0; 1764 } 1765 1766 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 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 //-------------------------------------------------------------------- 1820 void SAL_CALL OListBoxControl::setMultipleMode( ::sal_Bool bMulti ) 1821 { 1822 if ( m_xAggregateListBox.is() ) 1823 m_xAggregateListBox->setMultipleMode( bMulti ); 1824 } 1825 1826 //-------------------------------------------------------------------- 1827 ::sal_Int16 SAL_CALL OListBoxControl::getDropDownLineCount( ) 1828 { 1829 if ( m_xAggregateListBox.is() ) 1830 return m_xAggregateListBox->getDropDownLineCount(); 1831 return 0; 1832 } 1833 1834 //-------------------------------------------------------------------- 1835 void SAL_CALL OListBoxControl::setDropDownLineCount( ::sal_Int16 nLines ) 1836 { 1837 if ( m_xAggregateListBox.is() ) 1838 m_xAggregateListBox->setDropDownLineCount( nLines ); 1839 } 1840 1841 //-------------------------------------------------------------------- 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