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