tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / unoobj / celllistsource.cxx
blob19a1a94822bb4a70bb1e7131987ac6590eafb7db
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <com/sun/star/lang/IndexOutOfBoundsException.hpp>
22 #include <com/sun/star/lang/NotInitializedException.hpp>
23 #include <com/sun/star/lang/NullPointerException.hpp>
24 #include <com/sun/star/table/XCellRange.hpp>
25 #include <com/sun/star/text/XTextRange.hpp>
26 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
27 #include <com/sun/star/sheet/FormulaResult.hpp>
28 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
29 #include <com/sun/star/util/XModifyBroadcaster.hpp>
30 #include <com/sun/star/container/XIndexAccess.hpp>
31 #include <com/sun/star/beans/PropertyAttribute.hpp>
32 #include <com/sun/star/beans/NamedValue.hpp>
33 #include <cppuhelper/supportsservice.hxx>
34 #include <comphelper/diagnose_ex.hxx>
36 namespace calc
39 #define PROP_HANDLE_RANGE_ADDRESS 1
41 using namespace ::com::sun::star::uno;
42 using namespace ::com::sun::star::lang;
43 using namespace ::com::sun::star::table;
44 using namespace ::com::sun::star::text;
45 using namespace ::com::sun::star::sheet;
46 using namespace ::com::sun::star::container;
47 using namespace ::com::sun::star::beans;
48 using namespace ::com::sun::star::util;
49 using namespace ::com::sun::star::form::binding;
51 OCellListSource::OCellListSource( const Reference< XSpreadsheetDocument >& _rxDocument )
52 :m_xDocument( _rxDocument )
53 ,m_bInitialized( false )
55 OSL_PRECOND( m_xDocument.is(), "OCellListSource::OCellListSource: invalid document!" );
57 // register our property at the base class
58 registerPropertyNoMember(
59 u"CellRange"_ustr,
60 PROP_HANDLE_RANGE_ADDRESS,
61 PropertyAttribute::BOUND | PropertyAttribute::READONLY,
62 cppu::UnoType<CellRangeAddress>::get(),
63 css::uno::Any(CellRangeAddress())
67 OCellListSource::~OCellListSource( )
69 if ( !m_bDisposed )
71 acquire(); // prevent duplicate dtor
72 dispose();
76 IMPLEMENT_FORWARD_XINTERFACE2( OCellListSource, OCellListSource_Base, OCellListSource_PBase )
78 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellListSource, OCellListSource_Base, OCellListSource_PBase )
80 void OCellListSource::disposing(std::unique_lock<std::mutex>& rGuard)
82 Reference<XModifyBroadcaster> xBroadcaster( m_xRange, UNO_QUERY );
83 if ( xBroadcaster.is() )
85 xBroadcaster->removeModifyListener( this );
88 EventObject aDisposeEvent( *this );
89 m_aListEntryListeners.disposeAndClear( rGuard, aDisposeEvent );
91 WeakComponentImplHelperBase::disposing(rGuard);
93 // TODO: clean up here whatever you need to clean up (e.g. revoking listeners etc.)
96 Reference< XPropertySetInfo > SAL_CALL OCellListSource::getPropertySetInfo( )
98 return createPropertySetInfo( getInfoHelper() ) ;
101 ::cppu::IPropertyArrayHelper& OCellListSource::getInfoHelper()
103 return *OCellListSource_PABase::getArrayHelper();
106 ::cppu::IPropertyArrayHelper* OCellListSource::createArrayHelper( ) const
108 Sequence< Property > aProps;
109 describeProperties( aProps );
110 return new ::cppu::OPropertyArrayHelper(aProps);
113 void OCellListSource::getFastPropertyValue( std::unique_lock<std::mutex>& /*rGuard*/, Any& _rValue, sal_Int32 _nHandle ) const
115 OSL_ENSURE( _nHandle == PROP_HANDLE_RANGE_ADDRESS, "OCellListSource::getFastPropertyValue: invalid handle!" );
116 // we only have this one property...
118 _rValue <<= getRangeAddress( );
121 void OCellListSource::checkInitialized()
123 if ( !m_bInitialized )
124 throw NotInitializedException(u"CellListSource is not initialized"_ustr, getXWeak());
127 OUString SAL_CALL OCellListSource::getImplementationName( )
129 return u"com.sun.star.comp.sheet.OCellListSource"_ustr;
132 sal_Bool SAL_CALL OCellListSource::supportsService( const OUString& _rServiceName )
134 return cppu::supportsService(this, _rServiceName);
137 Sequence< OUString > SAL_CALL OCellListSource::getSupportedServiceNames( )
139 return {u"com.sun.star.table.CellRangeListSource"_ustr,
140 u"com.sun.star.form.binding.ListEntrySource"_ustr};
143 CellRangeAddress OCellListSource::getRangeAddress( ) const
145 OSL_PRECOND( m_xRange.is(), "OCellListSource::getRangeAddress: invalid range!" );
147 CellRangeAddress aAddress;
148 Reference< XCellRangeAddressable > xRangeAddress( m_xRange, UNO_QUERY );
149 if ( xRangeAddress.is() )
150 aAddress = xRangeAddress->getRangeAddress( );
151 return aAddress;
154 OUString OCellListSource::getCellTextContent_noCheck( std::unique_lock<std::mutex>& /*rGuard*/, sal_Int32 _nRangeRelativeRow, css::uno::Any* pAny )
156 OUString sText;
158 OSL_PRECOND( m_xRange.is(), "OCellListSource::getRangeAddress: invalid range!" );
160 if (!m_xRange.is())
161 return sText;
163 Reference< XCell > xCell( m_xRange->getCellByPosition( 0, _nRangeRelativeRow ));
164 if (!xCell.is())
166 if (pAny)
167 *pAny <<= sText;
168 return sText;
171 Reference< XTextRange > xCellText;
172 xCellText.set( xCell, UNO_QUERY);
174 if (xCellText.is())
175 sText = xCellText->getString(); // formatted output string
177 if (pAny)
179 switch (xCell->getType())
181 case CellContentType_VALUE:
182 *pAny <<= xCell->getValue();
183 break;
184 case CellContentType_TEXT:
185 *pAny <<= sText;
186 break;
187 case CellContentType_FORMULA:
188 if (xCell->getError())
189 *pAny <<= sText; // Err:... or #...!
190 else
192 Reference< XPropertySet > xProp( xCell, UNO_QUERY);
193 if (xProp.is())
195 sal_Int32 nResultType;
196 if ((xProp->getPropertyValue(u"FormulaResultType2"_ustr) >>= nResultType) &&
197 nResultType == FormulaResult::VALUE)
198 *pAny <<= xCell->getValue();
199 else
200 *pAny <<= sText;
203 break;
204 case CellContentType_EMPTY:
205 *pAny <<= OUString();
206 break;
207 default:
208 ; // nothing, if actually occurred it would result in #N/A being displayed if selected
212 return sText;
215 sal_Int32 SAL_CALL OCellListSource::getListEntryCount( )
217 std::unique_lock<std::mutex> aGuard( m_aMutex );
218 throwIfDisposed(aGuard);
219 checkInitialized();
220 return getListEntryCount(aGuard);
223 sal_Int32 OCellListSource::getListEntryCount( std::unique_lock<std::mutex>& /*rGuard*/ )
225 CellRangeAddress aAddress( getRangeAddress( ) );
226 return aAddress.EndRow - aAddress.StartRow + 1;
229 OUString SAL_CALL OCellListSource::getListEntry( sal_Int32 _nPosition )
231 std::unique_lock<std::mutex> aGuard( m_aMutex );
232 throwIfDisposed(aGuard);
233 checkInitialized();
235 if ( _nPosition >= getListEntryCount() )
236 throw IndexOutOfBoundsException();
238 return getCellTextContent_noCheck( aGuard, _nPosition, nullptr );
241 Sequence< OUString > SAL_CALL OCellListSource::getAllListEntries( )
243 std::unique_lock<std::mutex> aGuard( m_aMutex );
244 throwIfDisposed(aGuard);
245 checkInitialized();
247 Sequence< OUString > aAllEntries( getListEntryCount(aGuard) );
248 OUString* pAllEntries = aAllEntries.getArray();
249 for ( sal_Int32 i = 0; i < aAllEntries.getLength(); ++i )
251 *pAllEntries++ = getCellTextContent_noCheck( aGuard, i, nullptr );
254 return aAllEntries;
257 Sequence< OUString > SAL_CALL OCellListSource::getAllListEntriesTyped( Sequence< Any >& rDataValues )
259 std::unique_lock<std::mutex> aGuard( m_aMutex );
260 throwIfDisposed(aGuard);
261 checkInitialized();
263 const sal_Int32 nCount = getListEntryCount(aGuard);
264 Sequence< OUString > aAllEntries( nCount );
265 rDataValues = Sequence< Any >( nCount );
266 OUString* pAllEntries = aAllEntries.getArray();
267 Any* pDataValues = rDataValues.getArray();
268 for ( sal_Int32 i = 0; i < nCount; ++i )
270 *pAllEntries++ = getCellTextContent_noCheck( aGuard, i, pDataValues++ );
273 return aAllEntries;
276 void SAL_CALL OCellListSource::addListEntryListener( const Reference< XListEntryListener >& _rxListener )
278 std::unique_lock<std::mutex> aGuard( m_aMutex );
279 throwIfDisposed(aGuard);
280 checkInitialized();
282 if ( !_rxListener.is() )
283 throw NullPointerException();
285 m_aListEntryListeners.addInterface( aGuard, _rxListener );
288 void SAL_CALL OCellListSource::removeListEntryListener( const Reference< XListEntryListener >& _rxListener )
290 std::unique_lock<std::mutex> aGuard( m_aMutex );
291 throwIfDisposed(aGuard);
292 checkInitialized();
294 if ( !_rxListener.is() )
295 throw NullPointerException();
297 m_aListEntryListeners.removeInterface( aGuard, _rxListener );
300 void SAL_CALL OCellListSource::modified( const EventObject& /* aEvent */ )
302 notifyModified();
305 void OCellListSource::notifyModified()
307 std::unique_lock<std::mutex> aGuard( m_aMutex );
308 EventObject aEvent;
309 aEvent.Source.set(*this);
311 m_aListEntryListeners.forEach(aGuard,
312 [&aEvent] (const css::uno::Reference<css::form::binding::XListEntryListener>& l)
316 l->allEntriesChanged( aEvent );
318 catch( const RuntimeException& )
320 // silent this
322 catch( const Exception& )
324 TOOLS_WARN_EXCEPTION( "sc", "OCellListSource::notifyModified: caught a (non-runtime) exception!" );
329 void SAL_CALL OCellListSource::disposing( const EventObject& aEvent )
331 Reference<XInterface> xRangeInt( m_xRange, UNO_QUERY );
332 if ( xRangeInt == aEvent.Source )
334 // release references to range object
335 m_xRange.clear();
339 void SAL_CALL OCellListSource::initialize( const Sequence< Any >& _rArguments )
341 if ( m_bInitialized )
342 throw RuntimeException(u"CellListSource is already initialized"_ustr, getXWeak());
344 // get the cell address
345 CellRangeAddress aRangeAddress;
346 bool bFoundAddress = false;
348 for ( const Any& rArg : _rArguments )
350 NamedValue aValue;
351 if ( rArg >>= aValue )
353 if ( aValue.Name == "CellRange" )
355 if ( aValue.Value >>= aRangeAddress )
357 bFoundAddress = true;
358 break;
364 if ( !bFoundAddress )
365 throw RuntimeException(u"Cell not found"_ustr, getXWeak());
367 // determine the range we're bound to
370 if ( m_xDocument.is() )
372 // first the sheets collection
373 Reference< XIndexAccess > xSheets(m_xDocument->getSheets( ), UNO_QUERY);
374 OSL_ENSURE( xSheets.is(), "OCellListSource::initialize: could not retrieve the sheets!" );
376 if ( xSheets.is() )
378 // the concrete sheet
379 Reference< XCellRange > xSheet(xSheets->getByIndex( aRangeAddress.Sheet ), UNO_QUERY);
380 OSL_ENSURE( xSheet.is(), "OCellListSource::initialize: NULL sheet, but no exception!" );
382 // the concrete cell
383 if ( xSheet.is() )
385 m_xRange.set(xSheet->getCellRangeByPosition(
386 aRangeAddress.StartColumn, aRangeAddress.StartRow,
387 aRangeAddress.EndColumn, aRangeAddress.EndRow));
388 OSL_ENSURE( Reference< XCellRangeAddressable >( m_xRange, UNO_QUERY ).is(), "OCellListSource::initialize: either NULL range, or cell without address access!" );
393 catch( const Exception& )
395 TOOLS_WARN_EXCEPTION( "sc", "OCellListSource::initialize: caught an exception while retrieving the cell object!" );
398 if ( !m_xRange.is() )
399 throw RuntimeException(u"Failed to retrieve cell range"_ustr, getXWeak());
401 Reference<XModifyBroadcaster> xBroadcaster( m_xRange, UNO_QUERY );
402 if ( xBroadcaster.is() )
404 xBroadcaster->addModifyListener( this );
407 // TODO: add as XEventListener to the cell range, so we get notified when it dies,
408 // and can dispose ourself then
410 // TODO: somehow add as listener so we get notified when the address of the cell range changes
411 // We need to forward this as change in our CellRange property to our property change listeners
413 // TODO: somehow add as listener to the cells in the range, so that we get notified
414 // when their content changes. We need to forward this to our list entry listeners then
416 // TODO: somehow add as listener so that we get notified of insertions and removals of rows in our
417 // range. In this case, we need to fire a change in our CellRange property, and additionally
418 // notify our XListEntryListeners
420 m_bInitialized = true;
423 } // namespace calc
425 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */