From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- sc/source/ui/unoobj/celllistsource.cxx | 433 +++++++++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 sc/source/ui/unoobj/celllistsource.cxx (limited to 'sc/source/ui/unoobj/celllistsource.cxx') diff --git a/sc/source/ui/unoobj/celllistsource.cxx b/sc/source/ui/unoobj/celllistsource.cxx new file mode 100644 index 000000000..37704a503 --- /dev/null +++ b/sc/source/ui/unoobj/celllistsource.cxx @@ -0,0 +1,433 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "celllistsource.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace calc +{ + +#define PROP_HANDLE_RANGE_ADDRESS 1 + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::table; + using namespace ::com::sun::star::text; + using namespace ::com::sun::star::sheet; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::form::binding; + + OCellListSource::OCellListSource( const Reference< XSpreadsheetDocument >& _rxDocument ) + :OCellListSource_Base( m_aMutex ) + ,OCellListSource_PBase( OCellListSource_Base::rBHelper ) + ,m_xDocument( _rxDocument ) + ,m_aListEntryListeners( m_aMutex ) + ,m_bInitialized( false ) + { + OSL_PRECOND( m_xDocument.is(), "OCellListSource::OCellListSource: invalid document!" ); + + // register our property at the base class + registerPropertyNoMember( + "CellRange", + PROP_HANDLE_RANGE_ADDRESS, + PropertyAttribute::BOUND | PropertyAttribute::READONLY, + cppu::UnoType::get(), + css::uno::Any(CellRangeAddress()) + ); + } + + OCellListSource::~OCellListSource( ) + { + if ( !OCellListSource_Base::rBHelper.bDisposed ) + { + acquire(); // prevent duplicate dtor + dispose(); + } + } + + IMPLEMENT_FORWARD_XINTERFACE2( OCellListSource, OCellListSource_Base, OCellListSource_PBase ) + + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellListSource, OCellListSource_Base, OCellListSource_PBase ) + + void SAL_CALL OCellListSource::disposing() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference xBroadcaster( m_xRange, UNO_QUERY ); + if ( xBroadcaster.is() ) + { + xBroadcaster->removeModifyListener( this ); + } + + EventObject aDisposeEvent( *this ); + m_aListEntryListeners.disposeAndClear( aDisposeEvent ); + + WeakAggComponentImplHelperBase::disposing(); + + // TODO: clean up here whatever you need to clean up (e.g. revoking listeners etc.) + } + + Reference< XPropertySetInfo > SAL_CALL OCellListSource::getPropertySetInfo( ) + { + return createPropertySetInfo( getInfoHelper() ) ; + } + + ::cppu::IPropertyArrayHelper& SAL_CALL OCellListSource::getInfoHelper() + { + return *OCellListSource_PABase::getArrayHelper(); + } + + ::cppu::IPropertyArrayHelper* OCellListSource::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + void SAL_CALL OCellListSource::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const + { + OSL_ENSURE( _nHandle == PROP_HANDLE_RANGE_ADDRESS, "OCellListSource::getFastPropertyValue: invalid handle!" ); + // we only have this one property... + + _rValue <<= getRangeAddress( ); + } + + void OCellListSource::checkDisposed( ) const + { + if ( OCellListSource_Base::rBHelper.bInDispose || OCellListSource_Base::rBHelper.bDisposed ) + throw DisposedException(); + // TODO: is it worth having an error message here? + } + + void OCellListSource::checkInitialized() + { + if ( !m_bInitialized ) + throw NotInitializedException("CellListSource is not initialized", static_cast(this)); + } + + OUString SAL_CALL OCellListSource::getImplementationName( ) + { + return "com.sun.star.comp.sheet.OCellListSource"; + } + + sal_Bool SAL_CALL OCellListSource::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL OCellListSource::getSupportedServiceNames( ) + { + return {"com.sun.star.table.CellRangeListSource", + "com.sun.star.form.binding.ListEntrySource"}; + } + + CellRangeAddress OCellListSource::getRangeAddress( ) const + { + OSL_PRECOND( m_xRange.is(), "OCellListSource::getRangeAddress: invalid range!" ); + + CellRangeAddress aAddress; + Reference< XCellRangeAddressable > xRangeAddress( m_xRange, UNO_QUERY ); + if ( xRangeAddress.is() ) + aAddress = xRangeAddress->getRangeAddress( ); + return aAddress; + } + + OUString OCellListSource::getCellTextContent_noCheck( sal_Int32 _nRangeRelativeRow, css::uno::Any* pAny ) + { + OUString sText; + + OSL_PRECOND( m_xRange.is(), "OCellListSource::getRangeAddress: invalid range!" ); + + if (!m_xRange.is()) + return sText; + + Reference< XCell > xCell( m_xRange->getCellByPosition( 0, _nRangeRelativeRow )); + if (!xCell.is()) + { + if (pAny) + *pAny <<= sText; + return sText; + } + + Reference< XTextRange > xCellText; + xCellText.set( xCell, UNO_QUERY); + + if (xCellText.is()) + sText = xCellText->getString(); // formatted output string + + if (pAny) + { + switch (xCell->getType()) + { + case CellContentType_VALUE: + *pAny <<= xCell->getValue(); + break; + case CellContentType_TEXT: + *pAny <<= sText; + break; + case CellContentType_FORMULA: + if (xCell->getError()) + *pAny <<= sText; // Err:... or #...! + else + { + Reference< XPropertySet > xProp( xCell, UNO_QUERY); + if (xProp.is()) + { + sal_Int32 nResultType; + if ((xProp->getPropertyValue("FormulaResultType2") >>= nResultType) && + nResultType == FormulaResult::VALUE) + *pAny <<= xCell->getValue(); + else + *pAny <<= sText; + } + } + break; + case CellContentType_EMPTY: + *pAny <<= OUString(); + break; + default: + ; // nothing, if actually occurred it would result in #N/A being displayed if selected + } + } + + return sText; + } + + sal_Int32 SAL_CALL OCellListSource::getListEntryCount( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(); + checkInitialized(); + + CellRangeAddress aAddress( getRangeAddress( ) ); + return aAddress.EndRow - aAddress.StartRow + 1; + } + + OUString SAL_CALL OCellListSource::getListEntry( sal_Int32 _nPosition ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(); + checkInitialized(); + + if ( _nPosition >= getListEntryCount() ) + throw IndexOutOfBoundsException(); + + return getCellTextContent_noCheck( _nPosition, nullptr ); + } + + Sequence< OUString > SAL_CALL OCellListSource::getAllListEntries( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(); + checkInitialized(); + + Sequence< OUString > aAllEntries( getListEntryCount() ); + OUString* pAllEntries = aAllEntries.getArray(); + for ( sal_Int32 i = 0; i < aAllEntries.getLength(); ++i ) + { + *pAllEntries++ = getCellTextContent_noCheck( i, nullptr ); + } + + return aAllEntries; + } + + Sequence< OUString > SAL_CALL OCellListSource::getAllListEntriesTyped( Sequence< Any >& rDataValues ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(); + checkInitialized(); + + const sal_Int32 nCount = getListEntryCount(); + Sequence< OUString > aAllEntries( nCount ); + rDataValues = Sequence< Any >( nCount ); + OUString* pAllEntries = aAllEntries.getArray(); + Any* pDataValues = rDataValues.getArray(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + *pAllEntries++ = getCellTextContent_noCheck( i, pDataValues++ ); + } + + return aAllEntries; + } + + void SAL_CALL OCellListSource::addListEntryListener( const Reference< XListEntryListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(); + checkInitialized(); + + if ( !_rxListener.is() ) + throw NullPointerException(); + + m_aListEntryListeners.addInterface( _rxListener ); + } + + void SAL_CALL OCellListSource::removeListEntryListener( const Reference< XListEntryListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(); + checkInitialized(); + + if ( !_rxListener.is() ) + throw NullPointerException(); + + m_aListEntryListeners.removeInterface( _rxListener ); + } + + void SAL_CALL OCellListSource::modified( const EventObject& /* aEvent */ ) + { + notifyModified(); + } + + void OCellListSource::notifyModified() + { + EventObject aEvent; + aEvent.Source.set(*this); + + ::comphelper::OInterfaceIteratorHelper3 aIter( m_aListEntryListeners ); + while ( aIter.hasMoreElements() ) + { + try + { + aIter.next()->allEntriesChanged( aEvent ); + } + catch( const RuntimeException& ) + { + // silent this + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "sc", "OCellListSource::notifyModified: caught a (non-runtime) exception!" ); + } + } + + } + + void SAL_CALL OCellListSource::disposing( const EventObject& aEvent ) + { + Reference xRangeInt( m_xRange, UNO_QUERY ); + if ( xRangeInt == aEvent.Source ) + { + // release references to range object + m_xRange.clear(); + } + } + + void SAL_CALL OCellListSource::initialize( const Sequence< Any >& _rArguments ) + { + if ( m_bInitialized ) + throw RuntimeException("CellListSource is already initialized", static_cast(this)); + + // get the cell address + CellRangeAddress aRangeAddress; + bool bFoundAddress = false; + + for ( const Any& rArg : _rArguments ) + { + NamedValue aValue; + if ( rArg >>= aValue ) + { + if ( aValue.Name == "CellRange" ) + { + if ( aValue.Value >>= aRangeAddress ) + { + bFoundAddress = true; + break; + } + } + } + } + + if ( !bFoundAddress ) + throw RuntimeException("Cell not found", static_cast(this)); + + // determine the range we're bound to + try + { + if ( m_xDocument.is() ) + { + // first the sheets collection + Reference< XIndexAccess > xSheets(m_xDocument->getSheets( ), UNO_QUERY); + OSL_ENSURE( xSheets.is(), "OCellListSource::initialize: could not retrieve the sheets!" ); + + if ( xSheets.is() ) + { + // the concrete sheet + Reference< XCellRange > xSheet(xSheets->getByIndex( aRangeAddress.Sheet ), UNO_QUERY); + OSL_ENSURE( xSheet.is(), "OCellListSource::initialize: NULL sheet, but no exception!" ); + + // the concrete cell + if ( xSheet.is() ) + { + m_xRange.set(xSheet->getCellRangeByPosition( + aRangeAddress.StartColumn, aRangeAddress.StartRow, + aRangeAddress.EndColumn, aRangeAddress.EndRow)); + OSL_ENSURE( Reference< XCellRangeAddressable >( m_xRange, UNO_QUERY ).is(), "OCellListSource::initialize: either NULL range, or cell without address access!" ); + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "sc", "OCellListSource::initialize: caught an exception while retrieving the cell object!" ); + } + + if ( !m_xRange.is() ) + throw RuntimeException("Failed to retrieve cell range", static_cast(this)); + + Reference xBroadcaster( m_xRange, UNO_QUERY ); + if ( xBroadcaster.is() ) + { + xBroadcaster->addModifyListener( this ); + } + + // TODO: add as XEventListener to the cell range, so we get notified when it dies, + // and can dispose ourself then + + // TODO: somehow add as listener so we get notified when the address of the cell range changes + // We need to forward this as change in our CellRange property to our property change listeners + + // TODO: somehow add as listener to the cells in the range, so that we get notified + // when their content changes. We need to forward this to our list entry listeners then + + // TODO: somehow add as listener so that we get notified of insertions and removals of rows in our + // range. In this case, we need to fire a change in our CellRange property, and additionally + // notify our XListEntryListeners + + m_bInitialized = true; + } + +} // namespace calc + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3