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