extensions/source/propctrlr/formcomponenthandler.cxx | 9 forms/source/component/ListBox.cxx | 292 +++++++++-- forms/source/component/ListBox.hxx | 63 ++ forms/source/inc/FormComponent.hxx | 4 forms/source/inc/frm_strings.hxx | 2 forms/source/inc/property.hrc | 6 forms/source/misc/property.cxx | 2 offapi/com/sun/star/form/binding/BindableDatabaseListBox.idl | 21 offapi/com/sun/star/form/component/DatabaseListBox.idl | 37 - offapi/com/sun/star/form/component/ListBox.idl | 3 10 files changed, 371 insertions(+), 68 deletions(-)
New commits: commit 6099811d666ddaf1d9f445891096f97ab53175cc Author: Lionel Elie Mamane <[email protected]> Date: Mon Apr 22 17:40:01 2013 +0200 Data-aware ListBox: document changes & improve documentation Change-Id: If75a2e86654ffef71e37cf55c24af721182215d7 diff --git a/offapi/com/sun/star/form/component/DatabaseListBox.idl b/offapi/com/sun/star/form/component/DatabaseListBox.idl index d007021..ba6e171 100644 --- a/offapi/com/sun/star/form/component/DatabaseListBox.idl +++ b/offapi/com/sun/star/form/component/DatabaseListBox.idl @@ -33,8 +33,11 @@ /** This service specifies a data-aware list box control model. <p>The base service for list boxes (<type>ListBox</type>) offers only - one possibility to specify the list entries: the <member>ListBox::ListSource</member> - property, which contains all the strings to be displayed.</p> + one possibility to specify the list entries: + The display strings in the + <member scope="com::sun::star::awt">UnoControlListBoxModel::StringItemList</member> + property and the corresponding values in the <member>ListBox::ListSource</member> + property.</p> <p>This service here extends this mimic. It allows to fill the list from a data source. This means that a second result set is opened, which works on the same connection as the @@ -54,6 +57,8 @@ pure numbers.<br/> Let's call this result set the list is filled from the <em>list result set</em> here ...</p> + <p>The display strings are always taken from the first column of that result set, + and the corresponding value as per the BoundColumn property.</p> */ published service DatabaseListBox { @@ -134,6 +139,14 @@ published service DatabaseListBox */ [property] com::sun::star::form::ListSourceType ListSourceType; + /** The selected values. + */ + [property, transient, optional] sequence< any > SelectedValues; + + /** The selected value, if there is at most one. + */ + [property, transient, optional] any SelectedValue; + }; diff --git a/offapi/com/sun/star/form/component/ListBox.idl b/offapi/com/sun/star/form/component/ListBox.idl index 21f954b..7219999 100644 --- a/offapi/com/sun/star/form/component/ListBox.idl +++ b/offapi/com/sun/star/form/component/ListBox.idl @@ -55,7 +55,8 @@ published service ListBox [property] sequence<short> DefaultSelection; - /** contains the listbox entries. + /** contains the values associated to the strings to be displayed + (which are specified by <member scope="com::sun::star::awt">UnoControlListBoxModel::StringItemList</member>) */ [property] sequence<string> ListSource; commit 567a4fcf02bee6e989ddefcff81ad186b1a02eea Author: Lionel Elie Mamane <[email protected]> Date: Mon Apr 22 17:37:17 2013 +0200 Data-aware bindable ListBox new feature: bind *value* As opposed to index in list or *display* string Change-Id: I5fa74c80b28db843d45ee68523a4349ba44d229b diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index 2ea90a9..8771869 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -1246,8 +1246,10 @@ namespace frm { eIndexList, /// as list of indexes of selected entries eIndex, /// as index of the selected entry - eEntryList, /// as list of string representations of selected entries - eEntry /// as string representation of the selected entry + eEntryList, /// as list of string representations of selected *display* entries + eEntry, /// as string representation of the selected *display* entry + eValueList, /// as list of string representations of selected values + eValue /// as string representation of the selected value }; //-------------------------------------------------------------------- @@ -1255,6 +1257,8 @@ namespace frm { switch ( _rExchangeType.getTypeClass() ) { + case TypeClass_ANY: + return eValue; case TypeClass_STRING: return eEntry; case TypeClass_LONG: @@ -1264,6 +1268,8 @@ namespace frm Type aElementType = ::comphelper::getSequenceElementType( _rExchangeType ); switch ( aElementType.getTypeClass() ) { + case TypeClass_ANY: + return eValueList; case TypeClass_STRING: return eEntryList; case TypeClass_LONG: @@ -1287,6 +1293,22 @@ namespace frm switch ( lcl_getCurrentExchangeType( getExternalValueType() ) ) { + case eValueList: + { + Sequence< const Any > aExternalValues; + OSL_VERIFY( _rExternalValue >>= aExternalValues ); + aSelectIndexes = translateBindingValuesToControlValue( aExternalValues ); + } + break; + + case eValue: + { + ORowSetValue v; + v.fill(_rExternalValue); + aSelectIndexes = translateDbValueToControlValue(v); + } + break; + case eIndexList: { // unfortunately, our select sequence is a sequence<short>, while the external binding @@ -1475,6 +1497,14 @@ namespace frm Any aReturn; switch ( lcl_getCurrentExchangeType( getExternalValueType() ) ) { + case eValueList: + aReturn = getCurrentMultiValue(); + break; + + case eValue: + aReturn = getCurrentSingleValue(); + break; + case eIndexList: { // unfortunately, the select sequence is a sequence<short>, but our binding diff --git a/offapi/com/sun/star/form/binding/BindableDatabaseListBox.idl b/offapi/com/sun/star/form/binding/BindableDatabaseListBox.idl index 64acb45..4540dde 100644 --- a/offapi/com/sun/star/form/binding/BindableDatabaseListBox.idl +++ b/offapi/com/sun/star/form/binding/BindableDatabaseListBox.idl @@ -26,17 +26,28 @@ module com { module sun { module star { module form { module binding { - /** This service specifies a list box model which is data-aware and thus can be bound to a database field, and additionally supports binding to arbitrary external values. - <p>There are four possible ways how a <type>BindableDatabaseListBox</type> exchanges - values with an external binding, the following lists explains all of them. If a new binding + <p>There are six possible ways that a <type>BindableDatabaseListBox</type> exchanges + values with an external binding. If a new binding is set at a <type>BindableDatabaseListBox</type>, the types from the following list are tried in descending order: The first type supported by the binding is used for data exchange. - <ol><li><em>sequences of integers</em>: When used, the integers in the sequence will represent + <ol> + <li><em>sequences of <atom>any</atom>s</em>: + The elements in the sequence will represent + the values the selected entries of the list box + (taken from ValueList or read from BoundColumn). + In other words, the SelectedValues property.</li> + <li><em><atom>any</atom> value</em>: + The value will represent the value of the selected entry + (taken from ValueList or read from BoundColumn). + If more than one entry is selected, + <NULL/> will be transfered. + In other words, the SelectedValue property.</li> + <li><em>sequences of long integers</em>: When used, the integers in the sequence will represent the indexes of the selected entries of the list box.</li> - <li><em>integer values</em>: When used, the value will represent the index of the selected entry. + <li><em>long integer value</em>: When used, the value will represent the index of the selected entry. If no entry is selected, -1 will be transfered. If more than one entry is selected, <NULL/> will be transfered.</li> <li><em>sequences of strings</em>: When used, the strings in the sequence present the texts commit a2c54dc208278afca127c049f069b48b2a35710e Author: Lionel Elie Mamane <[email protected]> Date: Mon Apr 22 17:34:50 2013 +0200 ListBox: take care of validation (use binding value when appropriate) Change-Id: I7c2ab0e42a82baa39e1b48124cc8cf58bfa126d5 diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index 18421ab..2ea90a9 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -1513,6 +1513,13 @@ namespace frm return aReturn; } + //------------------------------------------------------------------------------ + Any OListBoxModel::translateControlValueToValidatableValue( ) const + { + OSL_PRECOND( hasValidator(), "OListBoxModel::translateControlValueToValidatableValue: no validator, so why should I?" ); + return getCurrentFormComponentValue(); + } + //-------------------------------------------------------------------- Any OListBoxModel::getCurrentSingleValue() const { @@ -1552,8 +1559,12 @@ namespace frm //-------------------------------------------------------------------- Any OListBoxModel::getCurrentFormComponentValue() const { - if ( hasValidator() ) - return OBoundControlModel::getCurrentFormComponentValue(); + { + Reference< com::sun::star::form::validation::XValidator > vtor (const_cast<OListBoxModel*>(this)->getValidator()); + Reference< XValueBinding > extBinding (const_cast<OListBoxModel*>(this)->getValueBinding()); + if ( vtor.is() && vtor == extBinding ) + return translateControlValueToExternalValue(); + } Any aCurrentValue; diff --git a/forms/source/component/ListBox.hxx b/forms/source/component/ListBox.hxx index 7b77883..fe60540 100644 --- a/forms/source/component/ListBox.hxx +++ b/forms/source/component/ListBox.hxx @@ -186,6 +186,8 @@ protected: translateExternalValueToControlValue( const ::com::sun::star::uno::Any& _rExternalValue ) const; virtual ::com::sun::star::uno::Any translateControlValueToExternalValue( ) const; + virtual ::com::sun::star::uno::Any + translateControlValueToValidatableValue( ) const; virtual sal_Bool commitControlValueToDbColumn( bool _bPostReset ); virtual void onConnectedDbColumn( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _rxForm ); diff --git a/forms/source/inc/FormComponent.hxx b/forms/source/inc/FormComponent.hxx index 69cb092..85ddf90 100644 --- a/forms/source/inc/FormComponent.hxx +++ b/forms/source/inc/FormComponent.hxx @@ -1081,7 +1081,7 @@ public: virtual void SAL_CALL reloading( const ::com::sun::star::lang::EventObject& aEvent ) throw(::com::sun::star::uno::RuntimeException); virtual void SAL_CALL reloaded( const ::com::sun::star::lang::EventObject& aEvent ) throw(::com::sun::star::uno::RuntimeException); -private: +protected: // XBindableValue virtual void SAL_CALL setValueBinding( const ::com::sun::star::uno::Reference< ::com::sun::star::form::binding::XValueBinding >& _rxBinding ) throw (::com::sun::star::form::binding::IncompatibleTypesException, ::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Reference< ::com::sun::star::form::binding::XValueBinding > SAL_CALL getValueBinding( ) throw (::com::sun::star::uno::RuntimeException); commit 1e698bb7f1614f69caa5a30df64a47d18435c89b Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 20:25:13 2013 +0200 Use (get|set)ControlValue instead of manipulating the property directly Change-Id: Ice58cf4f67fae6a26548bae6569ae0c0993a7e84 diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index 1d3848e..18421ab 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -350,7 +350,7 @@ namespace frm Sequence< const Any > v; _rValue >>= v; Any newSelectSeq(translateBindingValuesToControlValue(v)); - setPropertyValue( PROPERTY_SELECT_SEQ, newSelectSeq ); + setControlValue( newSelectSeq, eOther ); } break; @@ -359,7 +359,7 @@ namespace frm ORowSetValue v; v.fill(_rValue); Any newSelectSeq(translateDbValueToControlValue(v)); - setPropertyValue( PROPERTY_SELECT_SEQ, newSelectSeq ); + setControlValue( newSelectSeq, eOther ); } break; @@ -1470,7 +1470,7 @@ namespace frm OSL_PRECOND( hasExternalValueBinding(), "OListBoxModel::translateControlValueToExternalValue: no binding!" ); Sequence< sal_Int16 > aSelectSequence; - const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence; + OSL_VERIFY( getControlValue() >>= aSelectSequence ); Any aReturn; switch ( lcl_getCurrentExchangeType( getExternalValueType() ) ) @@ -1521,7 +1521,7 @@ namespace frm try { Sequence< sal_Int16 > aSelectSequence; - OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence ); + OSL_VERIFY( getControlValue() >>= aSelectSequence ); aCurrentValue = lcl_getSingleSelectedEntryAny( aSelectSequence, impl_getValues() ); } catch( const Exception& ) @@ -1539,7 +1539,7 @@ namespace frm try { Sequence< sal_Int16 > aSelectSequence; - OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence ); + OSL_VERIFY( getControlValue() >>= aSelectSequence ); aCurrentValue = lcl_getMultiSelectedEntriesAny( aSelectSequence, impl_getValues() ); } catch( const Exception& ) commit eb387dcf416427d8ad415cde6186796cc6f2ae4e Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 19:32:05 2013 +0200 Rephrase documentation a bit Change-Id: Icb02894c32ced62792d641bf1177bdc2b5ba184b diff --git a/offapi/com/sun/star/form/component/DatabaseListBox.idl b/offapi/com/sun/star/form/component/DatabaseListBox.idl index e77ee25..d007021 100644 --- a/offapi/com/sun/star/form/component/DatabaseListBox.idl +++ b/offapi/com/sun/star/form/component/DatabaseListBox.idl @@ -44,8 +44,8 @@ to enter invoices for your customers. Probably, you will have a second table (say <em>customer</em>), which (among other data) contains a unique key for identifying customers. In your invoice table, you will have a foreign key referring to these customers.<br/> - Now, besides the result set the form is based on (all your invoices), the list box can be caused - to open a second result set, this time for the <em>customer</em> table, and fill it's list with entries + Now, besides the result set the form is based on (all your invoices), the list box can be instructed + to open a second result set, this time for the <em>customer</em> table, and fill its list with entries from this result set.<br/> Additionally, it allows to model the relation between the two tables: When the user selects a customer from the list, this customer has the unique id we just talked about (which is not necessarily visible to the commit 1a19d124871079a80f0c93fe4478da66359de96d Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 19:21:30 2013 +0200 janitorial: alignment Change-Id: I1e061635d496c54a0c948805dac968f0fb0c67f8 diff --git a/forms/source/inc/property.hrc b/forms/source/inc/property.hrc index 4c23d21..af0ed33 100644 --- a/forms/source/inc/property.hrc +++ b/forms/source/inc/property.hrc @@ -102,7 +102,7 @@ namespace frm #define PROPERTY_ID_SUBMIT_ENCODING (PROPERTY_ID_START + 74) // FmSubmitEncoding #define PROPERTY_ID_DEFAULT_VALUE (PROPERTY_ID_START + 75) // ::rtl::OUString #define PROPERTY_ID_SUBMIT_TARGET (PROPERTY_ID_START + 76) // ::rtl::OUString -#define PROPERTY_ID_DEFAULT_STATE (PROPERTY_ID_START + 77) // UINT16 +#define PROPERTY_ID_DEFAULT_STATE (PROPERTY_ID_START + 77) // UINT16 #define PROPERTY_ID_VALUE_SEQ (PROPERTY_ID_START + 78) // StringSeq #define PROPERTY_ID_IMAGE_URL (PROPERTY_ID_START + 79) // ::rtl::OUString #define PROPERTY_ID_SELECT_VALUE (PROPERTY_ID_START + 80) // StringSeq commit a16bb08013f0ce81def57131526fbb075dd63565 Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 19:20:31 2013 +0200 Data-aware ListBox: add SelectedValue and SelectedValues properties Change-Id: Id081e4f6bb765056f17babcfec52a1aedcd7b5d5 diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index bd31454..1d3848e 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -274,6 +274,14 @@ namespace frm _rValue <<= lcl_convertToStringSequence( m_aBoundValues ); break; + case PROPERTY_ID_SELECT_VALUE_SEQ: + _rValue = getCurrentMultiValue(); + break; + + case PROPERTY_ID_SELECT_VALUE: + _rValue = getCurrentSingleValue(); + break; + case PROPERTY_ID_DEFAULT_SELECT_SEQ: _rValue <<= m_aDefaultSelectSeq; break; @@ -337,6 +345,24 @@ namespace frm OSL_FAIL( "ValueItemList is read-only!" ); throw PropertyVetoException(); + case PROPERTY_ID_SELECT_VALUE_SEQ : + { + Sequence< const Any > v; + _rValue >>= v; + Any newSelectSeq(translateBindingValuesToControlValue(v)); + setPropertyValue( PROPERTY_SELECT_SEQ, newSelectSeq ); + } + break; + + case PROPERTY_ID_SELECT_VALUE : + { + ORowSetValue v; + v.fill(_rValue); + Any newSelectSeq(translateDbValueToControlValue(v)); + setPropertyValue( PROPERTY_SELECT_SEQ, newSelectSeq ); + } + break; + case PROPERTY_ID_DEFAULT_SELECT_SEQ : DBG_ASSERT(_rValue.getValueType().equals(::getCppuType(static_cast< Sequence<sal_Int16>*>(0))), "OListBoxModel::setFastPropertyValue_NoBroadcast : invalid type !" ); @@ -388,6 +414,14 @@ namespace frm OSL_FAIL( "ValueItemList is read-only!" ); throw PropertyVetoException(); + case PROPERTY_ID_SELECT_VALUE_SEQ : + bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, getCurrentMultiValue()); + break; + + case PROPERTY_ID_SELECT_VALUE : + bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, getCurrentSingleValue()); + break; + case PROPERTY_ID_DEFAULT_SELECT_SEQ : bModified = tryPropertyValue(_rConvertedValue, _rOldValue, _rValue, m_aDefaultSelectSeq); break; @@ -441,12 +475,14 @@ namespace frm //------------------------------------------------------------------------------ void OListBoxModel::describeFixedProperties( Sequence< Property >& _rProps ) const { - BEGIN_DESCRIBE_PROPERTIES( 7, OBoundControlModel ) + BEGIN_DESCRIBE_PROPERTIES( 9, OBoundControlModel ) DECL_PROP1(TABINDEX, sal_Int16, BOUND); DECL_PROP2(BOUNDCOLUMN, sal_Int16, BOUND, MAYBEVOID); DECL_PROP1(LISTSOURCETYPE, ListSourceType, BOUND); DECL_PROP1(LISTSOURCE, StringSequence, BOUND); DECL_PROP3(VALUE_SEQ, StringSequence, BOUND, READONLY, TRANSIENT); + DECL_PROP2(SELECT_VALUE_SEQ, Sequence< Any >, BOUND, TRANSIENT); + DECL_PROP2(SELECT_VALUE, Any, BOUND, TRANSIENT); DECL_PROP1(DEFAULT_SELECT_SEQ, Sequence<sal_Int16>, BOUND); DECL_PROP1(STRINGITEMLIST, Sequence< OUString >, BOUND); END_DESCRIBE_PROPERTIES(); @@ -1078,24 +1114,13 @@ namespace frm return sal_True; } - // XPropertiesChangeListener //------------------------------------------------------------------------------ - Any OListBoxModel::translateDbColumnToControlValue() + Sequence< sal_Int16 > OListBoxModel::translateDbValueToControlValue(const ORowSetValue &i_aValue) const { - Reference< XPropertySet > xBoundField( getField() ); - if ( !xBoundField.is() ) - { - OSL_FAIL( "OListBoxModel::translateDbColumnToControlValue: no field? How could that happen?!" ); - return Any(); - } - Sequence< sal_Int16 > aSelectionIndicies; - ORowSetValue aCurrentValue; - aCurrentValue.fill( getValueType(), m_xColumn ); - // reset selection for NULL values - if ( aCurrentValue.isNull() ) + if ( i_aValue.isNull() ) { if ( m_nNULLPos != -1 ) { @@ -1106,7 +1131,10 @@ namespace frm else { ValueList aValues( impl_getValues() ); - ValueList::const_iterator curValuePos = ::std::find( aValues.begin(), aValues.end(), aCurrentValue ); + assert( m_nConvertedBoundValuesType == getValueType()); + ORowSetValue v(i_aValue); + v.setTypeKind( m_nConvertedBoundValuesType ); + ValueList::const_iterator curValuePos = ::std::find( aValues.begin(), aValues.end(), v ); if ( curValuePos != aValues.end() ) { aSelectionIndicies.realloc( 1 ); @@ -1114,9 +1142,64 @@ namespace frm } } + return aSelectionIndicies; + } + //------------------------------------------------------------------------------ + Sequence< sal_Int16 > OListBoxModel::translateBindingValuesToControlValue(const Sequence< const Any > &i_aValues) const + { + const ValueList aValues( impl_getValues() ); + assert( m_nConvertedBoundValuesType == getValueType()); + Sequence< sal_Int16 > aSelectionIndicies(i_aValues.getLength()); + sal_Int32 nCount(0); + + sal_Int16 *pIndex = aSelectionIndicies.getArray(); + const Any *pValue = i_aValues.getConstArray(); + const Any * const pValueEnd = i_aValues.getConstArray() + i_aValues.getLength(); + for (;pValue < pValueEnd; ++pValue) + { + if ( pValue->hasValue() ) + { + ORowSetValue v; + v.fill(*pValue); + v.setTypeKind( m_nConvertedBoundValuesType ); + ValueList::const_iterator curValuePos = ::std::find( aValues.begin(), aValues.end(), v ); + if ( curValuePos != aValues.end() ) + { + *pIndex = curValuePos - aValues.begin(); + ++pIndex; + ++nCount; + } + } + else + { + if ( m_nNULLPos != -1 ) + { + *pIndex = m_nNULLPos; + ++pIndex; + ++nCount; + } + } + } + assert(aSelectionIndicies.getArray() + nCount == pIndex); + aSelectionIndicies.realloc(nCount); + return aSelectionIndicies; + } + //------------------------------------------------------------------------------ + Any OListBoxModel::translateDbColumnToControlValue() + { + Reference< XPropertySet > xBoundField( getField() ); + if ( !xBoundField.is() ) + { + OSL_FAIL( "OListBoxModel::translateDbColumnToControlValue: no field? How could that happen?!" ); + return Any(); + } + + ORowSetValue aCurrentValue; + aCurrentValue.fill( getValueType(), m_xColumn ); + m_aSaveValue = aCurrentValue; - return makeAny( aSelectionIndicies ); + return makeAny( translateDbValueToControlValue(aCurrentValue) ); } // XReset @@ -1431,25 +1514,58 @@ namespace frm } //-------------------------------------------------------------------- - Any OListBoxModel::getCurrentFormComponentValue() const + Any OListBoxModel::getCurrentSingleValue() const { - if ( hasValidator() ) - return OBoundControlModel::getCurrentFormComponentValue(); + Any aCurrentValue; + try + { + Sequence< sal_Int16 > aSelectSequence; + OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence ); + aCurrentValue = lcl_getSingleSelectedEntryAny( aSelectSequence, impl_getValues() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return aCurrentValue; + } + //-------------------------------------------------------------------- + Any OListBoxModel::getCurrentMultiValue() const + { Any aCurrentValue; try { Sequence< sal_Int16 > aSelectSequence; OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_SELECT_SEQ ) >>= aSelectSequence ); + aCurrentValue = lcl_getMultiSelectedEntriesAny( aSelectSequence, impl_getValues() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return aCurrentValue; + } + //-------------------------------------------------------------------- + Any OListBoxModel::getCurrentFormComponentValue() const + { + if ( hasValidator() ) + return OBoundControlModel::getCurrentFormComponentValue(); + + Any aCurrentValue; + try + { sal_Bool bMultiSelection( sal_False ); OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection ); if ( bMultiSelection ) - aCurrentValue = lcl_getMultiSelectedEntriesAny( aSelectSequence, impl_getValues() ); + aCurrentValue = getCurrentMultiValue(); else - aCurrentValue = lcl_getSingleSelectedEntryAny( aSelectSequence, impl_getValues() ); + aCurrentValue = getCurrentSingleValue(); } catch( const Exception& ) { diff --git a/forms/source/component/ListBox.hxx b/forms/source/component/ListBox.hxx index 927befe..7b77883 100644 --- a/forms/source/component/ListBox.hxx +++ b/forms/source/component/ListBox.hxx @@ -206,7 +206,17 @@ protected: protected: DECLARE_XCLONEABLE(); + void init(); + ::com::sun::star::uno::Any getCurrentSingleValue() const; + ::com::sun::star::uno::Any getCurrentMultiValue() const; + ::com::sun::star::uno::Sequence< sal_Int16 > translateBindingValuesToControlValue( + const ::com::sun::star::uno::Sequence< const ::com::sun::star::uno::Any > &i_aValues) + const; + ::com::sun::star::uno::Sequence< sal_Int16 > translateDbValueToControlValue( + const ::connectivity::ORowSetValue &aValue) + const; + private: void loadData( bool _bForce ); diff --git a/forms/source/inc/frm_strings.hxx b/forms/source/inc/frm_strings.hxx index 3e10031..05bc7ce 100644 --- a/forms/source/inc/frm_strings.hxx +++ b/forms/source/inc/frm_strings.hxx @@ -104,6 +104,8 @@ namespace frm FORMS_CONSTASCII_STRING( PROPERTY_LISTSOURCE, "ListSource" ); FORMS_CONSTASCII_STRING( PROPERTY_SELECT_SEQ, "SelectedItems" ); FORMS_CONSTASCII_STRING( PROPERTY_VALUE_SEQ, "ValueItemList" ); + FORMS_CONSTASCII_STRING( PROPERTY_SELECT_VALUE_SEQ, "SelectedValues" ); + FORMS_CONSTASCII_STRING( PROPERTY_SELECT_VALUE, "SelectedValue" ); FORMS_CONSTASCII_STRING( PROPERTY_DEFAULT_SELECT_SEQ, "DefaultSelection" ); FORMS_CONSTASCII_STRING( PROPERTY_MULTISELECTION, "MultiSelection" ); FORMS_CONSTASCII_STRING( PROPERTY_ALIGN, "Align" ); diff --git a/forms/source/inc/property.hrc b/forms/source/inc/property.hrc index 0cb8625..4c23d21 100644 --- a/forms/source/inc/property.hrc +++ b/forms/source/inc/property.hrc @@ -105,8 +105,8 @@ namespace frm #define PROPERTY_ID_DEFAULT_STATE (PROPERTY_ID_START + 77) // UINT16 #define PROPERTY_ID_VALUE_SEQ (PROPERTY_ID_START + 78) // StringSeq #define PROPERTY_ID_IMAGE_URL (PROPERTY_ID_START + 79) // ::rtl::OUString - // free - // free +#define PROPERTY_ID_SELECT_VALUE (PROPERTY_ID_START + 80) // StringSeq +#define PROPERTY_ID_SELECT_VALUE_SEQ (PROPERTY_ID_START + 81) // StringSeq // free // free // free diff --git a/forms/source/misc/property.cxx b/forms/source/misc/property.cxx index 066b58d..63da1d5 100644 --- a/forms/source/misc/property.cxx +++ b/forms/source/misc/property.cxx @@ -127,6 +127,8 @@ void PropertyInfoService::initialize() ADD_PROP_ASSIGNMENT(LISTSOURCE); ADD_PROP_ASSIGNMENT(SELECT_SEQ); ADD_PROP_ASSIGNMENT(VALUE_SEQ); + ADD_PROP_ASSIGNMENT(SELECT_VALUE); + ADD_PROP_ASSIGNMENT(SELECT_VALUE_SEQ); ADD_PROP_ASSIGNMENT(DEFAULT_SELECT_SEQ); ADD_PROP_ASSIGNMENT(MULTISELECTION); ADD_PROP_ASSIGNMENT(DECIMAL_ACCURACY); commit 13a159896e3db1edd3f2d258bce1f9732ed8499e Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 19:16:24 2013 +0200 janitorial: typo in comment Change-Id: I5434b05a7980919773d017b5b450f5d3c2325551 diff --git a/forms/source/component/ListBox.hxx b/forms/source/component/ListBox.hxx index 2540ad8..927befe 100644 --- a/forms/source/component/ListBox.hxx +++ b/forms/source/component/ListBox.hxx @@ -198,7 +198,7 @@ protected: virtual ::com::sun::star::uno::Any getCurrentFormComponentValue() const; - // OEntryListHelper overriables + // OEntryListHelper overridables virtual void stringItemListChanged( ControlModelLock& _rInstanceLock ); virtual void connectedExternalListSource( ); virtual void disconnectedExternalListSource( ); commit f7be9c71d46310b22194461b3dae217df0e41f1e Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 15:53:12 2013 +0200 janitorial: typo in variable name Change-Id: I0bc68e7a1f589e11f16bc539f49a323e64bd834f diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index 4941918..bd31454 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -1436,7 +1436,7 @@ namespace frm if ( hasValidator() ) return OBoundControlModel::getCurrentFormComponentValue(); - Any aCurretnValue; + Any aCurrentValue; try { @@ -1447,16 +1447,16 @@ namespace frm OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection ); if ( bMultiSelection ) - aCurretnValue = lcl_getMultiSelectedEntriesAny( aSelectSequence, impl_getValues() ); + aCurrentValue = lcl_getMultiSelectedEntriesAny( aSelectSequence, impl_getValues() ); else - aCurretnValue = lcl_getSingleSelectedEntryAny( aSelectSequence, impl_getValues() ); + aCurrentValue = lcl_getSingleSelectedEntryAny( aSelectSequence, impl_getValues() ); } catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); } - return aCurretnValue; + return aCurrentValue; } //-------------------------------------------------------------------- commit 0ed5028e8e5b782d63b2d00602e7ef52f0e4d016 Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 15:46:47 2013 +0200 Note on design philosophy of data-aware ListBox Change-Id: I773c6b0704a31ab501cc51c6c7cd5e4be390a166 diff --git a/forms/source/component/ListBox.hxx b/forms/source/component/ListBox.hxx index 51cf5a8..2540ad8 100644 --- a/forms/source/component/ListBox.hxx +++ b/forms/source/component/ListBox.hxx @@ -42,6 +42,54 @@ #include <vector> +/** ListBox is a bit confusing / different from other form components, + so here are a few notes: + + The general design philosophy is that a ListBox is a mechanism + to translate back and forth between: + 1) *display* values (strings that the user sees and chooses) + 2) *binding* values, which is what the program (for a dialog), + the database, ... cares about. + + A non-data aware ListBox exposes this mechanism through + com.sun.star.awt.XItemList (get|set)ItemData. + + In a data-aware ListBox, this is naturally embodied by the + StringItemList on the one hand, and the ValueList on the other + hand (where, depending on ListSourceType, the ValueList is + possibly automatically filled from the BoundColumn of the + ListSource). + + This source file implements data-aware ListBox, and the rest + of this comment applies to data-aware ListBox (only). + + In all public APIs of the *model* (OListBoxModel), + the value of the control is the *binding* value. + That is what the bound database field gets, + that is what a validator validates, + that is what an external value binding + (com.sun.star.form.binding.XValueBinding) + exchanges with the control. + + As an *implementation* choice, we keep the current value of the + ListBox as a sequence of *indices* in the value list, and do the + lookup on demand: + + - ListBox's content propery (or value property, sorry the + terminology is not always consistent) is SelectedItems which is + a sequence of *indices* in the value list. + + - That is used to synchronise with our peer (UnoControlListBoxModel). + + In particular, note that getCurrentValue() is a public API (and + deals with bound values), but getControlValue and + (do)setControlValue are *internal* implementation helpers that + deal with *indices*. + + Note that the *view* (OListBoxControl) presents a different story + than the model. E.g. the "SelectedItems" property is *display* *values*. +*/ + //......................................................................... namespace frm { commit bfc0bf6a164f25c6e2af86fb0298ecb0f88c9df9 Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 19:40:39 2013 +0200 Data-aware ListBox: BoundValue==-1 to store index in list Change-Id: I248cd5ec62574f47a27f8b37e1e90333b8748af2 diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index 9cfdc70..4941918 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -858,6 +858,8 @@ namespace frm DBG_UNHANDLED_EXCEPTION(); } } + else if ( *aBoundColumn == -1) + m_nBoundColumnType = DataType::SMALLINT; // If the LB is bound to a field and empty entries are valid, we remember the position // for an empty entry @@ -873,6 +875,9 @@ namespace frm if(*aBoundColumn >= 0) aBoundValue.fill( *aBoundColumn + 1, m_nBoundColumnType, xCursorRow ); + else + // -1 because getRow() is 1-indexed, but ListBox positions are 0-indexed + aBoundValue = static_cast<sal_uInt16>(xListCursor->getRow()-1); aValueList.push_back( aBoundValue ); if ( bUseNULL && ( m_nNULLPos == -1 ) && aStr.isEmpty() ) diff --git a/offapi/com/sun/star/form/component/DatabaseListBox.idl b/offapi/com/sun/star/form/component/DatabaseListBox.idl index aa27e8d..e77ee25 100644 --- a/offapi/com/sun/star/form/component/DatabaseListBox.idl +++ b/offapi/com/sun/star/form/component/DatabaseListBox.idl @@ -72,13 +72,15 @@ published service DatabaseListBox <member scope="com::sun::star::form">DataAwareControlModel::DataField</member>. <dl> - <dt>0</dt> - <dd>The selected (displayed) list box string is stored in - the current database field.</dd> - - <dt>1 or greater</dt> - <dd>The column value of the result set at the position is - stored in the current database field.</dd> + <dt>-1</dt> + <dd>The index (starting at 0) of the selected list box entry + is stored in the current database field.</dd> + + <dt>0 or greater</dt> + <dd>The column value of the result set at the position + (0-indexed) is stored in the current database field. + In particular, for value 0, the selected (displayed) + list box string is stored.</dd> </dl></p> <p>The bound column property is only used if a list source is defined commit d645a6a17cd03d0f875e1246652664860d91c0c5 Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 15:45:58 2013 +0200 Data-aware ListBox: can have a BoundColumn even without bound database column It defines what goes into the ValueList property, what getCurrentValue() returns, and what an external value binding gets. Change-Id: I9242d3a6040ec98c22b1d4350942dfa0e7aa6c5b diff --git a/extensions/source/propctrlr/formcomponenthandler.cxx b/extensions/source/propctrlr/formcomponenthandler.cxx index 773a4e6..0937f14 100644 --- a/extensions/source/propctrlr/formcomponenthandler.cxx +++ b/extensions/source/propctrlr/formcomponenthandler.cxx @@ -1331,7 +1331,7 @@ namespace pcr Optional< double > aMinValue( sal_True, 0 ); Optional< double > aMaxValue( sal_True, 0x7FFFFFFF ); - if ( nPropId == PROPERTY_ID_MAXTEXTLEN ) + if ( nPropId == PROPERTY_ID_MAXTEXTLEN || nPropId == PROPERTY_ID_BOUNDCOLUMN ) aMinValue.Value = -1; else if ( nPropId == PROPERTY_ID_VISIBLESIZE ) aMinValue.Value = 1; @@ -1573,7 +1573,6 @@ namespace pcr if ( !_bFirstTimeInit && m_bHaveListSource ) // available list source values (tables or queries) might have changed _rxInspectorUI->rebuildPropertyUI( PROPERTY_LISTSOURCE ); - aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN ); aDependentProperties.push_back( PROPERTY_ID_STRINGITEMLIST ); // NO break! @@ -1837,15 +1836,11 @@ namespace pcr // ----- BoundColumn ----- case PROPERTY_ID_BOUNDCOLUMN: { - OUString sControlSource; - OSL_VERIFY( impl_getPropertyValue_throw( PROPERTY_CONTROLSOURCE ) >>= sControlSource ); - ListSourceType eLSType = ListSourceType_VALUELIST; OSL_VERIFY( impl_getPropertyValue_throw( PROPERTY_LISTSOURCETYPE ) >>= eLSType ); _rxInspectorUI->enablePropertyUI( PROPERTY_BOUNDCOLUMN, - ( !sControlSource.isEmpty() ) - && ( eLSType != ListSourceType_TABLEFIELDS ) + ( eLSType != ListSourceType_TABLEFIELDS ) && ( eLSType != ListSourceType_VALUELIST ) ); } commit 52bc6737cde524f04c9e0af7b7bc98c2030f2ff0 Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 19:43:34 2013 +0200 Data-aware ListBox: getCurrentValue should return *binding* values As opposed to display values Change-Id: I8afb52d69786702776f4e8d24390ba8ede417e92 diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index b4152bb..9cfdc70 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -1327,6 +1327,53 @@ namespace frm ); return makeAny( aSelectedEntriesTexts ); } + + //................................................................ + struct ExtractAnyFromValueList_Safe : public ::std::unary_function< sal_Int16, Any > + { + protected: + const ValueList& m_rList; + + public: + ExtractAnyFromValueList_Safe( const ValueList& _rList ) : m_rList( _rList ) { } + + Any operator ()( sal_Int16 _nIndex ) + { + OSL_ENSURE( static_cast<ValueList::size_type>(_nIndex) < m_rList.size(), "ExtractAnyFromValueList: inconsistence!" ); + if ( static_cast<ValueList::size_type>(_nIndex) < m_rList.size() ) + return m_rList[ _nIndex ].makeAny(); + return Any(); + } + }; + + //................................................................ + Any lcl_getSingleSelectedEntryAny( const Sequence< sal_Int16 >& _rSelectSequence, const ValueList& _rStringList ) + { + Any aReturn; + + // by definition, multiple selected entries are transfered as NULL if the + // binding does not support string lists + if ( _rSelectSequence.getLength() <= 1 ) + { + if ( _rSelectSequence.getLength() == 1 ) + aReturn = ExtractAnyFromValueList_Safe( _rStringList )( _rSelectSequence[0] ); + } + + return aReturn; + } + + //................................................................ + Any lcl_getMultiSelectedEntriesAny( const Sequence< sal_Int16 >& _rSelectSequence, const ValueList& _rStringList ) + { + Sequence< Any > aSelectedEntriesValues( _rSelectSequence.getLength() ); + ::std::transform( + _rSelectSequence.getConstArray(), + _rSelectSequence.getConstArray() + _rSelectSequence.getLength(), + aSelectedEntriesValues.getArray(), + ExtractAnyFromValueList_Safe( _rStringList ) + ); + return makeAny( aSelectedEntriesValues ); + } } //-------------------------------------------------------------------- @@ -1395,9 +1442,9 @@ namespace frm OSL_VERIFY( const_cast< OListBoxModel* >( this )->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection ); if ( bMultiSelection ) - aCurretnValue = lcl_getMultiSelectedEntries( aSelectSequence, getStringItemList() ); + aCurretnValue = lcl_getMultiSelectedEntriesAny( aSelectSequence, impl_getValues() ); else - aCurretnValue = lcl_getSingleSelectedEntry( aSelectSequence, getStringItemList() ); + aCurretnValue = lcl_getSingleSelectedEntryAny( aSelectSequence, impl_getValues() ); } catch( const Exception& ) { commit 3e1a0c9b2f83a44f5e7ff154d6e09d4f7b26a5e5 Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 15:41:20 2013 +0200 Data-aware ListBox: populate ValueList even without bound field Change-Id: I8742285778962b5be10f3aa300236efd525bdeb9 diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index b4df746..b4152bb 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -808,6 +808,10 @@ namespace frm ValueList aDisplayList, aValueList; sal_Bool bUseNULL = hasField() && !isRequired(); + // empty BoundColumn is treated as BoundColumn=0, + if(!aBoundColumn) + aBoundColumn = 0; + try { OSL_ENSURE( xListCursor.is() || ( ListSourceType_TABLEFIELDS == m_eListSourceType ), @@ -842,8 +846,8 @@ namespace frm // Get the field of BoundColumn of the ResultSet m_nBoundColumnType = DataType::SQLNULL; - if ( !!aBoundColumn && ( *aBoundColumn >= 0 ) && m_xColumn.is() ) - { // don't look for a bound column if we're not connected to a field + if ( *aBoundColumn >= 0 ) + { try { Reference< XPropertySet > xBoundField( xColumns->getByIndex( *aBoundColumn ), UNO_QUERY_THROW ); @@ -867,11 +871,9 @@ namespace frm aStr = aValueFormatter.getFormattedValue(); aDisplayList.push_back( aStr ); - if ( impl_hasBoundComponent() ) - { + if(*aBoundColumn >= 0) aBoundValue.fill( *aBoundColumn + 1, m_nBoundColumnType, xCursorRow ); - aValueList.push_back( aBoundValue ); - } + aValueList.push_back( aBoundValue ); if ( bUseNULL && ( m_nNULLPos == -1 ) && aStr.isEmpty() ) m_nNULLPos = sal_Int16( aDisplayList.size() - 1 ); @@ -914,8 +916,7 @@ namespace frm // Add NULL entry if (bUseNULL && m_nNULLPos == -1) { - if ( impl_hasBoundComponent() ) - aValueList.insert( aValueList.begin(), ORowSetValue() ); + aValueList.insert( aValueList.begin(), ORowSetValue() ); aDisplayList.insert( aDisplayList.begin(), ORowSetValue( OUString() ) ); m_nNULLPos = 0; commit 0202f9b7c4ddabd0d0567ad77a15617904996fec Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 08:38:05 2013 +0200 assert non-nullness of interface before use Change-Id: I467830dce80e97db1b20c6d589fb4ca407cfa26c diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index 536631b..b4df746 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -710,6 +710,7 @@ namespace frm break; Reference<XPropertySet> xFieldAsSet(xFieldsByIndex->getByIndex( *aBoundColumn ),UNO_QUERY); + assert(xFieldAsSet.is()); xFieldAsSet->getPropertyValue(PROPERTY_NAME) >>= aBoundFieldName; aBoundColumn.reset( 1 ); commit d198e7a1eb41e95bf199766205cfac9ce597e0ec Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 08:34:24 2013 +0200 janitorial: typo in comment Change-Id: Icc10f98e4153278d3e5bde33d0454675121306a7 diff --git a/forms/source/inc/FormComponent.hxx b/forms/source/inc/FormComponent.hxx index cf314a7..69cb092 100644 --- a/forms/source/inc/FormComponent.hxx +++ b/forms/source/inc/FormComponent.hxx @@ -973,7 +973,7 @@ protected: getCurrentFormComponentValue() const; /** We can't write (new) common properties in this base class, as the file format doesn't allow this - (unfortunally). So derived classes may use the following to methods. They secure the written + (unfortunally). So derived classes may use the following two methods. They secure the written data with marks, so any new common properties in newer versions will be skipped by older ones. */ void writeCommonProperties(const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream>& _rxOutStream); commit 64ef3bf0d961e775bf05cef8b16dac8974a7108a Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 08:22:26 2013 +0200 janitorial: typo in comment Change-Id: Icba805697caa6675339535b382fc4f24f86a94fb diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index e6c6bb3..536631b 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -157,7 +157,7 @@ namespace frm //------------------------------------------------------------------ OListBoxModel::OListBoxModel(const Reference<XMultiServiceFactory>& _rxFactory) :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_LISTBOX, FRM_SUN_CONTROL_LISTBOX, sal_True, sal_True, sal_True ) - // use the old control name for compytibility reasons + // use the old control name for compatibility reasons ,OEntryListHelper( (OControlModel&)*this ) ,OErrorBroadcaster( OComponentHelper::rBHelper ) ,m_aListRowSet( getContext() ) commit 24bdda09fb2312239be0a791fa71c28022a33d51 Author: Lionel Elie Mamane <[email protected]> Date: Sun Apr 21 07:59:53 2013 +0200 factorise common code Change-Id: I53ee3b7c99205046b25f437480d26e484ac2c340 diff --git a/forms/source/component/ListBox.cxx b/forms/source/component/ListBox.cxx index 5b75332..e6c6bb3 100644 --- a/forms/source/component/ListBox.cxx +++ b/forms/source/component/ListBox.cxx @@ -147,6 +147,11 @@ namespace frm ).getTypes(); } + // stuff common to all constructors + void OListBoxModel::init() + { + startAggregatePropertyListening( PROPERTY_STRINGITEMLIST ); + } DBG_NAME(OListBoxModel); //------------------------------------------------------------------ @@ -166,7 +171,7 @@ namespace frm m_aBoundColumn <<= (sal_Int16)1; initValueProperty( PROPERTY_SELECT_SEQ, PROPERTY_ID_SELECT_SEQ); - startAggregatePropertyListening( PROPERTY_STRINGITEMLIST ); + init(); } //------------------------------------------------------------------ @@ -185,7 +190,7 @@ namespace frm { DBG_CTOR(OListBoxModel,NULL); - startAggregatePropertyListening( PROPERTY_STRINGITEMLIST ); + init(); } //------------------------------------------------------------------ diff --git a/forms/source/component/ListBox.hxx b/forms/source/component/ListBox.hxx index 590a9cb..51cf5a8 100644 --- a/forms/source/component/ListBox.hxx +++ b/forms/source/component/ListBox.hxx @@ -158,6 +158,7 @@ protected: protected: DECLARE_XCLONEABLE(); + void init(); private: void loadData( bool _bForce ); _______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
