LibreOffice Module xmloff (master)  1
formcellbinding.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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 <tools/diagnose_ex.h>
32 
33 #include <algorithm>
34 
35 namespace xmloff
36 {
37 
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;
48 
49 namespace
50 {
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;
56 
57  template< class TYPE >
58  Reference< TYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode )
59  {
60  Reference< TYPE > xTypedNode( _rxModelNode, UNO_QUERY );
61  if ( xTypedNode.is() )
62  return xTypedNode;
63  else
64  {
65  Reference< XChild > xChild( _rxModelNode, UNO_QUERY );
66  if ( xChild.is() )
67  return getTypedModelNode< TYPE >( xChild->getParent() );
68  else
69  return nullptr;
70  }
71  }
72 
73  Reference< XModel > getDocument( const Reference< XInterface >& _rxModelNode )
74  {
75  return getTypedModelNode< XModel >( _rxModelNode );
76  }
77 
78  struct StringCompare
79  {
80  private:
81  const OUString & m_sReference;
82 
83  public:
84  explicit StringCompare( const OUString& _rReference ) : m_sReference( _rReference ) { }
85 
86  bool operator()( std::u16string_view _rCompare )
87  {
88  return ( _rCompare == m_sReference );
89  }
90  };
91 }
92 
93 //= FormCellBindingHelper
94 FormCellBindingHelper::FormCellBindingHelper( const Reference< XPropertySet >& _rxControlModel, const Reference< XModel >& _rxDocument )
95  :m_xControlModel( _rxControlModel )
96  ,m_xDocument( _rxDocument, UNO_QUERY )
97 {
98  OSL_ENSURE( m_xControlModel.is(), "FormCellBindingHelper::FormCellBindingHelper: invalid control model!" );
99 
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!" );
103 }
104 
106 {
107  Reference< XSpreadsheetDocument > xDocument( getDocument( _rxControlModel ), UNO_QUERY );
108  return xDocument.is();
109 }
110 
111 bool FormCellBindingHelper::convertStringAddress( const OUString& _rAddressDescription, CellAddress& /* [out] */ _rAddress ) const
112 {
113  Any aAddress;
116  makeAny( _rAddressDescription ),
118  aAddress,
119  false
120  )
121  && ( aAddress >>= _rAddress );
122 }
123 
124 bool FormCellBindingHelper::convertStringAddress( const OUString& _rAddressDescription,
125  CellRangeAddress& /* [out] */ _rAddress ) const
126 {
127  Any aAddress;
130  makeAny( _rAddressDescription ),
132  aAddress,
133  true
134  )
135  && ( aAddress >>= _rAddress );
136 }
137 
138 Reference< XValueBinding > FormCellBindingHelper::createCellBindingFromStringAddress( const OUString& _rAddress, bool _bUseIntegerBinding ) const
139 {
140  Reference< XValueBinding > xBinding;
141  if ( !m_xDocument.is() )
142  // very bad ...
143  return xBinding;
144 
145  // get the UNO representation of the address
146  CellAddress aAddress;
147  if ( _rAddress.isEmpty() || !convertStringAddress( _rAddress, aAddress ) )
148  return xBinding;
149 
150  xBinding.set(createDocumentDependentInstance(
151  _bUseIntegerBinding ? OUString(SERVICE_LISTINDEXCELLBINDING) : OUString(SERVICE_CELLVALUEBINDING),
153  makeAny( aAddress )
154  ), css::uno::UNO_QUERY);
155 
156  return xBinding;
157 }
158 
159 Reference< XListEntrySource > FormCellBindingHelper::createCellListSourceFromStringAddress( const OUString& _rAddress ) const
160 {
161  Reference< XListEntrySource > xSource;
162 
163  CellRangeAddress aRangeAddress;
164  if ( !convertStringAddress( _rAddress, aRangeAddress ) )
165  return xSource;
166 
167  // create a range object for this address
171  makeAny( aRangeAddress )
172  ), css::uno::UNO_QUERY);
173 
174  return xSource;
175 }
176 
177 OUString FormCellBindingHelper::getStringAddressFromCellBinding( const Reference< XValueBinding >& _rxBinding ) const
178 {
179  OSL_PRECOND( !_rxBinding.is() || isCellBinding( _rxBinding ), "FormCellBindingHelper::getStringAddressFromCellBinding: this is no cell binding!" );
180 
181  OUString sAddress;
182  try
183  {
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() )
187  {
188  CellAddress aAddress;
189  xBindingProps->getPropertyValue( PROPERTY_BOUND_CELL ) >>= aAddress;
190 
191  Any aStringAddress;
193  PROPERTY_FILE_REPRESENTATION, aStringAddress, false );
194 
195  aStringAddress >>= sAddress;
196  }
197  }
198  catch( const Exception& )
199  {
200  TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::getStringAddressFromCellBinding" );
201  }
202 
203  return sAddress;
204 }
205 
206 OUString FormCellBindingHelper::getStringAddressFromCellListSource( const Reference< XListEntrySource >& _rxSource ) const
207 {
208  OSL_PRECOND( !_rxSource.is() || isCellRangeListSource( _rxSource ), "FormCellBindingHelper::getStringAddressFromCellListSource: this is no cell list source!" );
209 
210  OUString sAddress;
211  try
212  {
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() )
216  {
217  CellRangeAddress aRangeAddress;
218  xSourceProps->getPropertyValue( PROPERTY_LIST_CELL_RANGE ) >>= aRangeAddress;
219 
220  Any aStringAddress;
222  PROPERTY_FILE_REPRESENTATION, aStringAddress, true );
223  aStringAddress >>= sAddress;
224  }
225  }
226  catch( const Exception& )
227  {
228  TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::getStringAddressFromCellListSource" );
229  }
230 
231  return sAddress;
232 }
233 
234 bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const Reference< XSpreadsheetDocument >& _rxDocument, const OUString& _rService )
235 {
236  bool bYesItIs = false;
237 
238  try
239  {
240  Reference< XServiceInfo > xSI( _rxDocument, UNO_QUERY );
241  if ( xSI.is() && xSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) )
242  {
243  Reference< XMultiServiceFactory > xDocumentFactory( _rxDocument, UNO_QUERY );
244  OSL_ENSURE( xDocumentFactory.is(), "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies: spreadsheet document, but no factory?" );
245 
246  Sequence< OUString > aAvailableServices;
247  if ( xDocumentFactory.is() )
248  aAvailableServices = xDocumentFactory->getAvailableServiceNames( );
249 
250  bYesItIs = std::any_of( aAvailableServices.begin(), aAvailableServices.end(), StringCompare( _rService ) );
251  }
252  }
253  catch( const Exception& )
254  {
255  TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies" );
256  }
257 
258  return bYesItIs;
259 }
260 
261 bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const OUString& _rService ) const
262 {
263  return isSpreadsheetDocumentWhichSupplies( m_xDocument, _rService );
264 }
265 
266 bool FormCellBindingHelper::isListCellRangeAllowed( const Reference< XModel >& _rxDocument )
267 {
269  Reference< XSpreadsheetDocument >( _rxDocument, UNO_QUERY ),
271  );
272 }
273 
275 {
276  bool bAllow( false );
277 
278  Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
279  if ( xSink.is() )
280  {
282  }
283 
284  return bAllow;
285 }
286 
288 {
289  bool bAllow( false );
290 
291  Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
292  if ( xBindable.is() )
293  {
294  // the control can potentially be bound to an external value
295  // Does it live within a Calc document, and is able to supply CellBindings?
297  }
298 
299  return bAllow;
300 }
301 
302 bool FormCellBindingHelper::isCellBindingAllowed( const Reference< XModel >& _rxDocument )
303 {
305  Reference< XSpreadsheetDocument >( _rxDocument, UNO_QUERY ),
307  );
308 }
309 
310 bool FormCellBindingHelper::isCellBinding( const Reference< XValueBinding >& _rxBinding )
311 {
312  return doesComponentSupport( _rxBinding, SERVICE_CELLVALUEBINDING );
313 }
314 
315 bool FormCellBindingHelper::isCellIntegerBinding( const Reference< XValueBinding >& _rxBinding )
316 {
318 }
319 
320 bool FormCellBindingHelper::isCellRangeListSource( const Reference< XListEntrySource >& _rxSource )
321 {
323 }
324 
325 bool FormCellBindingHelper::doesComponentSupport( const Reference< XInterface >& _rxComponent, const OUString& _rService )
326 {
327  Reference< XServiceInfo > xSI( _rxComponent, UNO_QUERY );
328  bool bDoes = xSI.is() && xSI->supportsService( _rService );
329  return bDoes;
330 }
331 
332 Reference< XValueBinding > FormCellBindingHelper::getCurrentBinding( ) const
333 {
334  Reference< XValueBinding > xBinding;
335  Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
336  if ( xBindable.is() )
337  xBinding = xBindable->getValueBinding();
338  return xBinding;
339 }
340 
341 Reference< XListEntrySource > FormCellBindingHelper::getCurrentListSource( ) const
342 {
343  Reference< XListEntrySource > xSource;
344  Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
345  if ( xSink.is() )
346  xSource = xSink->getListEntrySource();
347  return xSource;
348 }
349 
350 void FormCellBindingHelper::setBinding( const Reference< XValueBinding >& _rxBinding )
351 {
352  Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY );
353  OSL_PRECOND( xBindable.is(), "FormCellBindingHelper::setBinding: the object is not bindable!" );
354  if ( xBindable.is() )
355  xBindable->setValueBinding( _rxBinding );
356 }
357 
358 void FormCellBindingHelper::setListSource( const Reference< XListEntrySource >& _rxSource )
359 {
360  Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY );
361  OSL_PRECOND( xSink.is(), "FormCellBindingHelper::setListSource: the object is no list entry sink!" );
362  if ( xSink.is() )
363  xSink->setListEntrySource( _rxSource );
364 }
365 
366 Reference< XInterface > FormCellBindingHelper::createDocumentDependentInstance( const OUString& _rService, const OUString& _rArgumentName,
367  const Any& _rArgumentValue ) const
368 {
369  Reference< XInterface > xReturn;
370 
371  Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY );
372  OSL_ENSURE( xDocumentFactory.is(), "FormCellBindingHelper::createDocumentDependentInstance: no document service factory!" );
373  if ( xDocumentFactory.is() )
374  {
375  try
376  {
377  if ( !_rArgumentName.isEmpty() )
378  {
379  NamedValue aArg;
380  aArg.Name = _rArgumentName;
381  aArg.Value = _rArgumentValue;
382 
383  Sequence< Any > aArgs( 1 );
384  aArgs[ 0 ] <<= aArg;
385 
386  xReturn = xDocumentFactory->createInstanceWithArguments( _rService, aArgs );
387  }
388  else
389  {
390  xReturn = xDocumentFactory->createInstance( _rService );
391  }
392  }
393  catch ( const Exception& )
394  {
395  OSL_FAIL( "FormCellBindingHelper::createDocumentDependentInstance: could not create the binding at the document!" );
396  }
397  }
398  return xReturn;
399 }
400 
401 bool FormCellBindingHelper::doConvertAddressRepresentations( const OUString& _rInputProperty, const Any& _rInputValue,
402  const OUString& _rOutputProperty, Any& _rOutputValue, bool _bIsRange ) const
403 {
404  bool bSuccess = false;
405 
408  _bIsRange ? OUString(SERVICE_RANGEADDRESS_CONVERSION) : OUString(SERVICE_ADDRESS_CONVERSION),
409  OUString(),
410  Any()
411  ),
412  UNO_QUERY
413  );
414  OSL_ENSURE( xConverter.is(), "FormCellBindingHelper::doConvertAddressRepresentations: could not get a converter service!" );
415  if ( xConverter.is() )
416  {
417  try
418  {
419  xConverter->setPropertyValue( _rInputProperty, _rInputValue );
420  _rOutputValue = xConverter->getPropertyValue( _rOutputProperty );
421  bSuccess = true;
422  }
423  catch( const Exception& )
424  {
425  TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::doConvertAddressRepresentations" );
426  }
427  }
428 
429  return bSuccess;
430 }
431 
432 } // namespace xmloff
433 
434 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XTypeConverter > xConverter
tools::SvRef< SvBaseLink > xSink
static bool isCellRangeListSource(const css::uno::Reference< css::form::binding::XListEntrySource > &_rxSource)
checks whether a given list source is a spreadsheet cell list source
css::uno::Reference< css::beans::XPropertySet > m_xControlModel
css::uno::Reference< css::uno::XInterface > createDocumentDependentInstance(const OUString &_rService, const OUString &_rArgumentName, const css::uno::Any &_rArgumentValue) const
uses the document (it's factory interface, respectively) to create a component instance ...
#define PROPERTY_ADDRESS
Definition: strings.hxx:139
Reference< XOfficeDatabaseDocument > m_xDocument
FormCellBindingHelper(const css::uno::Reference< css::beans::XPropertySet > &_rxControlModel, const css::uno::Reference< css::frame::XModel > &_rxDocument)
ctor
#define SERVICE_SPREADSHEET_DOCUMENT
Definition: strings.hxx:144
#define SERVICE_CELLVALUEBINDING
Definition: strings.hxx:145
static bool livesInSpreadsheetDocument(const css::uno::Reference< css::beans::XPropertySet > &_rxControlModel)
determines whether the given control model lives in a spreadsheet document
#define PROPERTY_FILE_REPRESENTATION
Definition: strings.hxx:140
#define PROPERTY_LIST_CELL_RANGE
Definition: strings.hxx:138
const OUString & m_sReference
#define PROPERTY_BOUND_CELL
Definition: strings.hxx:137
css::uno::Reference< css::sheet::XSpreadsheetDocument > m_xDocument
#define TOOLS_WARN_EXCEPTION(area, stream)
static bool isCellBinding(const css::uno::Reference< css::form::binding::XValueBinding > &_rxBinding)
checks whether a given binding is a spreadsheet cell binding
css::uno::Reference< css::form::binding::XValueBinding > createCellBindingFromStringAddress(const OUString &_rAddress, bool _bUseIntegerBinding) const
gets a cell binding for the given address isCellBindingAllowed returns
void setBinding(const css::uno::Reference< css::form::binding::XValueBinding > &_rxBinding)
sets a new binding for our control model the control model is bindable (which is implied by ...
static bool isCellIntegerBinding(const css::uno::Reference< css::form::binding::XValueBinding > &_rxBinding)
checks whether a given binding is a spreadsheet cell binding, exchanging integer values ...
#define SERVICE_CELLRANGELISTSOURCE
Definition: strings.hxx:147
bool convertStringAddress(const OUString &_rAddressDescription, css::table::CellAddress &_rAddress) const
creates an address object from a string representation of a cell address
css::uno::Reference< css::form::binding::XListEntrySource > createCellListSourceFromStringAddress(const OUString &_rAddress) const
gets a cell range list source binding for the given address
#define SERVICE_RANGEADDRESS_CONVERSION
Definition: strings.hxx:149
bool isSpreadsheetDocumentWhichSupplies(const OUString &_rService) const
determines if our document is a spreadsheet document, and can supply the given service ...
css::uno::Reference< css::form::binding::XListEntrySource > getCurrentListSource() const
returns the current external list source of the control model, if any
OUString getStringAddressFromCellListSource(const css::uno::Reference< css::form::binding::XListEntrySource > &_rxSource) const
creates a string representation for the given list source's range address
bool doConvertAddressRepresentations(const OUString &_rInputProperty, const css::uno::Any &_rInputValue, const OUString &_rOutputProperty, css::uno::Any &_rOutputValue, bool _bIsRange) const
converts an address representation into another one
OUString getStringAddressFromCellBinding(const css::uno::Reference< css::form::binding::XValueBinding > &_rxBinding) const
creates a string representation for the given value binding's address
void setListSource(const css::uno::Reference< css::form::binding::XListEntrySource > &_rxSource)
sets a list source for our control model the control model is a list sink (which is implied by
static bool doesComponentSupport(const css::uno::Reference< css::uno::XInterface > &_rxComponent, const OUString &_rService)
checks whether a given component supports a given service
bool isListCellRangeAllowed() const
checks whether it's possible to bind the control model to a range of spreadsheet cells supplying the ...
#define SERVICE_ADDRESS_CONVERSION
Definition: strings.hxx:148
css::uno::Reference< css::form::binding::XValueBinding > getCurrentBinding() const
returns the current binding of our control model, if any.
bool isCellBindingAllowed() const
checks whether it's possible to bind the control model to a spreadsheet cell
#define SERVICE_LISTINDEXCELLBINDING
Definition: strings.hxx:146
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)