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