/* -*- 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 <o3tl/safeint.hxx>
#include <svl/hint.hxx>
#include <utility>
#include <vcl/svapp.hxx>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <com/sun/star/sheet/NamedRangeFlag.hpp>
#include <com/sun/star/awt/XBitmap.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <comphelper/servicehelper.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <unotools/charclass.hxx>
#include <nameuno.hxx>
#include <miscuno.hxx>
#include <cellsuno.hxx>
#include <convuno.hxx>
#include <targuno.hxx>
#include <tokenuno.hxx>
#include <tokenarray.hxx>
#include <docsh.hxx>
#include <docfunc.hxx>
#include <rangenam.hxx>
#include <unonames.hxx>
#include <scui_def.hxx>
using namespace ::com::sun::star;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Any;
static std::span<const SfxItemPropertyMapEntry> lcl_GetNamedRangeMap()
{
static const SfxItemPropertyMapEntry aNamedRangeMap_Impl[] =
{
{ SC_UNO_LINKDISPBIT, 0, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0 },
{ SC_UNO_LINKDISPNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
{ SC_UNONAME_TOKENINDEX, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
{ SC_UNONAME_ISSHAREDFMLA, 0, cppu::UnoType<bool>::get(), 0, 0 },
};
return aNamedRangeMap_Impl;
}
static std::span<const SfxItemPropertyMapEntry> lcl_GetNamedRangesMap()
{
static const SfxItemPropertyMapEntry aNamedRangesMap_Impl[] =
{
{ SC_UNO_MODIFY_BROADCAST, 0, cppu::UnoType<bool>::get(), 0, 0 },
};
return aNamedRangesMap_Impl;
}
constexpr OUString SCNAMEDRANGEOBJ_SERVICE = u"com.sun.star.sheet.NamedRange"_ustr;
SC_SIMPLE_SERVICE_INFO( ScLabelRangeObj, u"ScLabelRangeObj"_ustr, u"com.sun.star.sheet.LabelRange"_ustr )
SC_SIMPLE_SERVICE_INFO( ScLabelRangesObj, u"ScLabelRangesObj"_ustr, u"com.sun.star.sheet.LabelRanges"_ustr )
SC_SIMPLE_SERVICE_INFO( ScNamedRangesObj, u"ScNamedRangesObj"_ustr, u"com.sun.star.sheet.NamedRanges"_ustr )
// Database named ranges are not considered by getCount, hasByName, removeByName and getElementNames
// Note that hidden named ranges are considered by these methods
static bool lcl_UserVisibleName(const ScRangeData& rData)
{
//! as method to ScRangeData
return !rData.HasType(ScRangeData::Type::Database);
}
ScNamedRangeObj::ScNamedRangeObj( rtl::Reference< ScNamedRangesObj > xParent, ScDocShell* pDocSh, OUString aNm, Reference<container::XNamed> const & xSheet):
mxParent(std::move(xParent)),
pDocShell( pDocSh ),
aName(std::move( aNm )),
mxSheet( xSheet )
{
pDocShell->GetDocument().AddUnoObject(*this);
}
ScNamedRangeObj::~ScNamedRangeObj()
{
SolarMutexGuard g;
if (pDocShell)
pDocShell->GetDocument().RemoveUnoObject(*this);
}
void ScNamedRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
// reference update is of no interest
if ( rHint.GetId() == SfxHintId::Dying )
pDocShell = nullptr; // became invalid
}
// Helper functions
ScRangeData* ScNamedRangeObj::GetRangeData_Impl()
{
ScRangeData* pRet = nullptr;
if (pDocShell)
{
ScRangeName* pNames;
SCTAB nTab = GetTab_Impl();
if (nTab >= 0)
pNames = pDocShell->GetDocument().GetRangeName(nTab);
else
pNames = pDocShell->GetDocument().GetRangeName();
if (pNames)
{
pRet = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
if (pRet)
pRet->ValidateTabRefs(); // adjust relative tab refs to valid tables
}
}
return pRet;
}
SCTAB ScNamedRangeObj::GetTab_Impl()
{
if (mxSheet.is())
{
if (!pDocShell)
return -2;
ScDocument& rDoc = pDocShell->GetDocument();
SCTAB nTab;
OUString sName = mxSheet->getName();
bool bFound = rDoc.GetTable(sName, nTab);
assert(bFound); (void)bFound; // fouled up?
return nTab;
}
else
return -1;//global range name
}
// sheet::XNamedRange
void ScNamedRangeObj::Modify_Impl( const OUString* pNewName, const ScTokenArray* pNewTokens, const OUString* pNewContent,
const ScAddress* pNewPos, const ScRangeData::Type* pNewType,
const formula::FormulaGrammar::Grammar eGrammar )
{
if (!pDocShell)
return;
ScDocument& rDoc = pDocShell->GetDocument();
ScRangeName* pNames;
SCTAB nTab = GetTab_Impl();
if (nTab >= 0)
pNames = rDoc.GetRangeName(nTab);
else
pNames = rDoc.GetRangeName();
if (!pNames)
return;
const ScRangeData* pOld = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
if (!pOld)
return;
std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName(*pNames));
OUString aInsName = pOld->GetName();
if (pNewName)
aInsName = *pNewName;
// Content string based => no problems with changed positions and such.
OUString aContent = pOld->GetSymbol(eGrammar);
if (pNewContent)
aContent = *pNewContent;
ScAddress aPos = pOld->GetPos();
if (pNewPos)
aPos = *pNewPos;
ScRangeData::Type nType = pOld->GetType();
if (pNewType)
nType = *pNewType;
ScRangeData* pNew = nullptr;
if (pNewTokens)
pNew = new ScRangeData( rDoc, aInsName, *pNewTokens, aPos, nType );
else
pNew = new ScRangeData( rDoc, aInsName, aContent, aPos, nType, eGrammar );
pNew->SetIndex( pOld->GetIndex() );
pNewRanges->erase(*pOld);
if (pNewRanges->insert(pNew))
{
pDocShell->GetDocFunc().SetNewRangeNames(std::move(pNewRanges), mxParent->IsModifyAndBroadcast(), nTab);
aName = aInsName; //! broadcast?
}
else
{
pNew = nullptr; //! uno::Exception/Error or something
}
}
OUString SAL_CALL ScNamedRangeObj::getName()
{
SolarMutexGuard aGuard;
return aName;
}
void SAL_CALL ScNamedRangeObj::setName( const OUString& aNewName )
{
SolarMutexGuard aGuard;
//! adapt formulas ?????
OUString aNewStr(aNewName);
// GRAM_API for API compatibility.
Modify_Impl( &aNewStr, nullptr, nullptr, nullptr, nullptr,formula::FormulaGrammar::GRAM_API );
if ( aName != aNewStr ) // some error occurred...
throw uno::RuntimeException(); // no other exceptions specified
}
OUString SAL_CALL ScNamedRangeObj::getContent()
{
SolarMutexGuard aGuard;
OUString aContent;
ScRangeData* pData = GetRangeData_Impl();
if (pData)
// GRAM_API for API compatibility.
aContent = pData->GetSymbol(formula::FormulaGrammar::GRAM_API);
return aContent;
}
void SAL_CALL ScNamedRangeObj::setContent( const OUString& aContent )
{
SolarMutexGuard aGuard;
OUString aContStr(aContent);
// GRAM_API for API compatibility.
Modify_Impl( nullptr, nullptr, &aContStr, nullptr, nullptr,formula::FormulaGrammar::GRAM_API );
}
table::CellAddress SAL_CALL ScNamedRangeObj::getReferencePosition()
{
SolarMutexGuard aGuard;
ScAddress aPos;
ScRangeData* pData = GetRangeData_Impl();
if (pData)
aPos = pData->GetPos();
table::CellAddress aAddress;
aAddress.Column = aPos.Col();
aAddress.Row = aPos.Row();
aAddress.Sheet = aPos.Tab();
if (pDocShell)
{
SCTAB nDocTabs = pDocShell->GetDocument().GetTableCount();
if ( aAddress.Sheet >= nDocTabs && nDocTabs > 0 )
{
// Even after ValidateTabRefs, the position can be invalid if
// the content points to preceding tables. The resulting string
// is invalid in any case, so the position is just shifted.
aAddress.Sheet = nDocTabs - 1;
}
}
return aAddress;
}
void SAL_CALL ScNamedRangeObj::setReferencePosition( const table::CellAddress& aReferencePosition )
{
SolarMutexGuard aGuard;
ScAddress aPos( static_cast<SCCOL>(aReferencePosition.Column), static_cast<SCROW>(aReferencePosition.Row), aReferencePosition.Sheet );
// GRAM_API for API compatibility.
Modify_Impl( nullptr, nullptr, nullptr, &aPos, nullptr,formula::FormulaGrammar::GRAM_API );
}
sal_Int32 SAL_CALL ScNamedRangeObj::getType()
{
SolarMutexGuard aGuard;
sal_Int32 nType=0;
ScRangeData* pData = GetRangeData_Impl();
if (pData)
{
// do not return internal ScRangeData::Type flags
if ( pData->HasType(ScRangeData::Type::Criteria) ) nType |= sheet::NamedRangeFlag::FILTER_CRITERIA;
if ( pData->HasType(ScRangeData::Type::PrintArea) ) nType |= sheet::NamedRangeFlag::PRINT_AREA;
if ( pData->HasType(ScRangeData::Type::ColHeader) ) nType |= sheet::NamedRangeFlag::COLUMN_HEADER;
if ( pData->HasType(ScRangeData::Type::RowHeader) ) nType |= sheet::NamedRangeFlag::ROW_HEADER;
if ( pData->HasType(ScRangeData::Type::Hidden) ) nType |= sheet::NamedRangeFlag::HIDDEN;
}
return nType;
}
void SAL_CALL ScNamedRangeObj::setType( sal_Int32 nUnoType )
{
SolarMutexGuard aGuard;
ScRangeData::Type nNewType = ScRangeData::Type::Name;
if ( nUnoType & sheet::NamedRangeFlag::FILTER_CRITERIA ) nNewType |= ScRangeData::Type::Criteria;
if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA ) nNewType |= ScRangeData::Type::PrintArea;
if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER ) nNewType |= ScRangeData::Type::ColHeader;
if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER ) nNewType |= ScRangeData::Type::RowHeader;
if ( nUnoType & sheet::NamedRangeFlag::HIDDEN ) nNewType |= ScRangeData::Type::Hidden;
// GRAM_API for API compatibility.
Modify_Impl( nullptr, nullptr, nullptr, nullptr, &nNewType,formula::FormulaGrammar::GRAM_API );
}
// XFormulaTokens
uno::Sequence<sheet::FormulaToken> SAL_CALL ScNamedRangeObj::getTokens()
{
SolarMutexGuard aGuard;
uno::Sequence<sheet::FormulaToken> aSequence;
ScRangeData* pData = GetRangeData_Impl();
if (pData && pDocShell)
{
ScTokenArray* pTokenArray = pData->GetCode();
if ( pTokenArray )
ScTokenConversion::ConvertToTokenSequence( pDocShell->GetDocument(), aSequence, *pTokenArray );
}
return aSequence;
}
void SAL_CALL ScNamedRangeObj::setTokens( const uno::Sequence<sheet::FormulaToken>& rTokens )
{
SolarMutexGuard aGuard;
if( pDocShell )
{
ScTokenArray aTokenArray(pDocShell->GetDocument());
(void)ScTokenConversion::ConvertToTokenArray( pDocShell->GetDocument(), aTokenArray, rTokens );
// GRAM_API for API compatibility.
Modify_Impl( nullptr, &aTokenArray, nullptr, nullptr, nullptr, formula::FormulaGrammar::GRAM_API );
}
}
// XCellRangeSource
uno::Reference<table::XCellRange> SAL_CALL ScNamedRangeObj::getReferredCells()
{
SolarMutexGuard aGuard;
ScRange aRange;
ScRangeData* pData = GetRangeData_Impl();
if ( pData && pData->IsValidReference( aRange ) )
{
//! static function to create ScCellObj/ScCellRangeObj at ScCellRangeObj ???
if ( aRange.aStart == aRange.aEnd )
return new ScCellObj( pDocShell, aRange.aStart );
else
return new ScCellRangeObj( pDocShell, aRange );
}
return nullptr;
}
// beans::XPropertySet
uno::Reference<beans::XPropertySetInfo> SAL_CALL ScNamedRangeObj::getPropertySetInfo()
{
static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetNamedRangeMap() ));
return aRef;
}
void SAL_CALL ScNamedRangeObj::setPropertyValue(
const OUString& rPropertyName, const uno::Any& /*aValue*/ )
{
if ( rPropertyName == SC_UNONAME_ISSHAREDFMLA )
{
// Ignore this.
}
}
uno::Any SAL_CALL ScNamedRangeObj::getPropertyValue( const OUString& rPropertyName )
{
SolarMutexGuard aGuard;
uno::Any aRet;
if ( rPropertyName == SC_UNO_LINKDISPBIT )
{
// no target bitmaps for individual entries (would be all equal)
// ScLinkTargetTypeObj::SetLinkTargetBitmap( aRet, SC_LINKTARGETTYPE_RANGENAME );
}
else if ( rPropertyName == SC_UNO_LINKDISPNAME )
aRet <<= aName;
else if ( rPropertyName == SC_UNONAME_TOKENINDEX )
{
// get index for use in formula tokens (read-only)
ScRangeData* pData = GetRangeData_Impl();
if (pData)
aRet <<= static_cast<sal_Int32>(pData->GetIndex());
}
else if ( rPropertyName == SC_UNONAME_ISSHAREDFMLA )
{
if (GetRangeData_Impl())
aRet <<= false;
}
return aRet;
}
SC_IMPL_DUMMY_PROPERTY_LISTENER( ScNamedRangeObj )
// lang::XServiceInfo
OUString SAL_CALL ScNamedRangeObj::getImplementationName()
{
return u"ScNamedRangeObj"_ustr;
}
sal_Bool SAL_CALL ScNamedRangeObj::supportsService( const OUString& rServiceName )
{
return cppu::supportsService(this, rServiceName);
}
uno::Sequence<OUString> SAL_CALL ScNamedRangeObj::getSupportedServiceNames()
{
return {SCNAMEDRANGEOBJ_SERVICE, SCLINKTARGET_SERVICE};
}
ScNamedRangesObj::ScNamedRangesObj(ScDocShell* pDocSh) :
mbModifyAndBroadcast(true),
pDocShell( pDocSh )
{
pDocShell->GetDocument().AddUnoObject(*this);
}
ScNamedRangesObj::~ScNamedRangesObj()
{
SolarMutexGuard g;
if (pDocShell)
pDocShell->GetDocument().RemoveUnoObject(*this);
}
void ScNamedRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
// reference update is of no interest
if ( rHint.GetId() == SfxHintId::Dying )
{
pDocShell = nullptr; // became invalid
}
}
// sheet::XNamedRanges
void SAL_CALL ScNamedRangesObj::addNewByName( const OUString& aName,
const OUString& aContent, const table::CellAddress& aPosition,
sal_Int32 nUnoType )
{
SolarMutexGuard aGuard;
ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), aPosition.Sheet );
ScRangeData::Type nNewType = ScRangeData::Type::Name;
if ( nUnoType & sheet::NamedRangeFlag::FILTER_CRITERIA ) nNewType |= ScRangeData::Type::Criteria;
if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA ) nNewType |= ScRangeData::Type::PrintArea;
if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER ) nNewType |= ScRangeData::Type::ColHeader;
if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER ) nNewType |= ScRangeData::Type::RowHeader;
if ( nUnoType & sheet::NamedRangeFlag::HIDDEN ) nNewType |= ScRangeData::Type::Hidden;
bool bDone = false;
if (pDocShell)
{
ScDocument& rDoc = pDocShell->GetDocument();
// tdf#119457 - check for a valid range name and cell reference
switch (ScRangeData::IsNameValid(aName, rDoc))
{
case ScRangeData::IsNameValidType::NAME_INVALID_CELL_REF:
throw uno::RuntimeException(
u"Invalid name. Reference to a cell, or a range of cells not allowed"_ustr,
getXWeak());
break;
case ScRangeData::IsNameValidType::NAME_INVALID_BAD_STRING:
throw uno::RuntimeException(
u"Invalid name. Start with a letter, use only letters, numbers and underscore"_ustr,
getXWeak());
break;
case ScRangeData::IsNameValidType::NAME_VALID:
if (ScRangeName* pNames = GetRangeName_Impl();
pNames
&& !pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName)))
{
std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName( *pNames ));
// GRAM_API for API compatibility.
ScRangeData* pNew = new ScRangeData( rDoc, aName, aContent,
aPos, nNewType,formula::FormulaGrammar::GRAM_API );
if ( pNewRanges->insert(pNew) )
{
pDocShell->GetDocFunc().SetNewRangeNames(std::move(pNewRanges), mbModifyAndBroadcast, GetTab_Impl());
bDone = true;
}
else
{
pNew = nullptr;
}
}
}
}
if (!bDone)
throw uno::RuntimeException(); // no other exceptions specified
}
void SAL_CALL ScNamedRangesObj::addNewFromTitles( const table::CellRangeAddress& aSource,
sheet::Border aBorder )
{
SolarMutexGuard aGuard;
//! this cannot be an enum, because multiple bits can be set !!!
bool bTop = ( aBorder == sheet::Border_TOP );
bool bLeft = ( aBorder == sheet::Border_LEFT );
bool bBottom = ( aBorder == sheet::Border_BOTTOM );
bool bRight = ( aBorder == sheet::Border_RIGHT );
ScRange aRange;
ScUnoConversion::FillScRange( aRange, aSource );
CreateNameFlags nFlags = CreateNameFlags::NONE;
if (bTop) nFlags |= CreateNameFlags::Top;
if (bLeft) nFlags |= CreateNameFlags::Left;
if (bBottom) nFlags |= CreateNameFlags::Bottom;
if (bRight) nFlags |= CreateNameFlags::Right;
if (nFlags != CreateNameFlags::NONE)
pDocShell->GetDocFunc().CreateNames( aRange, nFlags, true, GetTab_Impl() );
}
void SAL_CALL ScNamedRangesObj::removeByName( const OUString& aName )
{
SolarMutexGuard aGuard;
bool bDone = false;
if (pDocShell)
{
ScRangeName* pNames = GetRangeName_Impl();
if (pNames)
{
const ScRangeData* pData = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
if (pData && lcl_UserVisibleName(*pData))
{
std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName(*pNames));
pNewRanges->erase(*pData);
pDocShell->GetDocFunc().SetNewRangeNames( std::move(pNewRanges), mbModifyAndBroadcast, GetTab_Impl());
bDone = true;
}
}
}
if (!bDone)
throw uno::RuntimeException(); // no other exceptions specified
}
void SAL_CALL ScNamedRangesObj::outputList( const table::CellAddress& aOutputPosition )
{
SolarMutexGuard aGuard;
ScAddress aPos( static_cast<SCCOL>(aOutputPosition.Column), static_cast<SCROW>(aOutputPosition.Row), aOutputPosition.Sheet );
if (pDocShell)
pDocShell->GetDocFunc().InsertNameList( aPos, true );
}
// container::XEnumerationAccess
uno::Reference<container::XEnumeration> SAL_CALL ScNamedRangesObj::createEnumeration()
{
SolarMutexGuard aGuard;
return new ScIndexEnumeration(this, u"com.sun.star.sheet.NamedRangesEnumeration"_ustr);
}
// container::XIndexAccess
sal_Int32 SAL_CALL ScNamedRangesObj::getCount()
{
SolarMutexGuard aGuard;
tools::Long nRet = 0;
if (pDocShell)
{
ScRangeName* pNames = GetRangeName_Impl();
if (pNames)
{
for (const auto& rName : *pNames)
if (lcl_UserVisibleName(*rName.second))
++nRet;
}
}
return nRet;
}
uno::Any SAL_CALL ScNamedRangesObj::getByIndex( sal_Int32 nIndex )
{
SolarMutexGuard aGuard;
uno::Reference< sheet::XNamedRange > xRange(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
if ( !xRange.is() )
throw lang::IndexOutOfBoundsException();
return uno::Any(xRange);
}
uno::Type SAL_CALL ScNamedRangesObj::getElementType()
{
return cppu::UnoType<sheet::XNamedRange>::get(); // must be suitable for getByIndex
}
sal_Bool SAL_CALL ScNamedRangesObj::hasElements()
{
SolarMutexGuard aGuard;
return ( getCount() != 0 );
}
Reference<beans::XPropertySetInfo> SAL_CALL ScNamedRangesObj::getPropertySetInfo()
{
static Reference<beans::XPropertySetInfo> aRef(
new SfxItemPropertySetInfo(lcl_GetNamedRangesMap()));
return aRef;
}
void SAL_CALL ScNamedRangesObj::setPropertyValue(
const OUString& rPropertyName, const uno::Any& aValue )
{
if ( rPropertyName == SC_UNO_MODIFY_BROADCAST )
{
aValue >>= mbModifyAndBroadcast;
}
}
Any SAL_CALL ScNamedRangesObj::getPropertyValue( const OUString& rPropertyName )
{
Any aRet;
if ( rPropertyName == SC_UNO_MODIFY_BROADCAST )
{
aRet <<= mbModifyAndBroadcast;
}
return aRet;
}
SC_IMPL_DUMMY_PROPERTY_LISTENER( ScNamedRangesObj )
uno::Any SAL_CALL ScNamedRangesObj::getByName( const OUString& aName )
{
SolarMutexGuard aGuard;
uno::Reference< sheet::XNamedRange > xRange(GetObjectByName_Impl(aName));
if ( !xRange.is() )
throw container::NoSuchElementException();
return uno::Any(xRange);
}
uno::Sequence<OUString> SAL_CALL ScNamedRangesObj::getElementNames()
{
SolarMutexGuard aGuard;
if (pDocShell)
{
ScRangeName* pNames = GetRangeName_Impl();
if (pNames)
{
tools::Long nVisCount = getCount(); // names with lcl_UserVisibleName
uno::Sequence<OUString> aSeq(nVisCount);
OUString* pAry = aSeq.getArray();
sal_uInt16 nVisPos = 0;
for (const auto& rName : *pNames)
{
if (lcl_UserVisibleName(*rName.second))
pAry[nVisPos++] = rName.second->GetName();
}
return aSeq;
}
}
return {};
}
sal_Bool SAL_CALL ScNamedRangesObj::hasByName( const OUString& aName )
{
SolarMutexGuard aGuard;
if (pDocShell)
{
ScRangeName* pNames = GetRangeName_Impl();
if (pNames)
{
const ScRangeData* pData = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
if (pData && lcl_UserVisibleName(*pData))
return true;
}
}
return false;
}
/** called from the XActionLockable interface methods on initial locking */
void ScNamedRangesObj::lock()
{
pDocShell->GetDocument().PreprocessRangeNameUpdate();
}
/** called from the XActionLockable interface methods on final unlock */
void ScNamedRangesObj::unlock()
{
pDocShell->GetDocument().CompileHybridFormula();
}
// document::XActionLockable
sal_Bool ScNamedRangesObj::isActionLocked()
{
SolarMutexGuard aGuard;
return pDocShell->GetDocument().GetNamedRangesLockCount() != 0;
}
void ScNamedRangesObj::addActionLock()
{
SolarMutexGuard aGuard;
ScDocument& rDoc = pDocShell->GetDocument();
sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
++nLockCount;
if ( nLockCount == 1 )
{
lock();
}
rDoc.SetNamedRangesLockCount( nLockCount );
}
void ScNamedRangesObj::removeActionLock()
{
SolarMutexGuard aGuard;
ScDocument& rDoc = pDocShell->GetDocument();
sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
if ( nLockCount > 0 )
{
--nLockCount;
if ( nLockCount == 0 )
{
unlock();
}
rDoc.SetNamedRangesLockCount( nLockCount );
}
}
void ScNamedRangesObj::setActionLocks( sal_Int16 nLock )
{
SolarMutexGuard aGuard;
if ( nLock < 0 )
return;
ScDocument& rDoc = pDocShell->GetDocument();
sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
if ( nLock == 0 && nLockCount > 0 )
{
unlock();
}
if ( nLock > 0 && nLockCount == 0 )
{
lock();
}
rDoc.SetNamedRangesLockCount( nLock );
}
sal_Int16 ScNamedRangesObj::resetActionLocks()
{
SolarMutexGuard aGuard;
ScDocument& rDoc = pDocShell->GetDocument();
sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
if ( nLockCount > 0 )
{
unlock();
}
rDoc.SetNamedRangesLockCount( 0 );
return nLockCount;
}
ScGlobalNamedRangesObj::ScGlobalNamedRangesObj(ScDocShell* pDocSh)
: ScNamedRangesObj(pDocSh)
{
}
ScGlobalNamedRangesObj::~ScGlobalNamedRangesObj()
{
}
rtl::Reference<ScNamedRangeObj> ScGlobalNamedRangesObj::GetObjectByIndex_Impl(sal_uInt16 nIndex)
{
if (!pDocShell)
return nullptr;
ScRangeName* pNames = pDocShell->GetDocument().GetRangeName();
if (!pNames)
return nullptr;
sal_uInt16 nPos = 0;
for (const auto& rName : *pNames)
{
if (lcl_UserVisibleName(*rName.second))
{
if (nPos == nIndex)
return new ScNamedRangeObj(this, pDocShell, rName.second->GetName());
}
++nPos;
}
return nullptr;
}
rtl::Reference<ScNamedRangeObj> ScGlobalNamedRangesObj::GetObjectByName_Impl(const OUString& aName)
{
if ( pDocShell && hasByName(aName) )
return new ScNamedRangeObj(this, pDocShell, aName);
return nullptr;
}
ScRangeName* ScGlobalNamedRangesObj::GetRangeName_Impl()
{
return pDocShell->GetDocument().GetRangeName();
}
SCTAB ScGlobalNamedRangesObj::GetTab_Impl()
{
return -1;
}
ScLocalNamedRangesObj::ScLocalNamedRangesObj( ScDocShell* pDocSh, uno::Reference<container::XNamed> xSheet )
: ScNamedRangesObj(pDocSh),
mxSheet(std::move(xSheet))
{
}
ScLocalNamedRangesObj::~ScLocalNamedRangesObj()
{
}
rtl::Reference<ScNamedRangeObj> ScLocalNamedRangesObj::GetObjectByName_Impl(const OUString& aName)
{
if ( pDocShell && hasByName( aName ) )
return new ScNamedRangeObj( this, pDocShell, aName, mxSheet);
return nullptr;
}
rtl::Reference<ScNamedRangeObj> ScLocalNamedRangesObj::GetObjectByIndex_Impl( sal_uInt16 nIndex )
{
if (!pDocShell)
return nullptr;
OUString aName = mxSheet->getName();
ScDocument& rDoc = pDocShell->GetDocument();
SCTAB nTab;
if (!rDoc.GetTable(aName, nTab))
return nullptr;
ScRangeName* pNames = rDoc.GetRangeName( nTab );
if (!pNames)
return nullptr;
sal_uInt16 nPos = 0;
for (const auto& rName : *pNames)
{
if (lcl_UserVisibleName(*rName.second))
{
if (nPos == nIndex)
return new ScNamedRangeObj(this, pDocShell, rName.second->GetName(), mxSheet);
}
++nPos;
}
return nullptr;
}
ScRangeName* ScLocalNamedRangesObj::GetRangeName_Impl()
{
SCTAB nTab = GetTab_Impl();
return pDocShell->GetDocument().GetRangeName( nTab );
}
SCTAB ScLocalNamedRangesObj::GetTab_Impl()
{
SCTAB nTab;
(void)pDocShell->GetDocument().GetTable(mxSheet->getName(), nTab);
return nTab;
}
ScLabelRangeObj::ScLabelRangeObj(ScDocShell* pDocSh, bool bCol, const ScRange& rR) :
pDocShell( pDocSh ),
bColumn( bCol ),
aRange( rR )
{
pDocShell->GetDocument().AddUnoObject(*this);
}
ScLabelRangeObj::~ScLabelRangeObj()
{
SolarMutexGuard g;
if (pDocShell)
pDocShell->GetDocument().RemoveUnoObject(*this);
}
void ScLabelRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
//! Ref-Update !!!
if ( rHint.GetId() == SfxHintId::Dying )
pDocShell = nullptr; // became invalid
}
// Helper functions
ScRangePair* ScLabelRangeObj::GetData_Impl()
{
ScRangePair* pRet = nullptr;
if (pDocShell)
{
ScDocument& rDoc = pDocShell->GetDocument();
ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
if (pList)
pRet = pList->Find( aRange );
}
return pRet;
}
void ScLabelRangeObj::Modify_Impl( const ScRange* pLabel, const ScRange* pData )
{
if (!pDocShell)
return;
ScDocument& rDoc = pDocShell->GetDocument();
ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
if (!pOldList)
return;
ScRangePairListRef xNewList(pOldList->Clone());
ScRangePair* pEntry = xNewList->Find( aRange );
if (!pEntry)
return;
if ( pLabel )
pEntry->GetRange(0) = *pLabel;
if ( pData )
pEntry->GetRange(1) = *pData;
xNewList->Join( *pEntry, true );
if (bColumn)
rDoc.GetColNameRangesRef() = std::move(xNewList);
else
rDoc.GetRowNameRangesRef() = std::move(xNewList);
rDoc.CompileColRowNameFormula();
pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
pDocShell->SetDocumentModified();
//! Undo ?!?! (here and from dialog)
if ( pLabel )
aRange = *pLabel; // adapt object to find range again
}
// sheet::XLabelRange
table::CellRangeAddress SAL_CALL ScLabelRangeObj::getLabelArea()
{
SolarMutexGuard aGuard;
table::CellRangeAddress aRet;
ScRangePair* pData = GetData_Impl();
if (pData)
ScUnoConversion::FillApiRange( aRet, pData->GetRange(0) );
return aRet;
}
void SAL_CALL ScLabelRangeObj::setLabelArea( const table::CellRangeAddress& aLabelArea )
{
SolarMutexGuard aGuard;
ScRange aLabelRange;
ScUnoConversion::FillScRange( aLabelRange, aLabelArea );
Modify_Impl( &aLabelRange, nullptr );
}
table::CellRangeAddress SAL_CALL ScLabelRangeObj::getDataArea()
{
SolarMutexGuard aGuard;
table::CellRangeAddress aRet;
ScRangePair* pData = GetData_Impl();
if (pData)
ScUnoConversion::FillApiRange( aRet, pData->GetRange(1) );
return aRet;
}
void SAL_CALL ScLabelRangeObj::setDataArea( const table::CellRangeAddress& aDataArea )
{
SolarMutexGuard aGuard;
ScRange aDataRange;
ScUnoConversion::FillScRange( aDataRange, aDataArea );
Modify_Impl( nullptr, &aDataRange );
}
ScLabelRangesObj::ScLabelRangesObj(ScDocShell* pDocSh, bool bCol) :
pDocShell( pDocSh ),
bColumn( bCol )
{
pDocShell->GetDocument().AddUnoObject(*this);
}
ScLabelRangesObj::~ScLabelRangesObj()
{
SolarMutexGuard g;
if (pDocShell)
pDocShell->GetDocument().RemoveUnoObject(*this);
}
void ScLabelRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
// reference update is of no interest
if ( rHint.GetId() == SfxHintId::Dying )
{
pDocShell = nullptr; // became invalid
}
}
// sheet::XLabelRanges
rtl::Reference<ScLabelRangeObj> ScLabelRangesObj::GetObjectByIndex_Impl(size_t nIndex)
{
if (pDocShell)
{
ScDocument& rDoc = pDocShell->GetDocument();
ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
if ( pList && nIndex < pList->size() )
{
ScRangePair & rData = (*pList)[nIndex];
return new ScLabelRangeObj( pDocShell, bColumn, rData.GetRange(0) );
}
}
return nullptr;
}
void SAL_CALL ScLabelRangesObj::addNew( const table::CellRangeAddress& aLabelArea,
const table::CellRangeAddress& aDataArea )
{
SolarMutexGuard aGuard;
if (!pDocShell)
return;
ScDocument& rDoc = pDocShell->GetDocument();
ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
if (!pOldList)
return;
ScRangePairListRef xNewList(pOldList->Clone());
ScRange aLabelRange;
ScRange aDataRange;
ScUnoConversion::FillScRange( aLabelRange, aLabelArea );
ScUnoConversion::FillScRange( aDataRange, aDataArea );
xNewList->Join( ScRangePair( aLabelRange, aDataRange ) );
if (bColumn)
rDoc.GetColNameRangesRef() = std::move(xNewList);
else
rDoc.GetRowNameRangesRef() = std::move(xNewList);
rDoc.CompileColRowNameFormula();
pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
pDocShell->SetDocumentModified();
//! Undo ?!?! (here and from dialog)
}
void SAL_CALL ScLabelRangesObj::removeByIndex( sal_Int32 nIndex )
{
SolarMutexGuard aGuard;
bool bDone = false;
if (pDocShell)
{
ScDocument& rDoc = pDocShell->GetDocument();
ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
if ( pOldList && nIndex >= 0 && o3tl::make_unsigned(nIndex) < pOldList->size() )
{
ScRangePairListRef xNewList(pOldList->Clone());
xNewList->Remove( nIndex );
if (bColumn)
rDoc.GetColNameRangesRef() = std::move(xNewList);
else
rDoc.GetRowNameRangesRef() = std::move(xNewList);
rDoc.CompileColRowNameFormula();
pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
pDocShell->SetDocumentModified();
bDone = true;
//! Undo ?!?! (here and from dialog)
}
}
if (!bDone)
throw uno::RuntimeException(); // no other exceptions specified
}
// container::XEnumerationAccess
uno::Reference<container::XEnumeration> SAL_CALL ScLabelRangesObj::createEnumeration()
{
SolarMutexGuard aGuard;
return new ScIndexEnumeration(this, u"com.sun.star.sheet.LabelRangesEnumeration"_ustr);
}
// container::XIndexAccess
sal_Int32 SAL_CALL ScLabelRangesObj::getCount()
{
SolarMutexGuard aGuard;
if (pDocShell)
{
ScDocument& rDoc = pDocShell->GetDocument();
ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
if (pList)
return pList->size();
}
return 0;
}
uno::Any SAL_CALL ScLabelRangesObj::getByIndex( sal_Int32 nIndex )
{
SolarMutexGuard aGuard;
uno::Reference< sheet::XLabelRange > xRange(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
if ( !xRange.is() )
throw lang::IndexOutOfBoundsException();
return uno::Any(xRange);
}
uno::Type SAL_CALL ScLabelRangesObj::getElementType()
{
return cppu::UnoType<sheet::XLabelRange>::get(); // must be suitable for getByIndex
}
sal_Bool SAL_CALL ScLabelRangesObj::hasElements()
{
SolarMutexGuard aGuard;
return ( getCount() != 0 );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V524 It is odd that the body of 'removePropertyChangeListener' function is fully equivalent to the body of 'addPropertyChangeListener' function.
↑ V524 It is odd that the body of 'removeVetoableChangeListener' function is fully equivalent to the body of 'addVetoableChangeListener' function.
↑ V524 It is odd that the body of 'removePropertyChangeListener' function is fully equivalent to the body of 'addPropertyChangeListener' function.
↑ V524 It is odd that the body of 'removeVetoableChangeListener' function is fully equivalent to the body of 'addVetoableChangeListener' function.