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 "ComboBox.hxx" 28 #include "property.hxx" 29 #include "property.hrc" 30 #include "services.hxx" 31 32 #include "frm_resource.hxx" 33 #include "frm_resource.hrc" 34 #include "BaseListBox.hxx" 35 36 /** === begin UNO includes === **/ 37 #include <com/sun/star/sdb/SQLErrorEvent.hpp> 38 #include <com/sun/star/sdbc/XRowSet.hpp> 39 #include <com/sun/star/sdbc/DataType.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/sdbc/XConnection.hpp> 45 #include <com/sun/star/sdb/SQLContext.hpp> 46 #include <com/sun/star/sdb/CommandType.hpp> 47 /** === end UNO includes === **/ 48 49 #include <comphelper/numbers.hxx> 50 #include <comphelper/basicio.hxx> 51 #include <connectivity/dbtools.hxx> 52 #include <connectivity/dbconversion.hxx> 53 #include <cppuhelper/queryinterface.hxx> 54 #include <rtl/ustrbuf.hxx> 55 #include <tools/debug.hxx> 56 #include <tools/diagnose_ex.h> 57 #include <unotools/sharedunocomponent.hxx> 58 59 #include <limits.h> 60 61 using namespace dbtools; 62 63 //......................................................................... 64 namespace frm 65 { 66 using namespace ::com::sun::star::uno; 67 using namespace ::com::sun::star::sdb; 68 using namespace ::com::sun::star::sdbc; 69 using namespace ::com::sun::star::sdbcx; 70 using namespace ::com::sun::star::beans; 71 using namespace ::com::sun::star::container; 72 using namespace ::com::sun::star::form; 73 using namespace ::com::sun::star::awt; 74 using namespace ::com::sun::star::io; 75 using namespace ::com::sun::star::lang; 76 using namespace ::com::sun::star::util; 77 using namespace ::com::sun::star::form::binding; 78 79 //======================================================================== 80 // class OComboBoxModel 81 //======================================================================== 82 //------------------------------------------------------------------ 83 InterfaceRef SAL_CALL OComboBoxModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) throw (RuntimeException) 84 { 85 return (*new OComboBoxModel(_rxFactory)); 86 } 87 88 //------------------------------------------------------------------------------ 89 Sequence<Type> OComboBoxModel::_getTypes() 90 { 91 return ::comphelper::concatSequences( 92 OBoundControlModel::_getTypes(), 93 OEntryListHelper::getTypes(), 94 OErrorBroadcaster::getTypes() 95 ); 96 } 97 98 // XServiceInfo 99 //------------------------------------------------------------------------------ 100 StringSequence SAL_CALL OComboBoxModel::getSupportedServiceNames() throw(RuntimeException) 101 { 102 StringSequence aSupported = OBoundControlModel::getSupportedServiceNames(); 103 104 sal_Int32 nOldLen = aSupported.getLength(); 105 aSupported.realloc( nOldLen + 8 ); 106 ::rtl::OUString* pStoreTo = aSupported.getArray() + nOldLen; 107 108 *pStoreTo++ = BINDABLE_CONTROL_MODEL; 109 *pStoreTo++ = DATA_AWARE_CONTROL_MODEL; 110 *pStoreTo++ = VALIDATABLE_CONTROL_MODEL; 111 112 *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL; 113 *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL; 114 115 *pStoreTo++ = FRM_SUN_COMPONENT_COMBOBOX; 116 *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_COMBOBOX; 117 *pStoreTo++ = BINDABLE_DATABASE_COMBO_BOX; 118 119 return aSupported; 120 } 121 122 //------------------------------------------------------------------------------ 123 Any SAL_CALL OComboBoxModel::queryAggregation(const Type& _rType) throw (RuntimeException) 124 { 125 Any aReturn = OBoundControlModel::queryAggregation( _rType ); 126 if ( !aReturn.hasValue() ) 127 aReturn = OEntryListHelper::queryInterface( _rType ); 128 if ( !aReturn.hasValue() ) 129 aReturn = OErrorBroadcaster::queryInterface( _rType ); 130 return aReturn; 131 } 132 133 //------------------------------------------------------------------ 134 DBG_NAME( OComboBoxModel ) 135 //------------------------------------------------------------------ 136 OComboBoxModel::OComboBoxModel(const Reference<XMultiServiceFactory>& _rxFactory) 137 :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_COMBOBOX, FRM_SUN_CONTROL_COMBOBOX, sal_True, sal_True, sal_True ) 138 // use the old control name for compytibility reasons 139 ,OEntryListHelper( (OControlModel&)*this ) 140 ,OErrorBroadcaster( OComponentHelper::rBHelper ) 141 ,m_aListRowSet( getContext() ) 142 ,m_eListSourceType(ListSourceType_TABLE) 143 ,m_bEmptyIsNull(sal_True) 144 { 145 DBG_CTOR( OComboBoxModel, NULL ); 146 147 m_nClassId = FormComponentType::COMBOBOX; 148 initValueProperty( PROPERTY_TEXT, PROPERTY_ID_TEXT ); 149 } 150 151 //------------------------------------------------------------------ 152 OComboBoxModel::OComboBoxModel( const OComboBoxModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory ) 153 :OBoundControlModel( _pOriginal, _rxFactory ) 154 ,OEntryListHelper( *_pOriginal, (OControlModel&)*this ) 155 ,OErrorBroadcaster( OComponentHelper::rBHelper ) 156 ,m_aListRowSet( getContext() ) 157 ,m_aListSource( _pOriginal->m_aListSource ) 158 ,m_aDefaultText( _pOriginal->m_aDefaultText ) 159 ,m_eListSourceType( _pOriginal->m_eListSourceType ) 160 ,m_bEmptyIsNull( _pOriginal->m_bEmptyIsNull ) 161 { 162 DBG_CTOR( OComboBoxModel, NULL ); 163 } 164 165 //------------------------------------------------------------------ 166 OComboBoxModel::~OComboBoxModel() 167 { 168 if (!OComponentHelper::rBHelper.bDisposed) 169 { 170 acquire(); 171 dispose(); 172 } 173 174 DBG_DTOR( OComboBoxModel, NULL ); 175 } 176 177 // XCloneable 178 //------------------------------------------------------------------------------ 179 IMPLEMENT_DEFAULT_CLONING( OComboBoxModel ) 180 181 //------------------------------------------------------------------------------ 182 void OComboBoxModel::disposing() 183 { 184 OBoundControlModel::disposing(); 185 OEntryListHelper::disposing(); 186 OErrorBroadcaster::disposing(); 187 m_xFormatter = NULL; 188 } 189 190 //------------------------------------------------------------------------------ 191 void OComboBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const 192 { 193 switch (_nHandle) 194 { 195 case PROPERTY_ID_LISTSOURCETYPE: 196 _rValue <<= m_eListSourceType; 197 break; 198 199 case PROPERTY_ID_LISTSOURCE: 200 _rValue <<= m_aListSource; 201 break; 202 203 case PROPERTY_ID_EMPTY_IS_NULL: 204 _rValue <<= m_bEmptyIsNull; 205 break; 206 207 case PROPERTY_ID_DEFAULT_TEXT: 208 _rValue <<= m_aDefaultText; 209 break; 210 211 case PROPERTY_ID_STRINGITEMLIST: 212 _rValue <<= getStringItemList(); 213 break; 214 215 default: 216 OBoundControlModel::getFastPropertyValue(_rValue, _nHandle); 217 } 218 } 219 220 //------------------------------------------------------------------------------ 221 void OComboBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) 222 throw (Exception) 223 { 224 switch (_nHandle) 225 { 226 case PROPERTY_ID_LISTSOURCETYPE : 227 DBG_ASSERT(_rValue.getValueType().equals(::getCppuType(reinterpret_cast<ListSourceType*>(NULL))), 228 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 229 _rValue >>= m_eListSourceType; 230 break; 231 232 case PROPERTY_ID_LISTSOURCE : 233 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING, 234 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 235 _rValue >>= m_aListSource; 236 // die ListSource hat sich geaendert -> neu laden 237 if (ListSourceType_VALUELIST != m_eListSourceType) 238 { 239 if ( m_xCursor.is() && !hasField() && !hasExternalListSource() ) 240 // combo box is already connected to a database, and no external list source 241 // data source changed -> refresh 242 loadData( false ); 243 } 244 break; 245 246 case PROPERTY_ID_EMPTY_IS_NULL : 247 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, 248 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 249 _rValue >>= m_bEmptyIsNull; 250 break; 251 252 case PROPERTY_ID_DEFAULT_TEXT : 253 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING, 254 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 255 _rValue >>= m_aDefaultText; 256 resetNoBroadcast(); 257 break; 258 259 case PROPERTY_ID_STRINGITEMLIST: 260 { 261 ControlModelLock aLock( *this ); 262 setNewStringItemList( _rValue, aLock ); 263 // TODO: this is bogus. setNewStringItemList expects a guard which has the *only* 264 // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with 265 // a lock - so we effectively has two locks here, of which setNewStringItemList can 266 // only control one. 267 } 268 break; 269 270 default: 271 OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue); 272 } 273 } 274 275 //------------------------------------------------------------------------------ 276 sal_Bool OComboBoxModel::convertFastPropertyValue( 277 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue) 278 throw (IllegalArgumentException) 279 { 280 sal_Bool bModified(sal_False); 281 switch (_nHandle) 282 { 283 case PROPERTY_ID_LISTSOURCETYPE : 284 bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType); 285 break; 286 287 case PROPERTY_ID_LISTSOURCE : 288 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aListSource); 289 break; 290 291 case PROPERTY_ID_EMPTY_IS_NULL : 292 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bEmptyIsNull); 293 break; 294 295 case PROPERTY_ID_DEFAULT_TEXT : 296 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultText); 297 break; 298 299 case PROPERTY_ID_STRINGITEMLIST: 300 bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue ); 301 break; 302 303 default: 304 bModified = OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue); 305 break; 306 } 307 return bModified; 308 } 309 310 //------------------------------------------------------------------------------ 311 void OComboBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const 312 { 313 BEGIN_DESCRIBE_PROPERTIES( 6, OBoundControlModel ) 314 DECL_PROP1(TABINDEX, sal_Int16, BOUND); 315 DECL_PROP1(LISTSOURCETYPE, ListSourceType, BOUND); 316 DECL_PROP1(LISTSOURCE, ::rtl::OUString, BOUND); 317 DECL_BOOL_PROP1(EMPTY_IS_NULL, BOUND); 318 DECL_PROP1(DEFAULT_TEXT, ::rtl::OUString, BOUND); 319 DECL_PROP1(STRINGITEMLIST, Sequence< ::rtl::OUString >,BOUND); 320 END_DESCRIBE_PROPERTIES(); 321 } 322 323 //------------------------------------------------------------------------------ 324 void OComboBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const 325 { 326 OBoundControlModel::describeAggregateProperties( _rAggregateProps ); 327 328 // superseded properties: 329 RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST ); 330 } 331 332 //------------------------------------------------------------------------------ 333 ::rtl::OUString SAL_CALL OComboBoxModel::getServiceName() throw(RuntimeException) 334 { 335 return FRM_COMPONENT_COMBOBOX; // old (non-sun) name for compatibility ! 336 } 337 338 //------------------------------------------------------------------------------ 339 void SAL_CALL OComboBoxModel::write(const Reference<stario::XObjectOutputStream>& _rxOutStream) 340 throw(stario::IOException, RuntimeException) 341 { 342 OBoundControlModel::write(_rxOutStream); 343 344 // Version 345 // Version 0x0002: EmptyIsNull 346 // Version 0x0003: ListSource->Seq 347 // Version 0x0004: DefaultText 348 // Version 0x0005: HelpText 349 _rxOutStream->writeShort(0x0006); 350 351 // Maskierung fuer any 352 sal_uInt16 nAnyMask = 0; 353 if (m_aBoundColumn.getValueType().getTypeClass() == TypeClass_SHORT) 354 nAnyMask |= BOUNDCOLUMN; 355 _rxOutStream << nAnyMask; 356 357 StringSequence aListSourceSeq(&m_aListSource, 1); 358 _rxOutStream << aListSourceSeq; 359 _rxOutStream << (sal_Int16)m_eListSourceType; 360 361 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN) 362 { 363 sal_Int16 nBoundColumn = 0; 364 m_aBoundColumn >>= nBoundColumn; 365 _rxOutStream << nBoundColumn; 366 } 367 368 _rxOutStream << (sal_Bool)m_bEmptyIsNull; 369 _rxOutStream << m_aDefaultText; 370 writeHelpTextCompatibly(_rxOutStream); 371 372 // from version 0x0006 : common properties 373 writeCommonProperties(_rxOutStream); 374 } 375 376 //------------------------------------------------------------------------------ 377 void SAL_CALL OComboBoxModel::read(const Reference<stario::XObjectInputStream>& _rxInStream) throw(stario::IOException, RuntimeException) 378 { 379 OBoundControlModel::read(_rxInStream); 380 ControlModelLock aLock( *this ); 381 382 // since we are "overwriting" the StringItemList of our aggregate (means we have 383 // an own place to store the value, instead of relying on our aggregate storing it), 384 // we need to respect what the aggregate just read for the StringItemList property. 385 try 386 { 387 if ( m_xAggregateSet.is() ) 388 setNewStringItemList( m_xAggregateSet->getPropertyValue( PROPERTY_STRINGITEMLIST ), aLock ); 389 } 390 catch( const Exception& ) 391 { 392 OSL_ENSURE( sal_False, "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" ); 393 } 394 395 // Version 396 sal_uInt16 nVersion = _rxInStream->readShort(); 397 DBG_ASSERT(nVersion > 0, "OComboBoxModel::read : version 0 ? this should never have been written !"); 398 399 if (nVersion > 0x0006) 400 { 401 DBG_ERROR("OComboBoxModel::read : invalid (means unknown) version !"); 402 m_aListSource = ::rtl::OUString(); 403 m_aBoundColumn <<= (sal_Int16)0; 404 m_aDefaultText = ::rtl::OUString(); 405 m_eListSourceType = ListSourceType_TABLE; 406 m_bEmptyIsNull = sal_True; 407 defaultCommonProperties(); 408 return; 409 } 410 411 // Maskierung fuer any 412 sal_uInt16 nAnyMask; 413 _rxInStream >> nAnyMask; 414 415 // ListSource 416 if (nVersion < 0x0003) 417 { 418 ::rtl::OUString sListSource; 419 _rxInStream >> m_aListSource; 420 } 421 else // nVersion == 4 422 { 423 m_aListSource = ::rtl::OUString(); 424 StringSequence aListSource; 425 _rxInStream >> aListSource; 426 const ::rtl::OUString* pToken = aListSource.getConstArray(); 427 sal_Int32 nLen = aListSource.getLength(); 428 for (sal_Int32 i = 0; i < nLen; ++i, ++pToken) 429 m_aListSource += *pToken; 430 } 431 432 sal_Int16 nListSourceType; 433 _rxInStream >> nListSourceType; 434 m_eListSourceType = (ListSourceType)nListSourceType; 435 436 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN) 437 { 438 sal_Int16 nValue; 439 _rxInStream >> nValue; 440 m_aBoundColumn <<= nValue; 441 } 442 443 if (nVersion > 0x0001) 444 { 445 sal_Bool bNull; 446 _rxInStream >> bNull; 447 m_bEmptyIsNull = bNull; 448 } 449 450 if (nVersion > 0x0003) // nVersion == 4 451 _rxInStream >> m_aDefaultText; 452 453 // Stringliste muss geleert werden, wenn eine Listenquelle gesetzt ist 454 // dieses kann der Fall sein wenn im alive modus gespeichert wird 455 if ( m_aListSource.getLength() 456 && !hasExternalListSource() 457 ) 458 { 459 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) ); 460 } 461 462 if (nVersion > 0x0004) 463 readHelpTextCompatibly(_rxInStream); 464 465 if (nVersion > 0x0005) 466 readCommonProperties(_rxInStream); 467 468 // Nach dem Lesen die Defaultwerte anzeigen 469 if ( getControlSource().getLength() ) 470 { 471 // (not if we don't have a control source - the "State" property acts like it is persistent, then 472 resetNoBroadcast(); 473 } 474 } 475 476 //------------------------------------------------------------------------------ 477 void OComboBoxModel::loadData( bool _bForce ) 478 { 479 DBG_ASSERT(m_eListSourceType != ListSourceType_VALUELIST, "OComboBoxModel::loadData : do not call for a value list !"); 480 DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::loadData: cannot load from DB when I have an external list source!" ); 481 482 if ( hasExternalListSource() ) 483 return; 484 485 // Connection holen 486 Reference<XRowSet> xForm(m_xCursor, UNO_QUERY); 487 if (!xForm.is()) 488 return; 489 Reference<XConnection> xConnection = getConnection(xForm); 490 if (!xConnection.is()) 491 return; 492 493 Reference<XServiceInfo> xServiceInfo(xConnection, UNO_QUERY); 494 if (!xServiceInfo.is() || !xServiceInfo->supportsService(SRV_SDB_CONNECTION)) 495 { 496 DBG_ERROR("OComboBoxModel::loadData : invalid connection !"); 497 return; 498 } 499 500 if (!m_aListSource.getLength() || m_eListSourceType == ListSourceType_VALUELIST) 501 return; 502 503 ::utl::SharedUNOComponent< XResultSet > xListCursor; 504 try 505 { 506 m_aListRowSet.setConnection( xConnection ); 507 508 bool bExecuteRowSet( false ); 509 switch (m_eListSourceType) 510 { 511 case ListSourceType_TABLEFIELDS: 512 // don't work with a statement here, the fields will be collected below 513 break; 514 case ListSourceType_TABLE: 515 { 516 // does the bound field belong to the table ? 517 // if we use an alias for the bound field, we won't find it 518 // in that case we use the first field of the table 519 520 Reference<XNameAccess> xFieldsByName = getTableFields(xConnection, m_aListSource); 521 Reference<XIndexAccess> xFieldsByIndex(xFieldsByName, UNO_QUERY); 522 523 ::rtl::OUString aFieldName; 524 if ( xFieldsByName.is() && xFieldsByName->hasByName( getControlSource() ) ) 525 { 526 aFieldName = getControlSource(); 527 } 528 else 529 { 530 // otherwise look for the alias 531 Reference<XPropertySet> xFormProp(xForm,UNO_QUERY); 532 Reference< XColumnsSupplier > xSupplyFields; 533 xFormProp->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SingleSelectQueryComposer"))) >>= xSupplyFields; 534 535 // search the field 536 DBG_ASSERT(xSupplyFields.is(), "OComboBoxModel::loadData : invalid query composer !"); 537 538 Reference< XNameAccess > xFieldNames = xSupplyFields->getColumns(); 539 if ( xFieldNames->hasByName( getControlSource() ) ) 540 { 541 Reference< XPropertySet > xComposerFieldAsSet; 542 xFieldNames->getByName( getControlSource() ) >>= xComposerFieldAsSet; 543 if (hasProperty(PROPERTY_FIELDSOURCE, xComposerFieldAsSet)) 544 xComposerFieldAsSet->getPropertyValue(PROPERTY_FIELDSOURCE) >>= aFieldName; 545 } 546 } 547 548 if (!aFieldName.getLength()) 549 break; 550 551 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData(); 552 OSL_ENSURE(xMeta.is(),"No database meta data!"); 553 if ( xMeta.is() ) 554 { 555 ::rtl::OUString aQuote = xMeta->getIdentifierQuoteString(); 556 557 ::rtl::OUString sCatalog, sSchema, sTable; 558 qualifiedNameComponents( xMeta, m_aListSource, sCatalog, sSchema, sTable, eInDataManipulation ); 559 560 ::rtl::OUStringBuffer aStatement; 561 aStatement.appendAscii( "SELECT DISTINCT " ); 562 aStatement.append ( quoteName( aQuote, aFieldName ) ); 563 aStatement.appendAscii( " FROM " ); 564 aStatement.append ( composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable ) ); 565 566 m_aListRowSet.setEscapeProcessing( sal_False ); 567 m_aListRowSet.setCommand( aStatement.makeStringAndClear() ); 568 bExecuteRowSet = true; 569 } 570 } break; 571 case ListSourceType_QUERY: 572 { 573 m_aListRowSet.setCommandFromQuery( m_aListSource ); 574 bExecuteRowSet = true; 575 } 576 break; 577 578 default: 579 { 580 m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType ); 581 m_aListRowSet.setCommand( m_aListSource ); 582 bExecuteRowSet = true; 583 } 584 } 585 586 if ( bExecuteRowSet ) 587 { 588 if ( !_bForce && !m_aListRowSet.isDirty() ) 589 { 590 // if none of the settings of the row set changed, compared to the last 591 // invocation of loadData, then don't re-fill the list. Instead, assume 592 // the list entries are the same. 593 return; 594 } 595 xListCursor.reset( m_aListRowSet.execute() ); 596 } 597 } 598 catch(SQLException& eSQL) 599 { 600 onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST)); 601 return; 602 } 603 catch( const Exception& ) 604 { 605 DBG_UNHANDLED_EXCEPTION(); 606 return; 607 } 608 609 ::std::vector< ::rtl::OUString > aStringList; 610 aStringList.reserve(16); 611 try 612 { 613 OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ), 614 "OComboBoxModel::loadData: logic error!" ); 615 if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) ) 616 return; 617 618 switch (m_eListSourceType) 619 { 620 case ListSourceType_SQL: 621 case ListSourceType_SQLPASSTHROUGH: 622 case ListSourceType_TABLE: 623 case ListSourceType_QUERY: 624 { 625 // die XDatabaseVAriant der ersten Spalte 626 Reference<XColumnsSupplier> xSupplyCols(xListCursor, UNO_QUERY); 627 DBG_ASSERT(xSupplyCols.is(), "OComboBoxModel::loadData : cursor supports the row set service but is no column supplier?!"); 628 Reference<XIndexAccess> xColumns; 629 if (xSupplyCols.is()) 630 { 631 xColumns = Reference<XIndexAccess>(xSupplyCols->getColumns(), UNO_QUERY); 632 DBG_ASSERT(xColumns.is(), "OComboBoxModel::loadData : no columns supplied by the row set !"); 633 } 634 Reference< XPropertySet > xDataField; 635 if ( xColumns.is() ) 636 xColumns->getByIndex(0) >>= xDataField; 637 if ( !xDataField.is() ) 638 return; 639 640 ::dbtools::FormattedColumnValue aValueFormatter( getContext(), xForm, xDataField ); 641 642 // Listen fuellen 643 sal_Int16 i = 0; 644 // per definitionem the list cursor is positioned _before_ the first row at the moment 645 while (xListCursor->next() && (i++<SHRT_MAX)) // max anzahl eintraege 646 { 647 aStringList.push_back( aValueFormatter.getFormattedValue() ); 648 } 649 } 650 break; 651 case ListSourceType_TABLEFIELDS: 652 { 653 Reference<XNameAccess> xFieldNames = getTableFields(xConnection, m_aListSource); 654 if (xFieldNames.is()) 655 { 656 StringSequence seqNames = xFieldNames->getElementNames(); 657 sal_Int32 nFieldsCount = seqNames.getLength(); 658 const ::rtl::OUString* pustrNames = seqNames.getConstArray(); 659 660 for (sal_Int32 k=0; k<nFieldsCount; ++k) 661 aStringList.push_back(pustrNames[k]); 662 } 663 } 664 break; 665 default: 666 OSL_ENSURE( false, "OComboBoxModel::loadData: unreachable!" ); 667 break; 668 } 669 } 670 catch(SQLException& eSQL) 671 { 672 onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST)); 673 return; 674 } 675 catch( const Exception& ) 676 { 677 DBG_UNHANDLED_EXCEPTION(); 678 return; 679 } 680 681 // String-Sequence fuer ListBox erzeugen 682 StringSequence aStringSeq(aStringList.size()); 683 ::rtl::OUString* pStringAry = aStringSeq.getArray(); 684 for (sal_Int32 i = 0; i<aStringSeq.getLength(); ++i) 685 pStringAry[i] = aStringList[i]; 686 687 // String-Sequence an ListBox setzen 688 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( aStringSeq ) ); 689 } 690 691 //------------------------------------------------------------------------------ 692 void OComboBoxModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm ) 693 { 694 Reference<XPropertySet> xField = getField(); 695 if ( xField.is() ) 696 m_pValueFormatter.reset( new ::dbtools::FormattedColumnValue( getContext(), Reference< XRowSet >( _rxForm, UNO_QUERY ), xField ) ); 697 getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= m_aDesignModeStringItems; 698 699 // Daten nur laden, wenn eine Listenquelle angegeben wurde 700 if ( m_aListSource.getLength() && m_xCursor.is() && !hasExternalListSource() ) 701 loadData( false ); 702 } 703 704 //------------------------------------------------------------------------------ 705 void OComboBoxModel::onDisconnectedDbColumn() 706 { 707 m_pValueFormatter.reset(); 708 709 // reset the string item list 710 if ( !hasExternalListSource() ) 711 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( m_aDesignModeStringItems ) ); 712 713 m_aListRowSet.dispose(); 714 } 715 716 //------------------------------------------------------------------------------ 717 void SAL_CALL OComboBoxModel::reloaded( const EventObject& aEvent ) throw(RuntimeException) 718 { 719 OBoundControlModel::reloaded(aEvent); 720 721 // reload data if we have a list source 722 if ( m_aListSource.getLength() && m_xCursor.is() && !hasExternalListSource() ) 723 loadData( false ); 724 } 725 726 //------------------------------------------------------------------------------ 727 void OComboBoxModel::resetNoBroadcast() 728 { 729 OBoundControlModel::resetNoBroadcast(); 730 m_aLastKnownValue.clear(); 731 } 732 733 //----------------------------------------------------------------------------- 734 sal_Bool OComboBoxModel::commitControlValueToDbColumn( bool _bPostReset ) 735 { 736 Any aNewValue( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) ); 737 738 ::rtl::OUString sNewValue; 739 aNewValue >>= sNewValue; 740 741 bool bModified = ( aNewValue != m_aLastKnownValue ); 742 if ( bModified ) 743 { 744 if ( !aNewValue.hasValue() 745 || ( !sNewValue.getLength() // an empty string 746 && m_bEmptyIsNull // which should be interpreted as NULL 747 ) 748 ) 749 { 750 m_xColumnUpdate->updateNull(); 751 } 752 else 753 { 754 try 755 { 756 OSL_PRECOND( m_pValueFormatter.get(), "OComboBoxModel::commitControlValueToDbColumn: no value formatter!" ); 757 if ( m_pValueFormatter.get() ) 758 { 759 if ( !m_pValueFormatter->setFormattedValue( sNewValue ) ) 760 return sal_False; 761 } 762 else 763 m_xColumnUpdate->updateString( sNewValue ); 764 } 765 catch ( const Exception& ) 766 { 767 return sal_False; 768 } 769 } 770 771 m_aLastKnownValue = aNewValue; 772 } 773 774 // add the new value to the list 775 sal_Bool bAddToList = bModified && !_bPostReset; 776 // (only if this is not the "commit" triggered by a "reset") 777 778 if ( bAddToList ) 779 { 780 StringSequence aStringItemList; 781 if ( getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aStringItemList ) 782 { 783 const ::rtl::OUString* pStringItems = aStringItemList.getConstArray(); 784 sal_Int32 i; 785 for (i=0; i<aStringItemList.getLength(); ++i, ++pStringItems) 786 { 787 if ( pStringItems->equals( sNewValue ) ) 788 break; 789 } 790 791 // not found -> add 792 if (i >= aStringItemList.getLength()) 793 { 794 sal_Int32 nOldLen = aStringItemList.getLength(); 795 aStringItemList.realloc( nOldLen + 1 ); 796 aStringItemList.getArray()[ nOldLen ] = sNewValue; 797 798 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( aStringItemList ) ); 799 } 800 } 801 } 802 803 return sal_True; 804 } 805 806 // XPropertiesChangeListener 807 //------------------------------------------------------------------------------ 808 Any OComboBoxModel::translateDbColumnToControlValue() 809 { 810 OSL_PRECOND( m_pValueFormatter.get(), "OComboBoxModel::translateDbColumnToControlValue: no value formatter!" ); 811 if ( m_pValueFormatter.get() ) 812 { 813 ::rtl::OUString sValue( m_pValueFormatter->getFormattedValue() ); 814 if ( !sValue.getLength() 815 && m_pValueFormatter->getColumn().is() 816 && m_pValueFormatter->getColumn()->wasNull() 817 ) 818 { 819 m_aLastKnownValue.clear(); 820 } 821 else 822 { 823 824 m_aLastKnownValue <<= sValue; 825 } 826 } 827 else 828 m_aLastKnownValue.clear(); 829 830 return m_aLastKnownValue.hasValue() ? m_aLastKnownValue : makeAny( ::rtl::OUString() ); 831 // (m_aLastKnownValue is alllowed to be VOID, the control value isn't) 832 } 833 834 //------------------------------------------------------------------------------ 835 Any OComboBoxModel::getDefaultForReset() const 836 { 837 return makeAny( m_aDefaultText ); 838 } 839 840 //-------------------------------------------------------------------- 841 void OComboBoxModel::stringItemListChanged( ControlModelLock& /*_rInstanceLock*/ ) 842 { 843 if ( m_xAggregateSet.is() ) 844 m_xAggregateSet->setPropertyValue( PROPERTY_STRINGITEMLIST, makeAny( getStringItemList() ) ); 845 } 846 847 //-------------------------------------------------------------------- 848 void OComboBoxModel::connectedExternalListSource( ) 849 { 850 // TODO? 851 } 852 853 //-------------------------------------------------------------------- 854 void OComboBoxModel::disconnectedExternalListSource( ) 855 { 856 // TODO? 857 } 858 859 //-------------------------------------------------------------------- 860 void OComboBoxModel::refreshInternalEntryList() 861 { 862 DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::refreshInternalEntryList: invalid call!" ); 863 864 if ( !hasExternalListSource( ) 865 && ( m_eListSourceType != ListSourceType_VALUELIST ) 866 && ( m_xCursor.is() ) 867 ) 868 { 869 loadData( true ); 870 } 871 } 872 873 //-------------------------------------------------------------------- 874 void SAL_CALL OComboBoxModel::disposing( const EventObject& _rSource ) throw ( RuntimeException ) 875 { 876 if ( !OEntryListHelper::handleDisposing( _rSource ) ) 877 OBoundControlModel::disposing( _rSource ); 878 } 879 880 //======================================================================== 881 //= OComboBoxControl 882 //======================================================================== 883 884 //------------------------------------------------------------------ 885 InterfaceRef SAL_CALL OComboBoxControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) throw (RuntimeException) 886 { 887 return *(new OComboBoxControl(_rxFactory)); 888 } 889 890 //------------------------------------------------------------------------------ 891 OComboBoxControl::OComboBoxControl(const Reference<XMultiServiceFactory>& _rxFactory) 892 :OBoundControl(_rxFactory, VCL_CONTROL_COMBOBOX) 893 { 894 } 895 896 //------------------------------------------------------------------------------ 897 StringSequence SAL_CALL OComboBoxControl::getSupportedServiceNames() throw(RuntimeException) 898 { 899 StringSequence aSupported = OBoundControl::getSupportedServiceNames(); 900 aSupported.realloc(aSupported.getLength() + 1); 901 902 ::rtl::OUString* pArray = aSupported.getArray(); 903 pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_COMBOBOX; 904 return aSupported; 905 } 906 907 //......................................................................... 908 } 909 //......................................................................... 910 911