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 "cellvaluebinding.hxx"
21 : #include <tools/debug.hxx>
22 : #include <rtl/math.hxx>
23 : #include <com/sun/star/table/XCellRange.hpp>
24 : #include <com/sun/star/sheet/XCellAddressable.hpp>
25 : #include <com/sun/star/sheet/XCellRangeData.hpp>
26 : #include <com/sun/star/container/XIndexAccess.hpp>
27 : #include <com/sun/star/beans/PropertyAttribute.hpp>
28 : #include <com/sun/star/beans/NamedValue.hpp>
29 : #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
30 : #include <com/sun/star/util/XNumberFormatTypes.hpp>
31 : #include <com/sun/star/util/NumberFormat.hpp>
32 :
33 : //.........................................................................
34 : namespace calc
35 : {
36 : //.........................................................................
37 :
38 : #define PROP_HANDLE_BOUND_CELL 1
39 :
40 : using namespace ::com::sun::star::uno;
41 : using namespace ::com::sun::star::lang;
42 : using namespace ::com::sun::star::table;
43 : using namespace ::com::sun::star::text;
44 : using namespace ::com::sun::star::sheet;
45 : using namespace ::com::sun::star::container;
46 : using namespace ::com::sun::star::beans;
47 : using namespace ::com::sun::star::util;
48 : using namespace ::com::sun::star::form::binding;
49 :
50 : //=====================================================================
51 : //= OCellValueBinding
52 : //=====================================================================
53 : DBG_NAME( OCellValueBinding )
54 : //---------------------------------------------------------------------
55 : #ifdef DBG_UTIL
56 : const char* OCellValueBinding::checkConsistency_static( const void* _pThis )
57 : {
58 : return static_cast< const OCellValueBinding* >( _pThis )->checkConsistency( );
59 : }
60 :
61 : const char* OCellValueBinding::checkConsistency( ) const
62 : {
63 : const char* pAssertion = NULL;
64 : if ( m_xCellText.is() && !m_xCell.is() )
65 : // there are places (e.g. getSupportedTypes) which rely on the fact
66 : // that m_xCellText.is() implies m_xCell.is()
67 : pAssertion = "cell references inconsistent!";
68 :
69 : // TODO: place any additional checks here to ensure consistency of this instance
70 : return pAssertion;
71 : }
72 : #endif
73 :
74 : //---------------------------------------------------------------------
75 4 : OCellValueBinding::OCellValueBinding( const Reference< XSpreadsheetDocument >& _rxDocument, sal_Bool _bListPos )
76 : :OCellValueBinding_Base( m_aMutex )
77 : ,OCellValueBinding_PBase( OCellValueBinding_Base::rBHelper )
78 : ,m_xDocument( _rxDocument )
79 : ,m_aModifyListeners( m_aMutex )
80 : ,m_bInitialized( false )
81 4 : ,m_bListPos( _bListPos )
82 : {
83 : DBG_CTOR( OCellValueBinding, checkConsistency_static );
84 :
85 : // register our property at the base class
86 4 : CellAddress aInitialPropValue;
87 : registerPropertyNoMember(
88 : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "BoundCell" )),
89 : PROP_HANDLE_BOUND_CELL,
90 : PropertyAttribute::BOUND | PropertyAttribute::READONLY,
91 4 : ::getCppuType( &aInitialPropValue ),
92 : &aInitialPropValue
93 4 : );
94 :
95 : // TODO: implement a ReadOnly property as required by the service,
96 : // which probably maps to the cell being locked
97 4 : }
98 :
99 : //---------------------------------------------------------------------
100 12 : OCellValueBinding::~OCellValueBinding( )
101 : {
102 4 : if ( !OCellValueBinding_Base::rBHelper.bDisposed )
103 : {
104 0 : acquire(); // prevent duplicate dtor
105 0 : dispose();
106 : }
107 :
108 : DBG_DTOR( OCellValueBinding, checkConsistency_static );
109 8 : }
110 :
111 : //--------------------------------------------------------------------
112 188 : IMPLEMENT_FORWARD_XINTERFACE2( OCellValueBinding, OCellValueBinding_Base, OCellValueBinding_PBase )
113 :
114 : //--------------------------------------------------------------------
115 0 : IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellValueBinding, OCellValueBinding_Base, OCellValueBinding_PBase )
116 :
117 : //--------------------------------------------------------------------
118 4 : void SAL_CALL OCellValueBinding::disposing()
119 : {
120 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
121 :
122 4 : Reference<XModifyBroadcaster> xBroadcaster( m_xCell, UNO_QUERY );
123 4 : if ( xBroadcaster.is() )
124 : {
125 0 : xBroadcaster->removeModifyListener( this );
126 : }
127 :
128 4 : WeakAggComponentImplHelperBase::disposing();
129 :
130 : // TODO: clean up here whatever you need to clean up (e.g. deregister as XEventListener
131 : // for the cell)
132 4 : }
133 :
134 : //--------------------------------------------------------------------
135 4 : Reference< XPropertySetInfo > SAL_CALL OCellValueBinding::getPropertySetInfo( ) throw(RuntimeException)
136 : {
137 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
138 4 : return createPropertySetInfo( getInfoHelper() ) ;
139 : }
140 :
141 : //--------------------------------------------------------------------
142 4 : ::cppu::IPropertyArrayHelper& SAL_CALL OCellValueBinding::getInfoHelper()
143 : {
144 4 : return *OCellValueBinding_PABase::getArrayHelper();
145 : }
146 :
147 : //--------------------------------------------------------------------
148 1 : ::cppu::IPropertyArrayHelper* OCellValueBinding::createArrayHelper( ) const
149 : {
150 1 : Sequence< Property > aProps;
151 1 : describeProperties( aProps );
152 1 : return new ::cppu::OPropertyArrayHelper(aProps);
153 : }
154 :
155 : //--------------------------------------------------------------------
156 0 : void SAL_CALL OCellValueBinding::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
157 : {
158 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
159 : OSL_ENSURE( _nHandle == PROP_HANDLE_BOUND_CELL, "OCellValueBinding::getFastPropertyValue: invalid handle!" );
160 : // we only have this one property ....
161 : (void)_nHandle; // avoid warning in product version
162 :
163 0 : _rValue.clear();
164 0 : Reference< XCellAddressable > xCellAddress( m_xCell, UNO_QUERY );
165 0 : if ( xCellAddress.is() )
166 0 : _rValue <<= xCellAddress->getCellAddress( );
167 0 : }
168 :
169 : //--------------------------------------------------------------------
170 13 : Sequence< Type > SAL_CALL OCellValueBinding::getSupportedValueTypes( ) throw (RuntimeException)
171 : {
172 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
173 13 : checkDisposed( );
174 13 : checkInitialized( );
175 :
176 13 : sal_Int32 nCount = m_xCellText.is() ? 3 : m_xCell.is() ? 1 : 0;
177 13 : if ( m_bListPos )
178 13 : ++nCount;
179 :
180 13 : Sequence< Type > aTypes( nCount );
181 13 : if ( m_xCell.is() )
182 : {
183 : // an XCell can be used to set/get "double" values
184 13 : aTypes[0] = ::getCppuType( static_cast< double* >( NULL ) );
185 13 : if ( m_xCellText.is() )
186 : {
187 : // an XTextRange can be used to set/get "string" values
188 13 : aTypes[1] = ::getCppuType( static_cast< ::rtl::OUString* >( NULL ) );
189 : // and additionally, we use it to handle booleans
190 13 : aTypes[2] = ::getCppuType( static_cast< sal_Bool* >( NULL ) );
191 : }
192 :
193 : // add sal_Int32 only if constructed as ListPositionCellBinding
194 13 : if ( m_bListPos )
195 13 : aTypes[nCount-1] = ::getCppuType( static_cast< sal_Int32* >( NULL ) );
196 : }
197 :
198 13 : return aTypes;
199 : }
200 :
201 : //--------------------------------------------------------------------
202 13 : sal_Bool SAL_CALL OCellValueBinding::supportsType( const Type& aType ) throw (RuntimeException)
203 : {
204 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
205 13 : checkDisposed( );
206 13 : checkInitialized( );
207 :
208 : // look up in our sequence
209 13 : Sequence< Type > aSupportedTypes( getSupportedValueTypes() );
210 13 : const Type* pTypes = aSupportedTypes.getConstArray();
211 13 : const Type* pTypesEnd = aSupportedTypes.getConstArray() + aSupportedTypes.getLength();
212 42 : while ( pTypes != pTypesEnd )
213 29 : if ( aType.equals( *pTypes++ ) )
214 13 : return sal_True;
215 :
216 0 : return false;
217 : }
218 :
219 : //--------------------------------------------------------------------
220 4 : Any SAL_CALL OCellValueBinding::getValue( const Type& aType ) throw (IncompatibleTypesException, RuntimeException)
221 : {
222 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
223 4 : checkDisposed( );
224 4 : checkInitialized( );
225 4 : checkValueType( aType );
226 :
227 4 : Any aReturn;
228 4 : switch ( aType.getTypeClass() )
229 : {
230 : case TypeClass_STRING:
231 : OSL_ENSURE( m_xCellText.is(), "OCellValueBinding::getValue: don't have a text!" );
232 3 : if ( m_xCellText.is() )
233 3 : aReturn <<= m_xCellText->getString();
234 : else
235 0 : aReturn <<= ::rtl::OUString();
236 3 : break;
237 :
238 : case TypeClass_BOOLEAN:
239 : OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
240 1 : if ( m_xCell.is() )
241 : {
242 : // check if the cell has a numeric value (this might go into a helper function):
243 :
244 1 : sal_Bool bHasValue = false;
245 1 : CellContentType eCellType = m_xCell->getType();
246 1 : if ( eCellType == CellContentType_VALUE )
247 1 : bHasValue = sal_True;
248 0 : else if ( eCellType == CellContentType_FORMULA )
249 : {
250 : // check if the formula result is a value
251 0 : if ( m_xCell->getError() == 0 )
252 : {
253 0 : Reference<XPropertySet> xProp( m_xCell, UNO_QUERY );
254 0 : if ( xProp.is() )
255 : {
256 : CellContentType eResultType;
257 0 : if ( (xProp->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "FormulaResultType" )) ) >>= eResultType) && eResultType == CellContentType_VALUE )
258 0 : bHasValue = sal_True;
259 0 : }
260 : }
261 : }
262 :
263 1 : if ( bHasValue )
264 : {
265 : // 0 is "unchecked", any other value is "checked", regardless of number format
266 1 : double nCellValue = m_xCell->getValue();
267 1 : sal_Bool bBoolValue = ( nCellValue != 0.0 );
268 1 : aReturn <<= bBoolValue;
269 : }
270 : // empty cells, text cells and text or error formula results: leave return value empty
271 : }
272 1 : break;
273 :
274 : case TypeClass_DOUBLE:
275 : OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
276 0 : if ( m_xCell.is() )
277 0 : aReturn <<= m_xCell->getValue();
278 : else
279 0 : aReturn <<= (double)0;
280 0 : break;
281 :
282 : case TypeClass_LONG:
283 : OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
284 0 : if ( m_xCell.is() )
285 : {
286 : // The list position value in the cell is 1-based.
287 : // We subtract 1 from any cell value (no special handling for 0 or negative values).
288 :
289 0 : sal_Int32 nValue = (sal_Int32) rtl::math::approxFloor( m_xCell->getValue() );
290 0 : --nValue;
291 :
292 0 : aReturn <<= nValue;
293 : }
294 : else
295 0 : aReturn <<= (sal_Int32)0;
296 0 : break;
297 :
298 : default:
299 : OSL_FAIL( "OCellValueBinding::getValue: unreachable code!" );
300 : // a type other than double and string should never have survived the checkValueType
301 : // above
302 : }
303 4 : return aReturn;
304 : }
305 :
306 : //--------------------------------------------------------------------
307 0 : void SAL_CALL OCellValueBinding::setValue( const Any& aValue ) throw (IncompatibleTypesException, NoSupportException, RuntimeException)
308 : {
309 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
310 0 : checkDisposed( );
311 0 : checkInitialized( );
312 0 : if ( aValue.hasValue() )
313 0 : checkValueType( aValue.getValueType() );
314 :
315 0 : switch ( aValue.getValueType().getTypeClass() )
316 : {
317 : case TypeClass_STRING:
318 : {
319 : OSL_ENSURE( m_xCellText.is(), "OCellValueBinding::setValue: don't have a text!" );
320 :
321 0 : ::rtl::OUString sText;
322 0 : aValue >>= sText;
323 0 : if ( m_xCellText.is() )
324 0 : m_xCellText->setString( sText );
325 : }
326 0 : break;
327 :
328 : case TypeClass_BOOLEAN:
329 : {
330 : OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
331 :
332 : // boolean is stored as values 0 or 1
333 : // TODO: set the number format to boolean if no format is set?
334 :
335 0 : sal_Bool bValue( false );
336 0 : aValue >>= bValue;
337 0 : double nCellValue = bValue ? 1.0 : 0.0;
338 :
339 0 : if ( m_xCell.is() )
340 0 : m_xCell->setValue( nCellValue );
341 :
342 0 : setBooleanFormat();
343 : }
344 0 : break;
345 :
346 : case TypeClass_DOUBLE:
347 : {
348 : OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
349 :
350 0 : double nValue = 0;
351 0 : aValue >>= nValue;
352 0 : if ( m_xCell.is() )
353 0 : m_xCell->setValue( nValue );
354 : }
355 0 : break;
356 :
357 : case TypeClass_LONG:
358 : {
359 : OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
360 :
361 0 : sal_Int32 nValue = 0;
362 0 : aValue >>= nValue; // list index from control layer (0-based)
363 0 : ++nValue; // the list position value in the cell is 1-based
364 0 : if ( m_xCell.is() )
365 0 : m_xCell->setValue( nValue );
366 : }
367 0 : break;
368 :
369 : case TypeClass_VOID:
370 : {
371 : // #N/A error value can only be set using XCellRangeData
372 :
373 0 : Reference<XCellRangeData> xData( m_xCell, UNO_QUERY );
374 : OSL_ENSURE( xData.is(), "OCellValueBinding::setValue: don't have XCellRangeData!" );
375 0 : if ( xData.is() )
376 : {
377 0 : Sequence<Any> aInner(1); // one empty element
378 0 : Sequence< Sequence<Any> > aOuter( &aInner, 1 ); // one row
379 0 : xData->setDataArray( aOuter );
380 0 : }
381 : }
382 0 : break;
383 :
384 : default:
385 : OSL_FAIL( "OCellValueBinding::setValue: unreachable code!" );
386 : // a type other than double and string should never have survived the checkValueType
387 : // above
388 : }
389 0 : }
390 : //--------------------------------------------------------------------
391 0 : void OCellValueBinding::setBooleanFormat()
392 : {
393 : // set boolean number format if not already set
394 :
395 0 : ::rtl::OUString sPropName( RTL_CONSTASCII_USTRINGPARAM( "NumberFormat" ) );
396 0 : Reference<XPropertySet> xCellProp( m_xCell, UNO_QUERY );
397 0 : Reference<XNumberFormatsSupplier> xSupplier( m_xDocument, UNO_QUERY );
398 0 : if ( xSupplier.is() && xCellProp.is() )
399 : {
400 0 : Reference<XNumberFormats> xFormats(xSupplier->getNumberFormats());
401 0 : Reference<XNumberFormatTypes> xTypes( xFormats, UNO_QUERY );
402 0 : if ( xTypes.is() )
403 : {
404 0 : Locale aLocale;
405 0 : sal_Bool bWasBoolean = false;
406 :
407 0 : sal_Int32 nOldIndex = ::comphelper::getINT32( xCellProp->getPropertyValue( sPropName ) );
408 0 : Reference<XPropertySet> xOldFormat;
409 : try
410 : {
411 0 : xOldFormat.set(xFormats->getByKey( nOldIndex ));
412 : }
413 0 : catch ( Exception& )
414 : {
415 : // non-existing format - can happen, use defaults
416 : }
417 0 : if ( xOldFormat.is() )
418 : {
419 : // use the locale of the existing format
420 0 : xOldFormat->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Locale" )) ) >>= aLocale;
421 :
422 : sal_Int16 nOldType = ::comphelper::getINT16(
423 0 : xOldFormat->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Type" )) ) );
424 0 : if ( nOldType & NumberFormat::LOGICAL )
425 0 : bWasBoolean = sal_True;
426 : }
427 :
428 0 : if ( !bWasBoolean )
429 : {
430 0 : sal_Int32 nNewIndex = xTypes->getStandardFormat( NumberFormat::LOGICAL, aLocale );
431 0 : xCellProp->setPropertyValue( sPropName, makeAny( nNewIndex ) );
432 0 : }
433 0 : }
434 0 : }
435 0 : }
436 :
437 : //--------------------------------------------------------------------
438 30 : void OCellValueBinding::checkDisposed( ) const SAL_THROW( ( DisposedException ) )
439 : {
440 30 : if ( OCellValueBinding_Base::rBHelper.bInDispose || OCellValueBinding_Base::rBHelper.bDisposed )
441 0 : throw DisposedException();
442 : // TODO: is it worth having an error message here?
443 30 : }
444 :
445 : //--------------------------------------------------------------------
446 30 : void OCellValueBinding::checkInitialized() SAL_THROW( ( RuntimeException ) )
447 : {
448 30 : if ( !m_bInitialized )
449 0 : throw RuntimeException();
450 : // TODO: error message
451 30 : }
452 :
453 : //--------------------------------------------------------------------
454 4 : void OCellValueBinding::checkValueType( const Type& _rType ) const SAL_THROW( ( IncompatibleTypesException ) )
455 : {
456 4 : OCellValueBinding* pNonConstThis = const_cast< OCellValueBinding* >( this );
457 4 : if ( !pNonConstThis->supportsType( _rType ) )
458 : {
459 0 : ::rtl::OUString sMessage( RTL_CONSTASCII_USTRINGPARAM( "The given type (" ) );
460 0 : sMessage += _rType.getTypeName();
461 0 : sMessage += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ") is not supported by this binding." ) );
462 : // TODO: localize this error message
463 :
464 0 : throw IncompatibleTypesException( sMessage, *pNonConstThis );
465 : // TODO: alternatively use a type converter service for this?
466 : }
467 4 : }
468 :
469 : //--------------------------------------------------------------------
470 0 : ::rtl::OUString SAL_CALL OCellValueBinding::getImplementationName( ) throw (RuntimeException)
471 : {
472 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
473 :
474 0 : return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.sheet.OCellValueBinding" ) );
475 : }
476 :
477 : //--------------------------------------------------------------------
478 0 : sal_Bool SAL_CALL OCellValueBinding::supportsService( const ::rtl::OUString& _rServiceName ) throw (RuntimeException)
479 : {
480 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
481 :
482 0 : Sequence< ::rtl::OUString > aSupportedServices( getSupportedServiceNames() );
483 0 : const ::rtl::OUString* pLookup = aSupportedServices.getConstArray();
484 0 : const ::rtl::OUString* pLookupEnd = aSupportedServices.getConstArray() + aSupportedServices.getLength();
485 0 : while ( pLookup != pLookupEnd )
486 0 : if ( *pLookup++ == _rServiceName )
487 0 : return sal_True;
488 :
489 0 : return false;
490 : }
491 :
492 : //--------------------------------------------------------------------
493 0 : Sequence< ::rtl::OUString > SAL_CALL OCellValueBinding::getSupportedServiceNames( ) throw (RuntimeException)
494 : {
495 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
496 :
497 0 : Sequence< ::rtl::OUString > aServices( m_bListPos ? 3 : 2 );
498 0 : aServices[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.table.CellValueBinding" ) );
499 0 : aServices[ 1 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.binding.ValueBinding" ) );
500 0 : if ( m_bListPos )
501 0 : aServices[ 2 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.table.ListPositionCellBinding" ) );
502 0 : return aServices;
503 : }
504 :
505 : //--------------------------------------------------------------------
506 4 : void SAL_CALL OCellValueBinding::addModifyListener( const Reference< XModifyListener >& _rxListener ) throw (RuntimeException)
507 : {
508 4 : if ( _rxListener.is() )
509 4 : m_aModifyListeners.addInterface( _rxListener );
510 4 : }
511 :
512 : //--------------------------------------------------------------------
513 4 : void SAL_CALL OCellValueBinding::removeModifyListener( const Reference< XModifyListener >& _rxListener ) throw (RuntimeException)
514 : {
515 4 : if ( _rxListener.is() )
516 4 : m_aModifyListeners.removeInterface( _rxListener );
517 4 : }
518 :
519 : //--------------------------------------------------------------------
520 0 : void OCellValueBinding::notifyModified()
521 : {
522 0 : EventObject aEvent;
523 0 : aEvent.Source.set(*this);
524 :
525 0 : ::cppu::OInterfaceIteratorHelper aIter( m_aModifyListeners );
526 0 : while ( aIter.hasMoreElements() )
527 : {
528 : try
529 : {
530 0 : static_cast< XModifyListener* >( aIter.next() )->modified( aEvent );
531 : }
532 0 : catch( const RuntimeException& )
533 : {
534 : // silent this
535 : }
536 0 : catch( const Exception& )
537 : {
538 : OSL_FAIL( "OCellValueBinding::notifyModified: caught a (non-runtime) exception!" );
539 : }
540 0 : }
541 0 : }
542 :
543 : //--------------------------------------------------------------------
544 0 : void SAL_CALL OCellValueBinding::modified( const EventObject& /* aEvent */ ) throw (RuntimeException)
545 : {
546 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
547 :
548 0 : notifyModified();
549 0 : }
550 :
551 : //--------------------------------------------------------------------
552 4 : void SAL_CALL OCellValueBinding::disposing( const EventObject& aEvent ) throw (RuntimeException)
553 : {
554 : DBG_CHKTHIS( OCellValueBinding, checkConsistency_static );
555 :
556 4 : Reference<XInterface> xCellInt( m_xCell, UNO_QUERY );
557 4 : if ( xCellInt == aEvent.Source )
558 : {
559 : // release references to cell object
560 4 : m_xCell.clear();
561 4 : m_xCellText.clear();
562 4 : }
563 4 : }
564 :
565 : //--------------------------------------------------------------------
566 4 : void SAL_CALL OCellValueBinding::initialize( const Sequence< Any >& _rArguments ) throw (Exception, RuntimeException)
567 : {
568 4 : if ( m_bInitialized )
569 0 : throw Exception();
570 : // TODO: error message
571 :
572 : // get the cell address
573 4 : CellAddress aAddress;
574 4 : sal_Bool bFoundAddress = false;
575 :
576 4 : const Any* pLoop = _rArguments.getConstArray();
577 4 : const Any* pLoopEnd = _rArguments.getConstArray() + _rArguments.getLength();
578 8 : for ( ; ( pLoop != pLoopEnd ) && !bFoundAddress; ++pLoop )
579 : {
580 4 : NamedValue aValue;
581 4 : if ( *pLoop >>= aValue )
582 : {
583 4 : if ( aValue.Name == "BoundCell" )
584 : {
585 4 : if ( aValue.Value >>= aAddress )
586 4 : bFoundAddress = sal_True;
587 : }
588 : }
589 4 : }
590 :
591 4 : if ( !bFoundAddress )
592 : // TODO: error message
593 0 : throw Exception();
594 :
595 : // get the cell object
596 : try
597 : {
598 : // first the sheets collection
599 4 : Reference< XIndexAccess > xSheets;
600 4 : if ( m_xDocument.is() )
601 4 : xSheets.set(xSheets.query( m_xDocument->getSheets( ) ));
602 : OSL_ENSURE( xSheets.is(), "OCellValueBinding::initialize: could not retrieve the sheets!" );
603 :
604 4 : if ( xSheets.is() )
605 : {
606 : // the concrete sheet
607 4 : Reference< XCellRange > xSheet(xSheets->getByIndex( aAddress.Sheet ), UNO_QUERY);
608 : OSL_ENSURE( xSheet.is(), "OCellValueBinding::initialize: NULL sheet, but no exception!" );
609 :
610 : // the concrete cell
611 4 : if ( xSheet.is() )
612 : {
613 4 : m_xCell.set(xSheet->getCellByPosition( aAddress.Column, aAddress.Row ));
614 4 : Reference< XCellAddressable > xAddressAccess( m_xCell, UNO_QUERY );
615 4 : OSL_ENSURE( xAddressAccess.is(), "OCellValueBinding::initialize: either NULL cell, or cell without address access!" );
616 4 : }
617 4 : }
618 : }
619 0 : catch( const Exception& )
620 : {
621 : OSL_FAIL( "OCellValueBinding::initialize: caught an exception while retrieving the cell object!" );
622 : }
623 :
624 4 : if ( !m_xCell.is() )
625 0 : throw Exception();
626 : // TODO error message
627 :
628 4 : m_xCellText.set(m_xCellText.query( m_xCell ));
629 :
630 4 : Reference<XModifyBroadcaster> xBroadcaster( m_xCell, UNO_QUERY );
631 4 : if ( xBroadcaster.is() )
632 : {
633 4 : xBroadcaster->addModifyListener( this );
634 : }
635 :
636 : // TODO: add as XEventListener to the cell, so we get notified when it dies,
637 : // and can dispose ourself then
638 :
639 : // TODO: somehow add as listener so we get notified when the address of the cell changes
640 : // We need to forward this as change in our BoundCell property to our property change listeners
641 :
642 : // TODO: be an XModifyBroadcaster, so that changes in our cell can be notified
643 : // to the BindableValue which is/will be bound to this instance.
644 :
645 4 : m_bInitialized = sal_True;
646 : // TODO: place your code here
647 4 : }
648 :
649 :
650 : //.........................................................................
651 : } // namespace calc
652 : //.........................................................................
653 :
654 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|