1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
20 #include "formcellbinding.hxx"
21 #include <com/sun/star/form/binding/XBindableValue.hpp>
22 #include <com/sun/star/form/binding/XListEntrySink.hpp>
23 #include <com/sun/star/frame/XModel.hpp>
24 #include <com/sun/star/container/XChild.hpp>
25 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
26 #include <com/sun/star/lang/XServiceInfo.hpp>
27 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
28 #include <com/sun/star/beans/NamedValue.hpp>
29 #include "strings.hxx"
30 #include <osl/diagnose.h>
31 #include <comphelper/diagnose_ex.hxx>
38 using namespace ::com::sun::star::uno
;
39 using namespace ::com::sun::star::beans
;
40 using namespace ::com::sun::star::frame
;
41 using namespace ::com::sun::star::sheet
;
42 using namespace ::com::sun::star::container
;
43 using namespace ::com::sun::star::drawing
;
44 using namespace ::com::sun::star::table
;
45 using namespace ::com::sun::star::form
;
46 using namespace ::com::sun::star::lang
;
47 using namespace ::com::sun::star::form::binding
;
51 using ::com::sun::star::uno::Reference
;
52 using ::com::sun::star::uno::XInterface
;
53 using ::com::sun::star::container::XChild
;
54 using ::com::sun::star::frame::XModel
;
55 using ::com::sun::star::uno::UNO_QUERY
;
57 template< class TYPE
>
58 Reference
< TYPE
> getTypedModelNode( const Reference
< XInterface
>& _rxModelNode
)
60 Reference
< TYPE
> xTypedNode( _rxModelNode
, UNO_QUERY
);
61 if ( xTypedNode
.is() )
65 Reference
< XChild
> xChild( _rxModelNode
, UNO_QUERY
);
67 return getTypedModelNode
< TYPE
>( xChild
->getParent() );
73 Reference
< XModel
> getDocument( const Reference
< XInterface
>& _rxModelNode
)
75 return getTypedModelNode
< XModel
>( _rxModelNode
);
81 const OUString
& m_sReference
;
84 explicit StringCompare( const OUString
& _rReference
) : m_sReference( _rReference
) { }
86 bool operator()( std::u16string_view _rCompare
)
88 return ( _rCompare
== m_sReference
);
93 //= FormCellBindingHelper
94 FormCellBindingHelper::FormCellBindingHelper( const Reference
< XPropertySet
>& _rxControlModel
, const Reference
< XModel
>& _rxDocument
)
95 :m_xControlModel( _rxControlModel
)
96 ,m_xDocument( _rxDocument
, UNO_QUERY
)
98 OSL_ENSURE( m_xControlModel
.is(), "FormCellBindingHelper::FormCellBindingHelper: invalid control model!" );
100 if ( !m_xDocument
.is() )
101 m_xDocument
.set(getDocument( m_xControlModel
), css::uno::UNO_QUERY
);
102 OSL_ENSURE( m_xDocument
.is(), "FormCellBindingHelper::FormCellBindingHelper: Did not find the spreadsheet document!" );
105 bool FormCellBindingHelper::livesInSpreadsheetDocument( const Reference
< XPropertySet
>& _rxControlModel
)
107 Reference
< XSpreadsheetDocument
> xDocument( getDocument( _rxControlModel
), UNO_QUERY
);
108 return xDocument
.is();
111 bool FormCellBindingHelper::convertStringAddress( const OUString
& _rAddressDescription
, CellAddress
& /* [out] */ _rAddress
) const
114 return doConvertAddressRepresentations(
115 PROPERTY_FILE_REPRESENTATION
,
116 Any( _rAddressDescription
),
121 && ( aAddress
>>= _rAddress
);
124 bool FormCellBindingHelper::convertStringAddress( const OUString
& _rAddressDescription
,
125 CellRangeAddress
& /* [out] */ _rAddress
) const
128 return doConvertAddressRepresentations(
129 PROPERTY_FILE_REPRESENTATION
,
130 Any( _rAddressDescription
),
135 && ( aAddress
>>= _rAddress
);
138 Reference
< XValueBinding
> FormCellBindingHelper::createCellBindingFromStringAddress( const OUString
& _rAddress
, bool _bUseIntegerBinding
) const
140 Reference
< XValueBinding
> xBinding
;
141 if ( !m_xDocument
.is() )
145 // get the UNO representation of the address
146 CellAddress aAddress
;
147 if ( _rAddress
.isEmpty() || !convertStringAddress( _rAddress
, aAddress
) )
150 xBinding
.set(createDocumentDependentInstance(
151 _bUseIntegerBinding
? OUString(SERVICE_LISTINDEXCELLBINDING
) : OUString(SERVICE_CELLVALUEBINDING
),
154 ), css::uno::UNO_QUERY
);
159 Reference
< XListEntrySource
> FormCellBindingHelper::createCellListSourceFromStringAddress( const OUString
& _rAddress
) const
161 Reference
< XListEntrySource
> xSource
;
163 CellRangeAddress aRangeAddress
;
164 if ( !convertStringAddress( _rAddress
, aRangeAddress
) )
167 // create a range object for this address
168 xSource
.set(createDocumentDependentInstance(
169 SERVICE_CELLRANGELISTSOURCE
,
170 PROPERTY_LIST_CELL_RANGE
,
172 ), css::uno::UNO_QUERY
);
177 OUString
FormCellBindingHelper::getStringAddressFromCellBinding( const Reference
< XValueBinding
>& _rxBinding
) const
179 OSL_PRECOND( !_rxBinding
.is() || isCellBinding( _rxBinding
), "FormCellBindingHelper::getStringAddressFromCellBinding: this is no cell binding!" );
184 Reference
< XPropertySet
> xBindingProps( _rxBinding
, UNO_QUERY
);
185 OSL_ENSURE( xBindingProps
.is() || !_rxBinding
.is(), "FormCellBindingHelper::getStringAddressFromCellBinding: no property set for the binding!" );
186 if ( xBindingProps
.is() )
188 CellAddress aAddress
;
189 xBindingProps
->getPropertyValue( PROPERTY_BOUND_CELL
) >>= aAddress
;
192 doConvertAddressRepresentations( PROPERTY_ADDRESS
, Any( aAddress
),
193 PROPERTY_FILE_REPRESENTATION
, aStringAddress
, false );
195 aStringAddress
>>= sAddress
;
198 catch( const Exception
& )
200 TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::getStringAddressFromCellBinding" );
206 OUString
FormCellBindingHelper::getStringAddressFromCellListSource( const Reference
< XListEntrySource
>& _rxSource
) const
208 OSL_PRECOND( !_rxSource
.is() || isCellRangeListSource( _rxSource
), "FormCellBindingHelper::getStringAddressFromCellListSource: this is no cell list source!" );
213 Reference
< XPropertySet
> xSourceProps( _rxSource
, UNO_QUERY
);
214 OSL_ENSURE( xSourceProps
.is() || !_rxSource
.is(), "FormCellBindingHelper::getStringAddressFromCellListSource: no property set for the list source!" );
215 if ( xSourceProps
.is() )
217 CellRangeAddress aRangeAddress
;
218 xSourceProps
->getPropertyValue( PROPERTY_LIST_CELL_RANGE
) >>= aRangeAddress
;
221 doConvertAddressRepresentations( PROPERTY_ADDRESS
, Any( aRangeAddress
),
222 PROPERTY_FILE_REPRESENTATION
, aStringAddress
, true );
223 aStringAddress
>>= sAddress
;
226 catch( const Exception
& )
228 TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::getStringAddressFromCellListSource" );
234 bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const Reference
< XSpreadsheetDocument
>& _rxDocument
, const OUString
& _rService
)
236 bool bYesItIs
= false;
240 Reference
< XServiceInfo
> xSI( _rxDocument
, UNO_QUERY
);
241 if ( xSI
.is() && xSI
->supportsService( SERVICE_SPREADSHEET_DOCUMENT
) )
243 Reference
< XMultiServiceFactory
> xDocumentFactory( _rxDocument
, UNO_QUERY
);
244 OSL_ENSURE( xDocumentFactory
.is(), "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies: spreadsheet document, but no factory?" );
246 if ( xDocumentFactory
.is() )
248 const Sequence
<OUString
> aAvailableServices
= xDocumentFactory
->getAvailableServiceNames( );
250 bYesItIs
= std::any_of( aAvailableServices
.begin(), aAvailableServices
.end(), StringCompare( _rService
) );
254 catch( const Exception
& )
256 TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies" );
262 bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const OUString
& _rService
) const
264 return isSpreadsheetDocumentWhichSupplies( m_xDocument
, _rService
);
267 bool FormCellBindingHelper::isListCellRangeAllowed( const Reference
< XModel
>& _rxDocument
)
269 return isSpreadsheetDocumentWhichSupplies(
270 Reference
< XSpreadsheetDocument
>( _rxDocument
, UNO_QUERY
),
271 SERVICE_CELLRANGELISTSOURCE
275 bool FormCellBindingHelper::isListCellRangeAllowed( ) const
277 bool bAllow( false );
279 Reference
< XListEntrySink
> xSink( m_xControlModel
, UNO_QUERY
);
282 bAllow
= isSpreadsheetDocumentWhichSupplies( SERVICE_CELLRANGELISTSOURCE
);
288 bool FormCellBindingHelper::isCellBindingAllowed( ) const
290 bool bAllow( false );
292 Reference
< XBindableValue
> xBindable( m_xControlModel
, UNO_QUERY
);
293 if ( xBindable
.is() )
295 // the control can potentially be bound to an external value
296 // Does it live within a Calc document, and is able to supply CellBindings?
297 bAllow
= isSpreadsheetDocumentWhichSupplies( SERVICE_CELLVALUEBINDING
);
303 bool FormCellBindingHelper::isCellBindingAllowed( const Reference
< XModel
>& _rxDocument
)
305 return isSpreadsheetDocumentWhichSupplies(
306 Reference
< XSpreadsheetDocument
>( _rxDocument
, UNO_QUERY
),
307 SERVICE_CELLVALUEBINDING
311 bool FormCellBindingHelper::isCellBinding( const Reference
< XValueBinding
>& _rxBinding
)
313 return doesComponentSupport( _rxBinding
, SERVICE_CELLVALUEBINDING
);
316 bool FormCellBindingHelper::isCellIntegerBinding( const Reference
< XValueBinding
>& _rxBinding
)
318 return doesComponentSupport( _rxBinding
, SERVICE_LISTINDEXCELLBINDING
);
321 bool FormCellBindingHelper::isCellRangeListSource( const Reference
< XListEntrySource
>& _rxSource
)
323 return doesComponentSupport( _rxSource
, SERVICE_CELLRANGELISTSOURCE
);
326 bool FormCellBindingHelper::doesComponentSupport( const Reference
< XInterface
>& _rxComponent
, const OUString
& _rService
)
328 Reference
< XServiceInfo
> xSI( _rxComponent
, UNO_QUERY
);
329 bool bDoes
= xSI
.is() && xSI
->supportsService( _rService
);
333 Reference
< XValueBinding
> FormCellBindingHelper::getCurrentBinding( ) const
335 Reference
< XValueBinding
> xBinding
;
336 Reference
< XBindableValue
> xBindable( m_xControlModel
, UNO_QUERY
);
337 if ( xBindable
.is() )
338 xBinding
= xBindable
->getValueBinding();
342 Reference
< XListEntrySource
> FormCellBindingHelper::getCurrentListSource( ) const
344 Reference
< XListEntrySource
> xSource
;
345 Reference
< XListEntrySink
> xSink( m_xControlModel
, UNO_QUERY
);
347 xSource
= xSink
->getListEntrySource();
351 void FormCellBindingHelper::setBinding( const Reference
< XValueBinding
>& _rxBinding
)
353 Reference
< XBindableValue
> xBindable( m_xControlModel
, UNO_QUERY
);
354 OSL_PRECOND( xBindable
.is(), "FormCellBindingHelper::setBinding: the object is not bindable!" );
355 if ( xBindable
.is() )
356 xBindable
->setValueBinding( _rxBinding
);
359 void FormCellBindingHelper::setListSource( const Reference
< XListEntrySource
>& _rxSource
)
361 Reference
< XListEntrySink
> xSink( m_xControlModel
, UNO_QUERY
);
362 OSL_PRECOND( xSink
.is(), "FormCellBindingHelper::setListSource: the object is no list entry sink!" );
364 xSink
->setListEntrySource( _rxSource
);
367 Reference
< XInterface
> FormCellBindingHelper::createDocumentDependentInstance( const OUString
& _rService
, const OUString
& _rArgumentName
,
368 const Any
& _rArgumentValue
) const
370 Reference
< XInterface
> xReturn
;
372 Reference
< XMultiServiceFactory
> xDocumentFactory( m_xDocument
, UNO_QUERY
);
373 OSL_ENSURE( xDocumentFactory
.is(), "FormCellBindingHelper::createDocumentDependentInstance: no document service factory!" );
374 if ( xDocumentFactory
.is() )
378 if ( !_rArgumentName
.isEmpty() )
381 aArg
.Name
= _rArgumentName
;
382 aArg
.Value
= _rArgumentValue
;
384 Sequence
< Any
> aArgs
{ Any(aArg
) };
385 xReturn
= xDocumentFactory
->createInstanceWithArguments( _rService
, aArgs
);
389 xReturn
= xDocumentFactory
->createInstance( _rService
);
392 catch ( const Exception
& )
394 OSL_FAIL( "FormCellBindingHelper::createDocumentDependentInstance: could not create the binding at the document!" );
400 bool FormCellBindingHelper::doConvertAddressRepresentations( const OUString
& _rInputProperty
, const Any
& _rInputValue
,
401 const OUString
& _rOutputProperty
, Any
& _rOutputValue
, bool _bIsRange
) const
403 bool bSuccess
= false;
405 Reference
< XPropertySet
> xConverter(
406 createDocumentDependentInstance(
407 _bIsRange
? OUString(SERVICE_RANGEADDRESS_CONVERSION
) : OUString(SERVICE_ADDRESS_CONVERSION
),
413 OSL_ENSURE( xConverter
.is(), "FormCellBindingHelper::doConvertAddressRepresentations: could not get a converter service!" );
414 if ( xConverter
.is() )
418 xConverter
->setPropertyValue( _rInputProperty
, _rInputValue
);
419 _rOutputValue
= xConverter
->getPropertyValue( _rOutputProperty
);
422 catch( const Exception
& )
424 TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::doConvertAddressRepresentations" );
431 } // namespace xmloff
433 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */