Line data Source code
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 "cellbindinghandler.hxx"
21 : #include "formstrings.hxx"
22 : #include "formmetadata.hxx"
23 : #include "cellbindinghelper.hxx"
24 :
25 : #include <com/sun/star/form/binding/XValueBinding.hpp>
26 : #include <com/sun/star/table/CellAddress.hpp>
27 : #include <com/sun/star/inspection/XObjectInspectorUI.hpp>
28 : #include <tools/debug.hxx>
29 :
30 :
31 0 : extern "C" void SAL_CALL createRegistryInfo_CellBindingPropertyHandler()
32 : {
33 0 : ::pcr::CellBindingPropertyHandler::registerImplementation();
34 0 : }
35 :
36 :
37 : namespace pcr
38 : {
39 :
40 :
41 : using namespace ::com::sun::star::uno;
42 : using namespace ::com::sun::star::table;
43 : using namespace ::com::sun::star::lang;
44 : using namespace ::com::sun::star::beans;
45 : using namespace ::com::sun::star::script;
46 : using namespace ::com::sun::star::frame;
47 : using namespace ::com::sun::star::inspection;
48 : using namespace ::com::sun::star::form::binding;
49 : using namespace ::comphelper;
50 :
51 :
52 : //= CellBindingPropertyHandler
53 :
54 :
55 0 : CellBindingPropertyHandler::CellBindingPropertyHandler( const Reference< XComponentContext >& _rxContext )
56 : :CellBindingPropertyHandler_Base( _rxContext )
57 0 : ,m_pCellExchangeConverter( new DefaultEnumRepresentation( *m_pInfoService, ::getCppuType( static_cast< sal_Int16* >( NULL ) ), PROPERTY_ID_CELL_EXCHANGE_TYPE ) )
58 : {
59 0 : }
60 :
61 :
62 0 : OUString SAL_CALL CellBindingPropertyHandler::getImplementationName_static( ) throw (RuntimeException)
63 : {
64 0 : return OUString( "com.sun.star.comp.extensions.CellBindingPropertyHandler" );
65 : }
66 :
67 :
68 0 : Sequence< OUString > SAL_CALL CellBindingPropertyHandler::getSupportedServiceNames_static( ) throw (RuntimeException)
69 : {
70 0 : Sequence< OUString > aSupported( 1 );
71 0 : aSupported[0] = "com.sun.star.form.inspection.CellBindingPropertyHandler";
72 0 : return aSupported;
73 : }
74 :
75 :
76 0 : void CellBindingPropertyHandler::onNewComponent()
77 : {
78 0 : PropertyHandlerComponent::onNewComponent();
79 :
80 0 : Reference< XModel > xDocument( impl_getContextDocument_nothrow() );
81 : DBG_ASSERT( xDocument.is(), "CellBindingPropertyHandler::onNewComponent: no document!" );
82 0 : if ( CellBindingHelper::isSpreadsheetDocument( xDocument ) )
83 0 : m_pHelper.reset( new CellBindingHelper( m_xComponent, xDocument ) );
84 0 : }
85 :
86 :
87 0 : CellBindingPropertyHandler::~CellBindingPropertyHandler( )
88 : {
89 0 : }
90 :
91 :
92 0 : Sequence< OUString > SAL_CALL CellBindingPropertyHandler::getActuatingProperties( ) throw (RuntimeException, std::exception)
93 : {
94 0 : Sequence< OUString > aInterestingProperties( 3 );
95 0 : aInterestingProperties[0] = PROPERTY_LIST_CELL_RANGE;
96 0 : aInterestingProperties[1] = PROPERTY_BOUND_CELL;
97 0 : aInterestingProperties[2] = PROPERTY_CONTROLSOURCE;
98 0 : return aInterestingProperties;
99 : }
100 :
101 :
102 0 : void SAL_CALL CellBindingPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) throw (NullPointerException, RuntimeException, std::exception)
103 : {
104 0 : ::osl::MutexGuard aGuard( m_aMutex );
105 0 : PropertyId nActuatingPropId( impl_getPropertyId_throw( _rActuatingPropertyName ) );
106 : OSL_PRECOND( m_pHelper.get(), "CellBindingPropertyHandler::actuatingPropertyChanged: inconsistentcy!" );
107 : // if we survived impl_getPropertyId_throw, we should have a helper, since no helper implies no properties
108 :
109 : OSL_PRECOND( _rxInspectorUI.is(), "FormComponentPropertyHandler::actuatingPropertyChanged: no access to the UI!" );
110 0 : if ( !_rxInspectorUI.is() )
111 0 : throw NullPointerException();
112 :
113 0 : ::std::vector< PropertyId > aDependentProperties;
114 :
115 0 : switch ( nActuatingPropId )
116 : {
117 : // ----- BoundCell -----
118 : case PROPERTY_ID_BOUND_CELL:
119 : {
120 : // the SQL-data-binding related properties need to be enabled if and only if
121 : // there is *no* valid cell binding
122 0 : Reference< XValueBinding > xBinding;
123 0 : _rNewValue >>= xBinding;
124 :
125 0 : if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_CELL_EXCHANGE_TYPE ) )
126 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_CELL_EXCHANGE_TYPE, xBinding.is() );
127 0 : if ( impl_componentHasProperty_throw( PROPERTY_CONTROLSOURCE ) )
128 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_CONTROLSOURCE, !xBinding.is() );
129 :
130 0 : if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_FILTERPROPOSAL ) )
131 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_FILTERPROPOSAL, !xBinding.is() );
132 0 : if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_EMPTY_IS_NULL ) )
133 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_EMPTY_IS_NULL, !xBinding.is() );
134 :
135 0 : aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN );
136 :
137 0 : if ( !xBinding.is() && m_pHelper->getCurrentBinding().is() )
138 : {
139 : // ensure that the "transfer selection as" property is reset. Since we can't remember
140 : // it at the object itself, but derive it from the binding only, we have to normalize
141 : // it now that there *is* no binding anymore.
142 0 : setPropertyValue( PROPERTY_CELL_EXCHANGE_TYPE, makeAny( (sal_Int16) 0 ) );
143 0 : }
144 : }
145 0 : break;
146 :
147 : // ----- CellRange -----
148 : case PROPERTY_ID_LIST_CELL_RANGE:
149 : {
150 : // the list source related properties need to be enabled if and only if
151 : // there is *no* valid external list source for the control
152 0 : Reference< XListEntrySource > xSource;
153 0 : _rNewValue >>= xSource;
154 :
155 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_STRINGITEMLIST, !xSource.is() );
156 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_LISTSOURCE, !xSource.is() );
157 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_LISTSOURCETYPE, !xSource.is() );
158 :
159 0 : aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN );
160 :
161 : // also reset the list entries if the cell range is reset
162 : // #i28319#
163 0 : if ( !_bFirstTimeInit )
164 : {
165 : try
166 : {
167 0 : if ( !xSource.is() )
168 0 : setPropertyValue( PROPERTY_STRINGITEMLIST, makeAny( Sequence< OUString >() ) );
169 : }
170 0 : catch( const Exception& )
171 : {
172 : OSL_FAIL( "OPropertyBrowserController::actuatingPropertyChanged( ListCellRange ): caught an exception while resetting the string items!" );
173 : }
174 0 : }
175 : }
176 0 : break; // case PROPERTY_ID_LIST_CELL_RANGE
177 :
178 : // ----- DataField -----
179 : case PROPERTY_ID_CONTROLSOURCE:
180 : {
181 0 : OUString sControlSource;
182 0 : _rNewValue >>= sControlSource;
183 0 : if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_BOUND_CELL ) )
184 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_BOUND_CELL, sControlSource.isEmpty() );
185 : }
186 0 : break; // case PROPERTY_ID_CONTROLSOURCE
187 :
188 : default:
189 : OSL_FAIL( "CellBindingPropertyHandler::actuatingPropertyChanged: did not register for this property!" );
190 : }
191 :
192 0 : for ( ::std::vector< PropertyId >::const_iterator loopAffected = aDependentProperties.begin();
193 0 : loopAffected != aDependentProperties.end();
194 : ++loopAffected
195 : )
196 : {
197 0 : impl_updateDependentProperty_nothrow( *loopAffected, _rxInspectorUI );
198 0 : }
199 0 : }
200 :
201 :
202 0 : void CellBindingPropertyHandler::impl_updateDependentProperty_nothrow( PropertyId _nPropId, const Reference< XObjectInspectorUI >& _rxInspectorUI ) const
203 : {
204 : try
205 : {
206 0 : switch ( _nPropId )
207 : {
208 : // ----- BoundColumn -----
209 : case PROPERTY_ID_BOUNDCOLUMN:
210 : {
211 0 : CellBindingPropertyHandler* pNonConstThis = const_cast< CellBindingPropertyHandler* >( this );
212 0 : Reference< XValueBinding > xBinding( pNonConstThis->getPropertyValue( PROPERTY_BOUND_CELL ), UNO_QUERY );
213 0 : Reference< XListEntrySource > xListSource( pNonConstThis->getPropertyValue( PROPERTY_LIST_CELL_RANGE ), UNO_QUERY );
214 :
215 0 : if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_BOUNDCOLUMN ) )
216 0 : _rxInspectorUI->enablePropertyUI( PROPERTY_BOUNDCOLUMN, !xBinding.is() && !xListSource.is() );
217 : }
218 0 : break; // case PROPERTY_ID_BOUNDCOLUMN
219 :
220 : } // switch
221 :
222 : }
223 0 : catch( const Exception& )
224 : {
225 : OSL_FAIL( "CellBindingPropertyHandler::impl_updateDependentProperty_nothrow: caught an exception!" );
226 : }
227 0 : }
228 :
229 :
230 0 : Any SAL_CALL CellBindingPropertyHandler::getPropertyValue( const OUString& _rPropertyName ) throw (UnknownPropertyException, RuntimeException, std::exception)
231 : {
232 0 : ::osl::MutexGuard aGuard( m_aMutex );
233 0 : PropertyId nPropId( impl_getPropertyId_throw( _rPropertyName ) );
234 :
235 : OSL_ENSURE( m_pHelper.get(), "CellBindingPropertyHandler::getPropertyValue: inconsistency!" );
236 : // if we survived impl_getPropertyId_throw, we should have a helper, since no helper implies no properties
237 :
238 0 : Any aReturn;
239 0 : switch ( nPropId )
240 : {
241 : case PROPERTY_ID_BOUND_CELL:
242 : {
243 0 : Reference< XValueBinding > xBinding( m_pHelper->getCurrentBinding() );
244 0 : if ( !m_pHelper->isCellBinding( xBinding ) )
245 0 : xBinding.clear();
246 :
247 0 : aReturn <<= xBinding;
248 : }
249 0 : break;
250 :
251 : case PROPERTY_ID_LIST_CELL_RANGE:
252 : {
253 0 : Reference< XListEntrySource > xSource( m_pHelper->getCurrentListSource() );
254 0 : if ( !m_pHelper->isCellRangeListSource( xSource ) )
255 0 : xSource.clear();
256 :
257 0 : aReturn <<= xSource;
258 : }
259 0 : break;
260 :
261 : case PROPERTY_ID_CELL_EXCHANGE_TYPE:
262 : {
263 0 : Reference< XValueBinding > xBinding( m_pHelper->getCurrentBinding() );
264 0 : aReturn <<= (sal_Int16)( m_pHelper->isCellIntegerBinding( xBinding ) ? 1 : 0 );
265 : }
266 0 : break;
267 :
268 : default:
269 : OSL_FAIL( "CellBindingPropertyHandler::getPropertyValue: cannot handle this!" );
270 0 : break;
271 : }
272 0 : return aReturn;
273 : }
274 :
275 :
276 0 : void SAL_CALL CellBindingPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) throw (UnknownPropertyException, RuntimeException, std::exception)
277 : {
278 0 : ::osl::MutexGuard aGuard( m_aMutex );
279 0 : PropertyId nPropId( impl_getPropertyId_throw( _rPropertyName ) );
280 :
281 : OSL_ENSURE( m_pHelper.get(), "CellBindingPropertyHandler::setPropertyValue: inconsistency!" );
282 : // if we survived impl_getPropertyId_throw, we should have a helper, since no helper implies no properties
283 :
284 : try
285 : {
286 0 : Any aOldValue = getPropertyValue( _rPropertyName );
287 :
288 0 : switch ( nPropId )
289 : {
290 : case PROPERTY_ID_BOUND_CELL:
291 : {
292 0 : Reference< XValueBinding > xBinding;
293 0 : _rValue >>= xBinding;
294 0 : m_pHelper->setBinding( xBinding );
295 : }
296 0 : break;
297 :
298 : case PROPERTY_ID_LIST_CELL_RANGE:
299 : {
300 0 : Reference< XListEntrySource > xSource;
301 0 : _rValue >>= xSource;
302 0 : m_pHelper->setListSource( xSource );
303 : }
304 0 : break;
305 :
306 : case PROPERTY_ID_CELL_EXCHANGE_TYPE:
307 : {
308 0 : sal_Int16 nExchangeType = 0;
309 0 : OSL_VERIFY( _rValue >>= nExchangeType );
310 :
311 0 : Reference< XValueBinding > xBinding = m_pHelper->getCurrentBinding( );
312 0 : if ( xBinding.is() )
313 : {
314 0 : sal_Bool bNeedIntegerBinding = ( nExchangeType == 1 );
315 0 : if ( (bool)bNeedIntegerBinding != m_pHelper->isCellIntegerBinding( xBinding ) )
316 : {
317 0 : CellAddress aAddress;
318 0 : if ( m_pHelper->getAddressFromCellBinding( xBinding, aAddress ) )
319 : {
320 0 : xBinding = m_pHelper->createCellBindingFromAddress( aAddress, bNeedIntegerBinding );
321 0 : m_pHelper->setBinding( xBinding );
322 : }
323 : }
324 0 : }
325 : }
326 0 : break;
327 :
328 : default:
329 : OSL_FAIL( "CellBindingPropertyHandler::setPropertyValue: cannot handle this!" );
330 0 : break;
331 : }
332 :
333 0 : impl_setContextDocumentModified_nothrow();
334 :
335 0 : Any aNewValue( getPropertyValue( _rPropertyName ) );
336 0 : firePropertyChange( _rPropertyName, nPropId, aOldValue, aNewValue );
337 : // TODO/UNOize: can't we make this a part of the base class, for all those "virtual"
338 : // properties? Base class'es |setPropertyValue| could call some |doSetPropertyValue|,
339 : // and handle the listener notification itself
340 : }
341 0 : catch( const Exception& )
342 : {
343 : OSL_FAIL( "CellBindingPropertyHandler::setPropertyValue: caught an exception!" );
344 0 : }
345 0 : }
346 :
347 :
348 0 : Any SAL_CALL CellBindingPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) throw (UnknownPropertyException, RuntimeException, std::exception)
349 : {
350 0 : ::osl::MutexGuard aGuard( m_aMutex );
351 0 : Any aPropertyValue;
352 :
353 : OSL_ENSURE( m_pHelper.get(), "CellBindingPropertyHandler::convertToPropertyValue: we have no SupportedProperties!" );
354 0 : if ( !m_pHelper.get() )
355 0 : return aPropertyValue;
356 :
357 0 : PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) );
358 :
359 0 : OUString sControlValue;
360 0 : OSL_VERIFY( _rControlValue >>= sControlValue );
361 0 : switch( nPropId )
362 : {
363 : case PROPERTY_ID_LIST_CELL_RANGE:
364 0 : aPropertyValue <<= m_pHelper->createCellListSourceFromStringAddress( sControlValue );
365 0 : break;
366 :
367 : case PROPERTY_ID_BOUND_CELL:
368 : {
369 : // if we have the possibility of an integer binding, then we must preserve
370 : // this property's value (e.g. if the current binding is an integer binding, then
371 : // the newly created one must be, too)
372 0 : bool bIntegerBinding = false;
373 0 : if ( m_pHelper->isCellIntegerBindingAllowed() )
374 : {
375 0 : sal_Int16 nCurrentBindingType = 0;
376 0 : getPropertyValue( PROPERTY_CELL_EXCHANGE_TYPE ) >>= nCurrentBindingType;
377 0 : bIntegerBinding = ( nCurrentBindingType != 0 );
378 : }
379 0 : aPropertyValue <<= m_pHelper->createCellBindingFromStringAddress( sControlValue, bIntegerBinding );
380 : }
381 0 : break;
382 :
383 : case PROPERTY_ID_CELL_EXCHANGE_TYPE:
384 0 : m_pCellExchangeConverter->getValueFromDescription( sControlValue, aPropertyValue );
385 0 : break;
386 :
387 : default:
388 : OSL_FAIL( "CellBindingPropertyHandler::convertToPropertyValue: cannot handle this!" );
389 0 : break;
390 : }
391 :
392 0 : return aPropertyValue;
393 : }
394 :
395 :
396 0 : Any SAL_CALL CellBindingPropertyHandler::convertToControlValue( const OUString& _rPropertyName,
397 : const Any& _rPropertyValue, const Type& /*_rControlValueType*/ ) throw (UnknownPropertyException, RuntimeException, std::exception)
398 : {
399 0 : ::osl::MutexGuard aGuard( m_aMutex );
400 0 : Any aControlValue;
401 :
402 : OSL_ENSURE( m_pHelper.get(), "CellBindingPropertyHandler::convertToControlValue: we have no SupportedProperties!" );
403 0 : if ( !m_pHelper.get() )
404 0 : return aControlValue;
405 :
406 0 : PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) );
407 :
408 0 : switch ( nPropId )
409 : {
410 : case PROPERTY_ID_BOUND_CELL:
411 : {
412 0 : Reference< XValueBinding > xBinding;
413 : #if OSL_DEBUG_LEVEL > 0
414 : sal_Bool bSuccess =
415 : #endif
416 0 : _rPropertyValue >>= xBinding;
417 : OSL_ENSURE( bSuccess, "CellBindingPropertyHandler::convertToControlValue: invalid value (1)!" );
418 :
419 : // the only value binding we support so far is linking to spreadsheet cells
420 0 : aControlValue <<= m_pHelper->getStringAddressFromCellBinding( xBinding );
421 : }
422 0 : break;
423 :
424 : case PROPERTY_ID_LIST_CELL_RANGE:
425 : {
426 0 : Reference< XListEntrySource > xSource;
427 : #if OSL_DEBUG_LEVEL > 0
428 : sal_Bool bSuccess =
429 : #endif
430 0 : _rPropertyValue >>= xSource;
431 : OSL_ENSURE( bSuccess, "CellBindingPropertyHandler::convertToControlValue: invalid value (2)!" );
432 :
433 : // the only value binding we support so far is linking to spreadsheet cells
434 0 : aControlValue <<= m_pHelper->getStringAddressFromCellListSource( xSource );
435 : }
436 0 : break;
437 :
438 : case PROPERTY_ID_CELL_EXCHANGE_TYPE:
439 0 : aControlValue <<= m_pCellExchangeConverter->getDescriptionForValue( _rPropertyValue );
440 0 : break;
441 :
442 : default:
443 : OSL_FAIL( "CellBindingPropertyHandler::convertToControlValue: cannot handle this!" );
444 0 : break;
445 : }
446 :
447 0 : return aControlValue;
448 : }
449 :
450 :
451 0 : Sequence< Property > SAL_CALL CellBindingPropertyHandler::doDescribeSupportedProperties() const
452 : {
453 0 : ::std::vector< Property > aProperties;
454 :
455 0 : bool bAllowCellLinking = m_pHelper.get() && m_pHelper->isCellBindingAllowed();
456 0 : bool bAllowCellIntLinking = m_pHelper.get() && m_pHelper->isCellIntegerBindingAllowed();
457 0 : bool bAllowListCellRange = m_pHelper.get() && m_pHelper->isListCellRangeAllowed();
458 0 : if ( bAllowCellLinking || bAllowListCellRange || bAllowCellIntLinking )
459 : {
460 : sal_Int32 nPos = ( bAllowCellLinking ? 1 : 0 )
461 0 : + ( bAllowListCellRange ? 1 : 0 )
462 0 : + ( bAllowCellIntLinking ? 1 : 0 );
463 0 : aProperties.resize( nPos );
464 :
465 0 : if ( bAllowCellLinking )
466 : {
467 0 : aProperties[ --nPos ] = Property( PROPERTY_BOUND_CELL, PROPERTY_ID_BOUND_CELL,
468 0 : ::getCppuType( static_cast< OUString* >( NULL ) ), 0 );
469 : }
470 0 : if ( bAllowCellIntLinking )
471 : {
472 0 : aProperties[ --nPos ] = Property( PROPERTY_CELL_EXCHANGE_TYPE, PROPERTY_ID_CELL_EXCHANGE_TYPE,
473 0 : ::getCppuType( static_cast< sal_Int16* >( NULL ) ), 0 );
474 : }
475 0 : if ( bAllowListCellRange )
476 : {
477 0 : aProperties[ --nPos ] = Property( PROPERTY_LIST_CELL_RANGE, PROPERTY_ID_LIST_CELL_RANGE,
478 0 : ::getCppuType( static_cast< OUString* >( NULL ) ), 0 );
479 : }
480 : }
481 :
482 0 : if ( aProperties.empty() )
483 0 : return Sequence< Property >();
484 0 : return Sequence< Property >( &(*aProperties.begin()), aProperties.size() );
485 : }
486 :
487 :
488 : } // namespace pcr
489 :
490 :
491 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|