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