/* -*- 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 #include #include #include #include #include #include #include "UnoNameItemTable.hxx" #include #include #include using namespace ::com::sun::star; using namespace ::cppu; namespace { // We need to override operator== here and specifically bypass the assert // in SfxPoolItem::operator== in order to make the GetItemSurrogates call // and comparing it's results in SvxUnoNameItemTable::hasByName safe. class SampleItem : public NameOrIndex { public: SampleItem(sal_uInt16 nWhich, const OUString& rName) : NameOrIndex(TypedWhichId(nWhich), rName, SfxItemType::NameOrIndexType) {} bool operator==(const SfxPoolItem& rCmp) const { assert(dynamic_cast(&rCmp) && "comparing different pool item subclasses"); auto const & rOther = static_cast(rCmp); return GetName() == rOther.GetName() && GetPalIndex() == rOther.GetPalIndex(); } }; } SvxUnoNameItemTable::SvxUnoNameItemTable( SdrModel* pModel, sal_uInt16 nWhich, sal_uInt8 nMemberId ) noexcept : mpModel( pModel ), mpModelPool( pModel ? &pModel->GetItemPool() : nullptr ), mnWhich( nWhich ), mnMemberId( nMemberId ) { if( pModel ) StartListening( *pModel ); } SvxUnoNameItemTable::~SvxUnoNameItemTable() noexcept { SolarMutexGuard aGuard; if( mpModel ) EndListening( *mpModel ); dispose(); } bool SvxUnoNameItemTable::isValid( const NameOrIndex* pItem ) const { return pItem && !pItem->GetName().isEmpty(); } void SvxUnoNameItemTable::dispose() { maItemSetVector.clear(); } void SvxUnoNameItemTable::Notify( SfxBroadcaster&, const SfxHint& rHint ) noexcept { if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint) return; const SdrHint* pSdrHint = static_cast(&rHint); if( SdrHintKind::ModelCleared == pSdrHint->GetKind() ) dispose(); } sal_Bool SAL_CALL SvxUnoNameItemTable::supportsService( const OUString& ServiceName ) { return cppu::supportsService(this, ServiceName); } void SvxUnoNameItemTable::ImplInsertByName( const OUString& aName, const uno::Any& aElement ) { maItemSetVector.push_back( std::make_unique< SfxItemSet >( *mpModelPool, mnWhich, mnWhich ) ); std::unique_ptr xNewItem(createItem()); xNewItem->SetName(aName); xNewItem->PutValue(aElement, mnMemberId); xNewItem->SetWhich(mnWhich); maItemSetVector.back()->Put(std::move(xNewItem)); } // XNameContainer void SAL_CALL SvxUnoNameItemTable::insertByName( const OUString& aApiName, const uno::Any& aElement ) { SolarMutexGuard aGuard; comphelper::ProfileZone aZone("SvxUnoNameItemTable::insertByName"); if( hasByName( aApiName ) ) throw container::ElementExistException(); OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName); ImplInsertByName( aName, aElement ); } void SAL_CALL SvxUnoNameItemTable::cancel() { SolarMutexGuard aGuard; // drop all items that are owned by this service and not the document // (i.e. they are unused) dispose(); } void SAL_CALL SvxUnoNameItemTable::removeByName( const OUString& aApiName ) { SolarMutexGuard aGuard; comphelper::ProfileZone aZone("SvxUnoNameItemTable::removeByName"); OUString sName = SvxUnogetInternalNameForItem(mnWhich, aApiName); auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(), [&](const std::unique_ptr& rpItem) { const NameOrIndex *pItem = static_cast(&(rpItem->Get( mnWhich ) )); return sName == pItem->GetName(); }); if (aIter != maItemSetVector.end()) { maItemSetVector.erase( aIter ); return; } if (!hasByName(sName)) throw container::NoSuchElementException(); } // XNameReplace void SAL_CALL SvxUnoNameItemTable::replaceByName( const OUString& aApiName, const uno::Any& aElement ) { SolarMutexGuard aGuard; OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName); auto aIter = std::find_if(maItemSetVector.begin(), maItemSetVector.end(), [&](const std::unique_ptr& rpItem) { const NameOrIndex *pItem = static_cast(&(rpItem->Get( mnWhich ) )); return aName == pItem->GetName(); }); if (aIter != maItemSetVector.end()) { std::unique_ptr xNewItem(createItem()); xNewItem->SetName(aName); if (!xNewItem->PutValue(aElement, mnMemberId) || !isValid(xNewItem.get())) throw lang::IllegalArgumentException(); (*aIter)->Put(std::move(xNewItem)); return; } // if it is not in our own sets, modify the pool! bool bFound = false; if (mpModelPool) { SampleItem aSample(mnWhich, aName); ItemSurrogates aSurrogates; mpModelPool->GetItemSurrogates(aSurrogates, mnWhich); for (const SfxPoolItem* pNameOrIndex : aSurrogates) if (aSample == *pNameOrIndex) if (isValid(static_cast(pNameOrIndex))) { const_cast(pNameOrIndex)->PutValue( aElement, mnMemberId ); bFound = true; } } if( !bFound ) throw container::NoSuchElementException(); ImplInsertByName( aName, aElement ); if( !hasByName( aName ) ) throw container::NoSuchElementException(); } // XNameAccess uno::Any SAL_CALL SvxUnoNameItemTable::getByName( const OUString& aApiName ) { SolarMutexGuard aGuard; comphelper::ProfileZone aZone("SvxUnoNameItemTable::getByName"); OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName); if (mpModelPool && !aName.isEmpty()) { SampleItem aSample(mnWhich, aName); ItemSurrogates aSurrogates; mpModelPool->GetItemSurrogates(aSurrogates, mnWhich); for (const SfxPoolItem* pFindItem : aSurrogates) if (aSample == *pFindItem) if (isValid(static_cast(pFindItem))) { uno::Any aAny; pFindItem->QueryValue( aAny, mnMemberId ); return aAny; } } throw container::NoSuchElementException(); } uno::Sequence< OUString > SAL_CALL SvxUnoNameItemTable::getElementNames( ) { SolarMutexGuard aGuard; std::set< OUString > aNameSet; if (mpModelPool) { ItemSurrogates aSurrogates; mpModelPool->GetItemSurrogates(aSurrogates, mnWhich); for (const SfxPoolItem* pItem : aSurrogates) { const NameOrIndex *pNameOrIndex = static_cast(pItem); if( !isValid( pNameOrIndex ) ) continue; OUString aApiName = SvxUnogetApiNameForItem(mnWhich, pNameOrIndex->GetName()); aNameSet.insert(aApiName); } } return comphelper::containerToSequence(aNameSet); } sal_Bool SAL_CALL SvxUnoNameItemTable::hasByName( const OUString& aApiName ) { SolarMutexGuard aGuard; OUString aName = SvxUnogetInternalNameForItem(mnWhich, aApiName); if (aName.isEmpty()) return false; if (!mpModelPool) return false; SampleItem aSample(mnWhich, aName); ItemSurrogates aSurrogates; mpModelPool->GetItemSurrogates(aSurrogates, mnWhich); for (const SfxPoolItem* pFindItem : aSurrogates) if (aSample == *pFindItem) if (isValid(static_cast(pFindItem))) return true; return false; } sal_Bool SAL_CALL SvxUnoNameItemTable::hasElements( ) { SolarMutexGuard aGuard; if (mpModelPool) { ItemSurrogates aSurrogates; mpModelPool->GetItemSurrogates(aSurrogates, mnWhich); for (const SfxPoolItem* pItem : aSurrogates) { const NameOrIndex *pNameOrIndex = static_cast(pItem); if( isValid( pNameOrIndex ) ) return true; } } return false; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */