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