1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "celllistsource.hxx"
21 #include <tools/debug.hxx>
22 #include <com/sun/star/text/XTextRange.hpp>
23 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
24 #include <com/sun/star/util/XModifyBroadcaster.hpp>
25 #include <com/sun/star/container/XIndexAccess.hpp>
26 #include <com/sun/star/beans/PropertyAttribute.hpp>
27 #include <com/sun/star/beans/NamedValue.hpp>
29 //.........................................................................
32 //.........................................................................
34 #define PROP_HANDLE_RANGE_ADDRESS 1
36 using namespace ::com::sun::star::uno
;
37 using namespace ::com::sun::star::lang
;
38 using namespace ::com::sun::star::table
;
39 using namespace ::com::sun::star::text
;
40 using namespace ::com::sun::star::sheet
;
41 using namespace ::com::sun::star::container
;
42 using namespace ::com::sun::star::beans
;
43 using namespace ::com::sun::star::util
;
44 using namespace ::com::sun::star::form::binding
;
46 //=====================================================================
48 //=====================================================================
49 DBG_NAME( OCellListSource
)
50 //---------------------------------------------------------------------
52 const char* OCellListSource::checkConsistency_static( const void* _pThis
)
54 return static_cast< const OCellListSource
* >( _pThis
)->checkConsistency( );
57 const char* OCellListSource::checkConsistency( ) const
59 const char* pAssertion
= NULL
;
61 // TODO: place any checks here to ensure consistency of this instance
67 //---------------------------------------------------------------------
68 OCellListSource::OCellListSource( const Reference
< XSpreadsheetDocument
>& _rxDocument
)
69 :OCellListSource_Base( m_aMutex
)
70 ,OCellListSource_PBase( OCellListSource_Base::rBHelper
)
71 ,m_xDocument( _rxDocument
)
72 ,m_aListEntryListeners( m_aMutex
)
73 ,m_bInitialized( false )
75 DBG_CTOR( OCellListSource
, checkConsistency_static
);
77 OSL_PRECOND( m_xDocument
.is(), "OCellListSource::OCellListSource: invalid document!" );
79 // register our property at the base class
80 CellRangeAddress aInitialPropValue
;
81 registerPropertyNoMember(
82 OUString( "CellRange" ),
83 PROP_HANDLE_RANGE_ADDRESS
,
84 PropertyAttribute::BOUND
| PropertyAttribute::READONLY
,
85 ::getCppuType( &aInitialPropValue
),
90 //---------------------------------------------------------------------
91 OCellListSource::~OCellListSource( )
93 if ( !OCellListSource_Base::rBHelper
.bDisposed
)
95 acquire(); // prevent duplicate dtor
99 DBG_DTOR( OCellListSource
, checkConsistency_static
);
102 //--------------------------------------------------------------------
103 IMPLEMENT_FORWARD_XINTERFACE2( OCellListSource
, OCellListSource_Base
, OCellListSource_PBase
)
105 //--------------------------------------------------------------------
106 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellListSource
, OCellListSource_Base
, OCellListSource_PBase
)
108 //--------------------------------------------------------------------
109 void SAL_CALL
OCellListSource::disposing()
111 ::osl::MutexGuard
aGuard( m_aMutex
);
112 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
114 Reference
<XModifyBroadcaster
> xBroadcaster( m_xRange
, UNO_QUERY
);
115 if ( xBroadcaster
.is() )
117 xBroadcaster
->removeModifyListener( this );
120 EventObject
aDisposeEvent( *this );
121 m_aListEntryListeners
.disposeAndClear( aDisposeEvent
);
123 WeakAggComponentImplHelperBase::disposing();
125 // TODO: clean up here whatever you need to clean up (e.g. revoking listeners etc.)
128 //--------------------------------------------------------------------
129 Reference
< XPropertySetInfo
> SAL_CALL
OCellListSource::getPropertySetInfo( ) throw(RuntimeException
)
131 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
132 return createPropertySetInfo( getInfoHelper() ) ;
135 //--------------------------------------------------------------------
136 ::cppu::IPropertyArrayHelper
& SAL_CALL
OCellListSource::getInfoHelper()
138 return *OCellListSource_PABase::getArrayHelper();
141 //--------------------------------------------------------------------
142 ::cppu::IPropertyArrayHelper
* OCellListSource::createArrayHelper( ) const
144 Sequence
< Property
> aProps
;
145 describeProperties( aProps
);
146 return new ::cppu::OPropertyArrayHelper(aProps
);
149 //--------------------------------------------------------------------
150 void SAL_CALL
OCellListSource::getFastPropertyValue( Any
& _rValue
, sal_Int32 _nHandle
) const
152 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
153 OSL_ENSURE( _nHandle
== PROP_HANDLE_RANGE_ADDRESS
, "OCellListSource::getFastPropertyValue: invalid handle!" );
154 // we only have this one property ....
155 (void)_nHandle
; // avoid warning in product version
157 _rValue
<<= getRangeAddress( );
160 //--------------------------------------------------------------------
161 void OCellListSource::checkDisposed( ) const SAL_THROW( ( DisposedException
) )
163 if ( OCellListSource_Base::rBHelper
.bInDispose
|| OCellListSource_Base::rBHelper
.bDisposed
)
164 throw DisposedException();
165 // TODO: is it worth having an error message here?
168 //--------------------------------------------------------------------
169 void OCellListSource::checkInitialized() SAL_THROW( ( RuntimeException
) )
171 if ( !m_bInitialized
)
172 throw RuntimeException();
173 // TODO: error message
176 //--------------------------------------------------------------------
177 OUString SAL_CALL
OCellListSource::getImplementationName( ) throw (RuntimeException
)
179 return OUString( "com.sun.star.comp.sheet.OCellListSource" );
182 //--------------------------------------------------------------------
183 sal_Bool SAL_CALL
OCellListSource::supportsService( const OUString
& _rServiceName
) throw (RuntimeException
)
185 Sequence
< OUString
> aSupportedServices( getSupportedServiceNames() );
186 const OUString
* pLookup
= aSupportedServices
.getConstArray();
187 const OUString
* pLookupEnd
= aSupportedServices
.getConstArray() + aSupportedServices
.getLength();
188 while ( pLookup
!= pLookupEnd
)
189 if ( *pLookup
++ == _rServiceName
)
195 //--------------------------------------------------------------------
196 Sequence
< OUString
> SAL_CALL
OCellListSource::getSupportedServiceNames( ) throw (RuntimeException
)
198 Sequence
< OUString
> aServices( 2 );
199 aServices
[ 0 ] = "com.sun.star.table.CellRangeListSource";
200 aServices
[ 1 ] = "com.sun.star.form.binding.ListEntrySource";
204 //--------------------------------------------------------------------
205 CellRangeAddress
OCellListSource::getRangeAddress( ) const
207 OSL_PRECOND( m_xRange
.is(), "OCellListSource::getRangeAddress: invalid range!" );
209 CellRangeAddress aAddress
;
210 Reference
< XCellRangeAddressable
> xRangeAddress( m_xRange
, UNO_QUERY
);
211 if ( xRangeAddress
.is() )
212 aAddress
= xRangeAddress
->getRangeAddress( );
216 //--------------------------------------------------------------------
217 OUString
OCellListSource::getCellTextContent_noCheck( sal_Int32 _nRangeRelativeColumn
, sal_Int32 _nRangeRelativeRow
)
219 OSL_PRECOND( m_xRange
.is(), "OCellListSource::getRangeAddress: invalid range!" );
220 Reference
< XTextRange
> xCellText
;
222 xCellText
.set(xCellText
.query( m_xRange
->getCellByPosition( _nRangeRelativeColumn
, _nRangeRelativeRow
) ));
225 if ( xCellText
.is() )
226 sText
= xCellText
->getString();
230 //--------------------------------------------------------------------
231 sal_Int32 SAL_CALL
OCellListSource::getListEntryCount( ) throw (RuntimeException
)
233 ::osl::MutexGuard
aGuard( m_aMutex
);
234 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
238 CellRangeAddress
aAddress( getRangeAddress( ) );
239 return aAddress
.EndRow
- aAddress
.StartRow
+ 1;
242 //--------------------------------------------------------------------
243 OUString SAL_CALL
OCellListSource::getListEntry( sal_Int32 _nPosition
) throw (IndexOutOfBoundsException
, RuntimeException
)
245 ::osl::MutexGuard
aGuard( m_aMutex
);
246 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
250 if ( _nPosition
>= getListEntryCount() )
251 throw IndexOutOfBoundsException();
253 return getCellTextContent_noCheck( 0, _nPosition
);
256 //--------------------------------------------------------------------
257 Sequence
< OUString
> SAL_CALL
OCellListSource::getAllListEntries( ) throw (RuntimeException
)
259 ::osl::MutexGuard
aGuard( m_aMutex
);
260 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
264 Sequence
< OUString
> aAllEntries( getListEntryCount() );
265 OUString
* pAllEntries
= aAllEntries
.getArray();
266 for ( sal_Int32 i
= 0; i
< aAllEntries
.getLength(); ++i
)
268 *pAllEntries
++ = getCellTextContent_noCheck( 0, i
);
274 //--------------------------------------------------------------------
275 void SAL_CALL
OCellListSource::addListEntryListener( const Reference
< XListEntryListener
>& _rxListener
) throw (NullPointerException
, RuntimeException
)
277 ::osl::MutexGuard
aGuard( m_aMutex
);
278 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
282 if ( !_rxListener
.is() )
283 throw NullPointerException();
285 m_aListEntryListeners
.addInterface( _rxListener
);
288 //--------------------------------------------------------------------
289 void SAL_CALL
OCellListSource::removeListEntryListener( const Reference
< XListEntryListener
>& _rxListener
) throw (NullPointerException
, RuntimeException
)
291 ::osl::MutexGuard
aGuard( m_aMutex
);
292 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
296 if ( !_rxListener
.is() )
297 throw NullPointerException();
299 m_aListEntryListeners
.removeInterface( _rxListener
);
302 //--------------------------------------------------------------------
303 void SAL_CALL
OCellListSource::modified( const EventObject
& /* aEvent */ ) throw (RuntimeException
)
305 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
310 //--------------------------------------------------------------------
311 void OCellListSource::notifyModified()
314 aEvent
.Source
.set(*this);
316 ::cppu::OInterfaceIteratorHelper
aIter( m_aListEntryListeners
);
317 while ( aIter
.hasMoreElements() )
321 static_cast< XListEntryListener
* >( aIter
.next() )->allEntriesChanged( aEvent
);
323 catch( const RuntimeException
& )
327 catch( const Exception
& )
329 OSL_FAIL( "OCellListSource::notifyModified: caught a (non-runtime) exception!" );
335 //--------------------------------------------------------------------
336 void SAL_CALL
OCellListSource::disposing( const EventObject
& aEvent
) throw (RuntimeException
)
338 DBG_CHKTHIS( OCellListSource
, checkConsistency_static
);
340 Reference
<XInterface
> xRangeInt( m_xRange
, UNO_QUERY
);
341 if ( xRangeInt
== aEvent
.Source
)
343 // release references to range object
348 //--------------------------------------------------------------------
349 void SAL_CALL
OCellListSource::initialize( const Sequence
< Any
>& _rArguments
) throw (Exception
, RuntimeException
)
351 if ( m_bInitialized
)
353 // TODO: error message
355 // get the cell address
356 CellRangeAddress aRangeAddress
;
357 sal_Bool bFoundAddress
= false;
359 const Any
* pLoop
= _rArguments
.getConstArray();
360 const Any
* pLoopEnd
= _rArguments
.getConstArray() + _rArguments
.getLength();
361 for ( ; ( pLoop
!= pLoopEnd
) && !bFoundAddress
; ++pLoop
)
364 if ( *pLoop
>>= aValue
)
366 if ( aValue
.Name
== "CellRange" )
368 if ( aValue
.Value
>>= aRangeAddress
)
369 bFoundAddress
= sal_True
;
374 if ( !bFoundAddress
)
375 // TODO: error message
378 // determine the range we're bound to
381 if ( m_xDocument
.is() )
383 // first the sheets collection
384 Reference
< XIndexAccess
> xSheets(m_xDocument
->getSheets( ), UNO_QUERY
);
385 OSL_ENSURE( xSheets
.is(), "OCellListSource::initialize: could not retrieve the sheets!" );
389 // the concrete sheet
390 Reference
< XCellRange
> xSheet(xSheets
->getByIndex( aRangeAddress
.Sheet
), UNO_QUERY
);
391 OSL_ENSURE( xSheet
.is(), "OCellListSource::initialize: NULL sheet, but no exception!" );
396 m_xRange
.set(xSheet
->getCellRangeByPosition(
397 aRangeAddress
.StartColumn
, aRangeAddress
.StartRow
,
398 aRangeAddress
.EndColumn
, aRangeAddress
.EndRow
));
399 OSL_ENSURE( Reference
< XCellRangeAddressable
>( m_xRange
, UNO_QUERY
).is(), "OCellListSource::initialize: either NULL range, or cell without address access!" );
404 catch( const Exception
& )
406 OSL_FAIL( "OCellListSource::initialize: caught an exception while retrieving the cell object!" );
410 if ( !m_xRange
.is() )
412 // TODO error message
414 Reference
<XModifyBroadcaster
> xBroadcaster( m_xRange
, UNO_QUERY
);
415 if ( xBroadcaster
.is() )
417 xBroadcaster
->addModifyListener( this );
420 // TODO: add as XEventListener to the cell range, so we get notified when it dies,
421 // and can dispose ourself then
423 // TODO: somehow add as listener so we get notified when the address of the cell range changes
424 // We need to forward this as change in our CellRange property to our property change listeners
426 // TODO: somehow add as listener to the cells in the range, so that we get notified
427 // when their content changes. We need to forward this to our list entry listeners then
429 // TODO: somehow add as listener so that we get notified of insertions and removals of rows in our
430 // range. In this case, we need to fire a change in our CellRange property, and additionally
431 // notify our XListEntryListeners
433 m_bInitialized
= sal_True
;
436 //.........................................................................
438 //.........................................................................
440 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */