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