bump product version to 5.0.4.1
[LibreOffice.git] / forms / source / component / ComboBox.cxx
blob654d962b49a9937e97d180748a7a3537b4146753
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "ComboBox.hxx"
22 #include "property.hxx"
23 #include "property.hrc"
24 #include "services.hxx"
26 #include "frm_resource.hxx"
27 #include "frm_resource.hrc"
28 #include "BaseListBox.hxx"
30 #include <com/sun/star/sdb/SQLErrorEvent.hpp>
31 #include <com/sun/star/sdbc/XRowSet.hpp>
32 #include <com/sun/star/sdbc/DataType.hpp>
33 #include <com/sun/star/container/XIndexAccess.hpp>
34 #include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
35 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
36 #include <com/sun/star/util/NumberFormat.hpp>
37 #include <com/sun/star/sdbc/XConnection.hpp>
38 #include <com/sun/star/sdb/SQLContext.hpp>
39 #include <com/sun/star/sdb/CommandType.hpp>
41 #include <comphelper/numbers.hxx>
42 #include <comphelper/basicio.hxx>
43 #include <comphelper/processfactory.hxx>
44 #include <connectivity/dbtools.hxx>
45 #include <connectivity/dbconversion.hxx>
46 #include <cppuhelper/queryinterface.hxx>
47 #include <rtl/ustrbuf.hxx>
48 #include <tools/debug.hxx>
49 #include <tools/diagnose_ex.h>
50 #include <unotools/sharedunocomponent.hxx>
52 #include <limits.h>
54 using namespace dbtools;
57 namespace frm
59 using namespace ::com::sun::star::uno;
60 using namespace ::com::sun::star::sdb;
61 using namespace ::com::sun::star::sdbc;
62 using namespace ::com::sun::star::sdbcx;
63 using namespace ::com::sun::star::beans;
64 using namespace ::com::sun::star::container;
65 using namespace ::com::sun::star::form;
66 using namespace ::com::sun::star::awt;
67 using namespace ::com::sun::star::io;
68 using namespace ::com::sun::star::lang;
69 using namespace ::com::sun::star::util;
70 using namespace ::com::sun::star::form::binding;
73 // class OComboBoxModel
74 Sequence<Type> OComboBoxModel::_getTypes()
76 return ::comphelper::concatSequences(
77 OBoundControlModel::_getTypes(),
78 OEntryListHelper::getTypes(),
79 OErrorBroadcaster::getTypes()
83 // XServiceInfo
85 StringSequence SAL_CALL OComboBoxModel::getSupportedServiceNames() throw(RuntimeException, std::exception)
87 StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();
89 sal_Int32 nOldLen = aSupported.getLength();
90 aSupported.realloc( nOldLen + 9 );
91 OUString* pStoreTo = aSupported.getArray() + nOldLen;
93 *pStoreTo++ = BINDABLE_CONTROL_MODEL;
94 *pStoreTo++ = DATA_AWARE_CONTROL_MODEL;
95 *pStoreTo++ = VALIDATABLE_CONTROL_MODEL;
97 *pStoreTo++ = BINDABLE_DATA_AWARE_CONTROL_MODEL;
98 *pStoreTo++ = VALIDATABLE_BINDABLE_CONTROL_MODEL;
100 *pStoreTo++ = FRM_SUN_COMPONENT_COMBOBOX;
101 *pStoreTo++ = FRM_SUN_COMPONENT_DATABASE_COMBOBOX;
102 *pStoreTo++ = BINDABLE_DATABASE_COMBO_BOX;
104 *pStoreTo++ = FRM_COMPONENT_COMBOBOX;
106 return aSupported;
110 Any SAL_CALL OComboBoxModel::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
112 Any aReturn = OBoundControlModel::queryAggregation( _rType );
113 if ( !aReturn.hasValue() )
114 aReturn = OEntryListHelper::queryInterface( _rType );
115 if ( !aReturn.hasValue() )
116 aReturn = OErrorBroadcaster::queryInterface( _rType );
117 return aReturn;
122 OComboBoxModel::OComboBoxModel(const Reference<XComponentContext>& _rxFactory)
123 :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_COMBOBOX, FRM_SUN_CONTROL_COMBOBOX, true, true, true )
124 // use the old control name for compatibility reasons
125 ,OEntryListHelper( (OControlModel&)*this )
126 ,OErrorBroadcaster( OComponentHelper::rBHelper )
127 ,m_aListRowSet()
128 ,m_eListSourceType(ListSourceType_TABLE)
129 ,m_bEmptyIsNull(true)
131 m_nClassId = FormComponentType::COMBOBOX;
132 initValueProperty( PROPERTY_TEXT, PROPERTY_ID_TEXT );
136 OComboBoxModel::OComboBoxModel( const OComboBoxModel* _pOriginal, const Reference<XComponentContext>& _rxFactory )
137 :OBoundControlModel( _pOriginal, _rxFactory )
138 ,OEntryListHelper( *_pOriginal, (OControlModel&)*this )
139 ,OErrorBroadcaster( OComponentHelper::rBHelper )
140 ,m_aListRowSet()
141 ,m_aListSource( _pOriginal->m_aListSource )
142 ,m_aDefaultText( _pOriginal->m_aDefaultText )
143 ,m_eListSourceType( _pOriginal->m_eListSourceType )
144 ,m_bEmptyIsNull( _pOriginal->m_bEmptyIsNull )
149 OComboBoxModel::~OComboBoxModel()
151 if (!OComponentHelper::rBHelper.bDisposed)
153 acquire();
154 dispose();
159 // XCloneable
161 IMPLEMENT_DEFAULT_CLONING( OComboBoxModel )
164 void OComboBoxModel::disposing()
166 OBoundControlModel::disposing();
167 OEntryListHelper::disposing();
168 OErrorBroadcaster::disposing();
169 m_xFormatter = NULL;
173 void OComboBoxModel::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
175 switch (_nHandle)
177 case PROPERTY_ID_LISTSOURCETYPE:
178 _rValue <<= m_eListSourceType;
179 break;
181 case PROPERTY_ID_LISTSOURCE:
182 _rValue <<= m_aListSource;
183 break;
185 case PROPERTY_ID_EMPTY_IS_NULL:
186 _rValue <<= m_bEmptyIsNull;
187 break;
189 case PROPERTY_ID_DEFAULT_TEXT:
190 _rValue <<= m_aDefaultText;
191 break;
193 case PROPERTY_ID_STRINGITEMLIST:
194 _rValue <<= getStringItemList();
195 break;
197 default:
198 OBoundControlModel::getFastPropertyValue(_rValue, _nHandle);
203 void OComboBoxModel::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
204 throw (Exception, std::exception)
206 switch (_nHandle)
208 case PROPERTY_ID_LISTSOURCETYPE :
209 DBG_ASSERT(_rValue.getValueType().equals(::cppu::UnoType<ListSourceType>::get()),
210 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
211 _rValue >>= m_eListSourceType;
212 break;
214 case PROPERTY_ID_LISTSOURCE :
215 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING,
216 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
217 _rValue >>= m_aListSource;
218 // The ListSource has changed -> reload
219 if (ListSourceType_VALUELIST != m_eListSourceType)
221 if ( m_xCursor.is() && !hasField() && !hasExternalListSource() )
222 // combo box is already connected to a database, and no external list source
223 // data source changed -> refresh
224 loadData( false );
226 break;
228 case PROPERTY_ID_EMPTY_IS_NULL :
229 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN,
230 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
231 _rValue >>= m_bEmptyIsNull;
232 break;
234 case PROPERTY_ID_DEFAULT_TEXT :
235 DBG_ASSERT(_rValue.getValueType().getTypeClass() == TypeClass_STRING,
236 "OComboBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" );
237 _rValue >>= m_aDefaultText;
238 resetNoBroadcast();
239 break;
241 case PROPERTY_ID_STRINGITEMLIST:
243 ControlModelLock aLock( *this );
244 setNewStringItemList( _rValue, aLock );
245 // FIXME: this is bogus. setNewStringItemList expects a guard which has the *only*
246 // lock to the mutex, but setFastPropertyValue_NoBroadcast is already called with
247 // a lock - so we effectively has two locks here, of which setNewStringItemList can
248 // only control one.
250 break;
252 default:
253 OBoundControlModel::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
258 sal_Bool OComboBoxModel::convertFastPropertyValue(
259 Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue)
260 throw (IllegalArgumentException)
262 bool bModified(false);
263 switch (_nHandle)
265 case PROPERTY_ID_LISTSOURCETYPE :
266 bModified = tryPropertyValueEnum(_rConvertedValue, _rOldValue, _rValue, m_eListSourceType);
267 break;
269 case PROPERTY_ID_LISTSOURCE :
270 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aListSource);
271 break;
273 case PROPERTY_ID_EMPTY_IS_NULL :
274 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_bEmptyIsNull);
275 break;
277 case PROPERTY_ID_DEFAULT_TEXT :
278 bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultText);
279 break;
281 case PROPERTY_ID_STRINGITEMLIST:
282 bModified = convertNewListSourceProperty( _rConvertedValue, _rOldValue, _rValue );
283 break;
285 default:
286 bModified = OBoundControlModel::convertFastPropertyValue(_rConvertedValue, _rOldValue, _nHandle, _rValue);
287 break;
289 return bModified;
293 void OComboBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const
295 BEGIN_DESCRIBE_PROPERTIES( 6, OBoundControlModel )
296 DECL_PROP1(TABINDEX, sal_Int16, BOUND);
297 DECL_PROP1(LISTSOURCETYPE, ListSourceType, BOUND);
298 DECL_PROP1(LISTSOURCE, OUString, BOUND);
299 DECL_BOOL_PROP1(EMPTY_IS_NULL, BOUND);
300 DECL_PROP1(DEFAULT_TEXT, OUString, BOUND);
301 DECL_PROP1(STRINGITEMLIST, Sequence< OUString >,BOUND);
302 END_DESCRIBE_PROPERTIES();
306 void OComboBoxModel::describeAggregateProperties( Sequence< Property >& _rAggregateProps ) const
308 OBoundControlModel::describeAggregateProperties( _rAggregateProps );
310 // superseded properties:
311 RemoveProperty( _rAggregateProps, PROPERTY_STRINGITEMLIST );
315 OUString SAL_CALL OComboBoxModel::getServiceName() throw(RuntimeException, std::exception)
317 return OUString(FRM_COMPONENT_COMBOBOX); // old (non-sun) name for compatibility !
321 void SAL_CALL OComboBoxModel::write(const Reference<css::io::XObjectOutputStream>& _rxOutStream)
322 throw(css::io::IOException, RuntimeException, std::exception)
324 OBoundControlModel::write(_rxOutStream);
326 // Version
327 // Version 0x0002: EmptyIsNull
328 // Version 0x0003: ListSource->Seq
329 // Version 0x0004: DefaultText
330 // Version 0x0005: HelpText
331 _rxOutStream->writeShort(0x0006);
333 // Mask for Any
334 sal_uInt16 nAnyMask = 0;
335 if (m_aBoundColumn.getValueType().getTypeClass() == TypeClass_SHORT)
336 nAnyMask |= BOUNDCOLUMN;
337 _rxOutStream << nAnyMask;
339 StringSequence aListSourceSeq(&m_aListSource, 1);
340 _rxOutStream << aListSourceSeq;
341 _rxOutStream << (sal_Int16)m_eListSourceType;
343 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
345 sal_Int16 nBoundColumn = 0;
346 m_aBoundColumn >>= nBoundColumn;
347 _rxOutStream << nBoundColumn;
350 _rxOutStream << m_bEmptyIsNull;
351 _rxOutStream << m_aDefaultText;
352 writeHelpTextCompatibly(_rxOutStream);
354 // from version 0x0006 : common properties
355 writeCommonProperties(_rxOutStream);
359 void SAL_CALL OComboBoxModel::read(const Reference<css::io::XObjectInputStream>& _rxInStream) throw(css::io::IOException, RuntimeException, std::exception)
361 OBoundControlModel::read(_rxInStream);
362 ControlModelLock aLock( *this );
364 // since we are "overwriting" the StringItemList of our aggregate (means we have
365 // an own place to store the value, instead of relying on our aggregate storing it),
366 // we need to respect what the aggregate just read for the StringItemList property.
369 if ( m_xAggregateSet.is() )
370 setNewStringItemList( m_xAggregateSet->getPropertyValue( PROPERTY_STRINGITEMLIST ), aLock );
372 catch( const Exception& )
374 OSL_FAIL( "OComboBoxModel::read: caught an exception while examining the aggregate's string item list!" );
377 // Version
378 sal_uInt16 nVersion = _rxInStream->readShort();
379 DBG_ASSERT(nVersion > 0, "OComboBoxModel::read : version 0 ? this should never have been written !");
381 if (nVersion > 0x0006)
383 OSL_FAIL("OComboBoxModel::read : invalid (means unknown) version !");
384 m_aListSource.clear();
385 m_aBoundColumn <<= (sal_Int16)0;
386 m_aDefaultText.clear();
387 m_eListSourceType = ListSourceType_TABLE;
388 m_bEmptyIsNull = true;
389 defaultCommonProperties();
390 return;
393 // Mask for Any
394 sal_uInt16 nAnyMask;
395 _rxInStream >> nAnyMask;
397 // ListSource
398 if (nVersion < 0x0003)
400 _rxInStream >> m_aListSource;
402 else // nVersion == 4
404 m_aListSource.clear();
405 StringSequence aListSource;
406 _rxInStream >> aListSource;
407 const OUString* pToken = aListSource.getConstArray();
408 sal_Int32 nLen = aListSource.getLength();
409 for (sal_Int32 i = 0; i < nLen; ++i, ++pToken)
410 m_aListSource += *pToken;
413 sal_Int16 nListSourceType;
414 _rxInStream >> nListSourceType;
415 m_eListSourceType = (ListSourceType)nListSourceType;
417 if ((nAnyMask & BOUNDCOLUMN) == BOUNDCOLUMN)
419 sal_Int16 nValue;
420 _rxInStream >> nValue;
421 m_aBoundColumn <<= nValue;
424 if (nVersion > 0x0001)
426 bool bNull;
427 _rxInStream >> bNull;
428 m_bEmptyIsNull = bNull;
431 if (nVersion > 0x0003) // nVersion == 4
432 _rxInStream >> m_aDefaultText;
434 // StringList must be emptied if a ListSource is set.
435 // This can be the case if we save in alive mode.
436 if ( !m_aListSource.isEmpty()
437 && !hasExternalListSource()
440 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( StringSequence() ) );
443 if (nVersion > 0x0004)
444 readHelpTextCompatibly(_rxInStream);
446 if (nVersion > 0x0005)
447 readCommonProperties(_rxInStream);
449 // After reading in, display the default values
450 if ( !getControlSource().isEmpty() )
452 // (not if we don't have a control source - the "State" property acts like it is persistent, then
453 resetNoBroadcast();
458 void OComboBoxModel::loadData( bool _bForce )
460 DBG_ASSERT(m_eListSourceType != ListSourceType_VALUELIST, "OComboBoxModel::loadData : do not call for a value list !");
461 DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::loadData: cannot load from DB when I have an external list source!" );
463 if ( hasExternalListSource() )
464 return;
466 // Get Connection
467 Reference<XRowSet> xForm(m_xCursor, UNO_QUERY);
468 if (!xForm.is())
469 return;
470 Reference<XConnection> xConnection = getConnection(xForm);
471 if (!xConnection.is())
472 return;
474 Reference<XServiceInfo> xServiceInfo(xConnection, UNO_QUERY);
475 if (!xServiceInfo.is() || !xServiceInfo->supportsService(SRV_SDB_CONNECTION))
477 OSL_FAIL("OComboBoxModel::loadData : invalid connection !");
478 return;
481 if (m_aListSource.isEmpty() || m_eListSourceType == ListSourceType_VALUELIST)
482 return;
484 ::utl::SharedUNOComponent< XResultSet > xListCursor;
487 m_aListRowSet.setConnection( xConnection );
489 bool bExecuteRowSet( false );
490 switch (m_eListSourceType)
492 case ListSourceType_TABLEFIELDS:
493 // don't work with a statement here, the fields will be collected below
494 break;
495 case ListSourceType_TABLE:
497 // does the bound field belong to the table ?
498 // if we use an alias for the bound field, we won't find it
499 // in that case we use the first field of the table
501 Reference<XNameAccess> xFieldsByName = getTableFields(xConnection, m_aListSource);
502 Reference<XIndexAccess> xFieldsByIndex(xFieldsByName, UNO_QUERY);
504 OUString aFieldName;
505 if ( xFieldsByName.is() && xFieldsByName->hasByName( getControlSource() ) )
507 aFieldName = getControlSource();
509 else
511 // otherwise look for the alias
512 Reference<XPropertySet> xFormProp(xForm,UNO_QUERY);
513 Reference< XColumnsSupplier > xSupplyFields;
514 xFormProp->getPropertyValue("SingleSelectQueryComposer") >>= xSupplyFields;
516 // search the field
517 DBG_ASSERT(xSupplyFields.is(), "OComboBoxModel::loadData : invalid query composer !");
519 Reference< XNameAccess > xFieldNames = xSupplyFields->getColumns();
520 if ( xFieldNames->hasByName( getControlSource() ) )
522 Reference< XPropertySet > xComposerFieldAsSet;
523 xFieldNames->getByName( getControlSource() ) >>= xComposerFieldAsSet;
524 if (hasProperty(PROPERTY_FIELDSOURCE, xComposerFieldAsSet))
525 xComposerFieldAsSet->getPropertyValue(PROPERTY_FIELDSOURCE) >>= aFieldName;
529 if (aFieldName.isEmpty())
530 break;
532 Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
533 OSL_ENSURE(xMeta.is(),"No database meta data!");
534 if ( xMeta.is() )
536 OUString aQuote = xMeta->getIdentifierQuoteString();
538 OUString sCatalog, sSchema, sTable;
539 qualifiedNameComponents( xMeta, m_aListSource, sCatalog, sSchema, sTable, eInDataManipulation );
541 OUStringBuffer aStatement;
542 aStatement.appendAscii( "SELECT DISTINCT " );
543 aStatement.append ( quoteName( aQuote, aFieldName ) );
544 aStatement.appendAscii( " FROM " );
545 aStatement.append ( composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable ) );
547 m_aListRowSet.setEscapeProcessing( false );
548 m_aListRowSet.setCommand( aStatement.makeStringAndClear() );
549 bExecuteRowSet = true;
551 } break;
552 case ListSourceType_QUERY:
554 m_aListRowSet.setCommandFromQuery( m_aListSource );
555 bExecuteRowSet = true;
557 break;
559 default:
561 m_aListRowSet.setEscapeProcessing( ListSourceType_SQLPASSTHROUGH != m_eListSourceType );
562 m_aListRowSet.setCommand( m_aListSource );
563 bExecuteRowSet = true;
567 if ( bExecuteRowSet )
569 if ( !_bForce && !m_aListRowSet.isDirty() )
571 // if none of the settings of the row set changed, compared to the last
572 // invocation of loadData, then don't re-fill the list. Instead, assume
573 // the list entries are the same.
574 return;
576 xListCursor.reset( m_aListRowSet.execute() );
579 catch(const SQLException& eSQL)
581 onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
582 return;
584 catch( const Exception& )
586 DBG_UNHANDLED_EXCEPTION();
587 return;
590 ::std::vector< OUString > aStringList;
591 aStringList.reserve(16);
594 OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ),
595 "OComboBoxModel::loadData: logic error!" );
596 if ( !xListCursor.is() && ( ListSourceType_TABLEFIELDS != m_eListSourceType ) )
597 return;
599 switch (m_eListSourceType)
601 case ListSourceType_SQL:
602 case ListSourceType_SQLPASSTHROUGH:
603 case ListSourceType_TABLE:
604 case ListSourceType_QUERY:
606 // The XDatabaseVariant of the first column
607 Reference<XColumnsSupplier> xSupplyCols(xListCursor, UNO_QUERY);
608 DBG_ASSERT(xSupplyCols.is(), "OComboBoxModel::loadData : cursor supports the row set service but is no column supplier?!");
609 Reference<XIndexAccess> xColumns;
610 if (xSupplyCols.is())
612 xColumns = Reference<XIndexAccess>(xSupplyCols->getColumns(), UNO_QUERY);
613 DBG_ASSERT(xColumns.is(), "OComboBoxModel::loadData : no columns supplied by the row set !");
615 Reference< XPropertySet > xDataField;
616 if ( xColumns.is() )
617 xColumns->getByIndex(0) >>= xDataField;
618 if ( !xDataField.is() )
619 return;
621 ::dbtools::FormattedColumnValue aValueFormatter( getContext(), xForm, xDataField );
623 // Fill Lists
624 sal_Int16 i = 0;
625 // At the moment by definition the list cursor is positioned _before_ the first row
626 while (xListCursor->next() && (i++<SHRT_MAX)) // Set max. count
628 aStringList.push_back( aValueFormatter.getFormattedValue() );
631 break;
632 case ListSourceType_TABLEFIELDS:
634 Reference<XNameAccess> xFieldNames = getTableFields(xConnection, m_aListSource);
635 if (xFieldNames.is())
637 StringSequence seqNames = xFieldNames->getElementNames();
638 sal_Int32 nFieldsCount = seqNames.getLength();
639 const OUString* pustrNames = seqNames.getConstArray();
641 for (sal_Int32 k=0; k<nFieldsCount; ++k)
642 aStringList.push_back(pustrNames[k]);
645 break;
646 default:
647 OSL_FAIL( "OComboBoxModel::loadData: unreachable!" );
648 break;
651 catch(const SQLException& eSQL)
653 onError(eSQL, FRM_RES_STRING(RID_BASELISTBOX_ERROR_FILLLIST));
654 return;
656 catch( const Exception& )
658 DBG_UNHANDLED_EXCEPTION();
659 return;
662 // Create StringSequence for ListBox
663 StringSequence aStringSeq(aStringList.size());
664 OUString* pStringAry = aStringSeq.getArray();
665 for (sal_Int32 i = 0; i<aStringSeq.getLength(); ++i)
666 pStringAry[i] = aStringList[i];
668 // Set String-Sequence at ListBox
669 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( aStringSeq ) );
673 void OComboBoxModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm )
675 Reference<XPropertySet> xField = getField();
676 if ( xField.is() )
677 m_pValueFormatter.reset( new ::dbtools::FormattedColumnValue( getContext(), Reference< XRowSet >( _rxForm, UNO_QUERY ), xField ) );
678 getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= m_aDesignModeStringItems;
680 // Only load data if a ListSource was supplied
681 if ( !m_aListSource.isEmpty() && m_xCursor.is() && !hasExternalListSource() )
682 loadData( false );
686 void OComboBoxModel::onDisconnectedDbColumn()
688 m_pValueFormatter.reset();
690 // reset the string item list
691 if ( !hasExternalListSource() )
692 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( m_aDesignModeStringItems ) );
694 m_aListRowSet.dispose();
698 void SAL_CALL OComboBoxModel::reloaded( const EventObject& aEvent ) throw(RuntimeException, std::exception)
700 OBoundControlModel::reloaded(aEvent);
702 // reload data if we have a list source
703 if ( !m_aListSource.isEmpty() && m_xCursor.is() && !hasExternalListSource() )
704 loadData( false );
708 void OComboBoxModel::resetNoBroadcast()
710 OBoundControlModel::resetNoBroadcast();
711 m_aLastKnownValue.clear();
715 bool OComboBoxModel::commitControlValueToDbColumn( bool _bPostReset )
717 Any aNewValue( m_xAggregateFastSet->getFastPropertyValue( getValuePropertyAggHandle() ) );
719 OUString sNewValue;
720 aNewValue >>= sNewValue;
722 bool bModified = ( aNewValue != m_aLastKnownValue );
723 if ( bModified )
725 if ( !aNewValue.hasValue()
726 || ( sNewValue.isEmpty() // an empty string
727 && m_bEmptyIsNull // which should be interpreted as NULL
731 m_xColumnUpdate->updateNull();
733 else
737 OSL_PRECOND( m_pValueFormatter.get(), "OComboBoxModel::commitControlValueToDbColumn: no value formatter!" );
738 if ( m_pValueFormatter.get() )
740 if ( !m_pValueFormatter->setFormattedValue( sNewValue ) )
741 return false;
743 else
744 m_xColumnUpdate->updateString( sNewValue );
746 catch ( const Exception& )
748 return false;
752 m_aLastKnownValue = aNewValue;
755 // add the new value to the list
756 bool bAddToList = bModified && !_bPostReset;
757 // (only if this is not the "commit" triggered by a "reset")
759 if ( bAddToList )
761 StringSequence aStringItemList;
762 if ( getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aStringItemList )
764 const OUString* pStringItems = aStringItemList.getConstArray();
765 sal_Int32 i;
766 for (i=0; i<aStringItemList.getLength(); ++i, ++pStringItems)
768 if ( pStringItems->equals( sNewValue ) )
769 break;
772 // not found -> add
773 if (i >= aStringItemList.getLength())
775 sal_Int32 nOldLen = aStringItemList.getLength();
776 aStringItemList.realloc( nOldLen + 1 );
777 aStringItemList.getArray()[ nOldLen ] = sNewValue;
779 setFastPropertyValue( PROPERTY_ID_STRINGITEMLIST, makeAny( aStringItemList ) );
784 return true;
787 // XPropertiesChangeListener
789 Any OComboBoxModel::translateDbColumnToControlValue()
791 OSL_PRECOND( m_pValueFormatter.get(), "OComboBoxModel::translateDbColumnToControlValue: no value formatter!" );
792 if ( m_pValueFormatter.get() )
794 OUString sValue( m_pValueFormatter->getFormattedValue() );
795 if ( sValue.isEmpty()
796 && m_pValueFormatter->getColumn().is()
797 && m_pValueFormatter->getColumn()->wasNull()
800 m_aLastKnownValue.clear();
802 else
805 m_aLastKnownValue <<= sValue;
808 else
809 m_aLastKnownValue.clear();
811 return m_aLastKnownValue.hasValue() ? m_aLastKnownValue : makeAny( OUString() );
812 // (m_aLastKnownValue is alllowed to be VOID, the control value isn't)
816 Any OComboBoxModel::getDefaultForReset() const
818 return makeAny( m_aDefaultText );
822 void OComboBoxModel::stringItemListChanged( ControlModelLock& /*_rInstanceLock*/ )
824 if ( m_xAggregateSet.is() )
825 m_xAggregateSet->setPropertyValue( PROPERTY_STRINGITEMLIST, makeAny( getStringItemList() ) );
829 void OComboBoxModel::connectedExternalListSource( )
831 // TODO?
835 void OComboBoxModel::disconnectedExternalListSource( )
837 // TODO?
841 void OComboBoxModel::refreshInternalEntryList()
843 DBG_ASSERT( !hasExternalListSource(), "OComboBoxModel::refreshInternalEntryList: invalid call!" );
845 if ( !hasExternalListSource( )
846 && ( m_eListSourceType != ListSourceType_VALUELIST )
847 && ( m_xCursor.is() )
850 loadData( true );
855 void SAL_CALL OComboBoxModel::disposing( const EventObject& _rSource ) throw ( RuntimeException, std::exception )
857 if ( !OEntryListHelper::handleDisposing( _rSource ) )
858 OBoundControlModel::disposing( _rSource );
862 //= OComboBoxControl
864 OComboBoxControl::OComboBoxControl(const Reference<XComponentContext>& _rxContext)
865 :OBoundControl(_rxContext, VCL_CONTROL_COMBOBOX)
870 StringSequence SAL_CALL OComboBoxControl::getSupportedServiceNames() throw(RuntimeException, std::exception)
872 StringSequence aSupported = OBoundControl::getSupportedServiceNames();
873 aSupported.realloc(aSupported.getLength() + 2);
875 OUString* pArray = aSupported.getArray();
876 pArray[aSupported.getLength()-2] = FRM_SUN_CONTROL_COMBOBOX;
877 pArray[aSupported.getLength()-1] = STARDIV_ONE_FORM_CONTROL_COMBOBOX;
878 return aSupported;
883 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
884 com_sun_star_form_OComboBoxModel_get_implementation(::com::sun::star::uno::XComponentContext* component,
885 ::com::sun::star::uno::Sequence<css::uno::Any> const &)
887 return cppu::acquire(new frm::OComboBoxModel(component));
890 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
891 com_sun_star_form_OComboBoxControl_get_implementation(::com::sun::star::uno::XComponentContext* component,
892 ::com::sun::star::uno::Sequence<css::uno::Any> const &)
894 return cppu::acquire(new frm::OComboBoxControl(component));
897 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */