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