Bump version to 24.04.3.4
[LibreOffice.git] / svx / source / items / customshapeitem.cxx
blob84e9af4de2b807c2d7ed96fdf32be0b02545eb04
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 <sal/config.h>
22 #include <o3tl/any.hxx>
23 #include <comphelper/anycompare.hxx>
24 #include <comphelper/anytohash.hxx>
25 #include <svx/sdasitm.hxx>
27 #include <com/sun/star/beans/PropertyValue.hpp>
29 using namespace com::sun::star;
32 SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem()
33 : SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
36 SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem( const uno::Sequence< beans::PropertyValue >& rVal )
37 : SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
39 SetPropSeq( rVal );
42 css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName )
44 css::uno::Any* pRet = nullptr;
45 PropertyHashMap::iterator aHashIter( m_aPropHashMap.find( rPropName ) );
46 if ( aHashIter != m_aPropHashMap.end() )
47 pRet = &m_aPropSeq.getArray()[ (*aHashIter).second ].Value;
48 return pRet;
51 const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName ) const
53 const css::uno::Any* pRet = nullptr;
54 PropertyHashMap::const_iterator aHashIter( m_aPropHashMap.find( rPropName ) );
55 if ( aHashIter != m_aPropHashMap.end() )
56 pRet = &m_aPropSeq[ (*aHashIter).second ].Value;
57 return pRet;
60 css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName )
62 css::uno::Any* pRet = nullptr;
63 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
64 if ( pSeqAny )
66 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
68 PropertyPairHashMap::iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
69 if ( aHashIter != m_aPropPairHashMap.end() )
71 pRet = &const_cast<css::uno::Sequence<css::beans::PropertyValue> &>(*rSecSequence).getArray()[ (*aHashIter).second ].Value;
75 return pRet;
78 const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName ) const
80 const css::uno::Any* pRet = nullptr;
81 const css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
82 if ( pSeqAny )
84 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
86 PropertyPairHashMap::const_iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
87 if ( aHashIter != m_aPropPairHashMap.end() )
89 pRet = &(*rSecSequence)[ (*aHashIter).second ].Value;
93 return pRet;
96 void SdrCustomShapeGeometryItem::SetPropertyValue( const css::beans::PropertyValue& rPropVal )
98 css::uno::Any* pAny = GetPropertyValueByName( rPropVal.Name );
99 if ( pAny )
100 { // property is already available
101 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
102 { // old property is a sequence->each entry has to be removed from the HashPairMap
103 for ( auto const & i : *rSecSequence )
105 PropertyPairHashMap::iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rPropVal.Name, i.Name ) ) );
106 if ( aHashIter != m_aPropPairHashMap.end() )
107 m_aPropPairHashMap.erase( aHashIter );
110 *pAny = rPropVal.Value;
111 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
112 { // the new property is a sequence->each entry has to be inserted into the HashPairMap
113 for ( sal_Int32 i = 0; i < rSecSequence->getLength(); i++ )
115 beans::PropertyValue const & rPropVal2 = (*rSecSequence)[ i ];
116 m_aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = i;
120 else
121 { // it's a new property
122 assert(std::none_of(std::cbegin(m_aPropSeq), std::cend(m_aPropSeq),
123 [&rPropVal](beans::PropertyValue const& rVal)
124 { return rVal.Name == rPropVal.Name; } ));
125 sal_uInt32 nIndex = m_aPropSeq.getLength();
126 m_aPropSeq.realloc( nIndex + 1 );
127 m_aPropSeq.getArray()[ nIndex ] = rPropVal ;
129 m_aPropHashMap[ rPropVal.Name ] = nIndex;
131 InvalidateHash();
134 void SdrCustomShapeGeometryItem::SetPropertyValue( const OUString& rSequenceName, const css::beans::PropertyValue& rPropVal )
136 css::uno::Any* pAny = GetPropertyValueByName( rSequenceName, rPropVal.Name );
137 if ( pAny ) // just replacing
138 *pAny = rPropVal.Value;
139 else
141 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
142 if( pSeqAny == nullptr )
144 css::uno::Sequence < beans::PropertyValue > aSeq;
145 beans::PropertyValue aValue;
146 aValue.Name = rSequenceName;
147 aValue.Value <<= aSeq;
149 assert(std::none_of(std::cbegin(m_aPropSeq), std::cend(m_aPropSeq),
150 [&rSequenceName](beans::PropertyValue const& rV)
151 { return rV.Name == rSequenceName; } ));
152 sal_uInt32 nIndex = m_aPropSeq.getLength();
153 m_aPropSeq.realloc( nIndex + 1 );
154 auto pPropSeq = m_aPropSeq.getArray();
155 pPropSeq[ nIndex ] = aValue;
156 m_aPropHashMap[ rSequenceName ] = nIndex;
158 pSeqAny = &pPropSeq[ nIndex ].Value;
161 if (auto pSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny))
163 PropertyPairHashMap::iterator aHashIter(
164 m_aPropPairHashMap.find(PropertyPair(rSequenceName, rPropVal.Name)));
165 auto& rSeq = const_cast<css::uno::Sequence<css::beans::PropertyValue>&>(*pSecSequence);
166 if (aHashIter != m_aPropPairHashMap.end())
168 rSeq.getArray()[(*aHashIter).second].Value = rPropVal.Value;
170 else
172 const sal_Int32 nCount = pSecSequence->getLength();
173 rSeq.realloc(nCount + 1);
174 rSeq.getArray()[nCount] = rPropVal;
176 m_aPropPairHashMap[PropertyPair(rSequenceName, rPropVal.Name)] = nCount;
180 InvalidateHash();
183 void SdrCustomShapeGeometryItem::ClearPropertyValue( const OUString& rPropName )
185 if ( !m_aPropSeq.hasElements() )
186 return;
188 PropertyHashMap::iterator aHashIter( m_aPropHashMap.find( rPropName ) );
189 if ( aHashIter == m_aPropHashMap.end() )
190 return;
192 auto pPropSeq = m_aPropSeq.getArray();
193 css::uno::Any& rSeqAny = pPropSeq[(*aHashIter).second].Value;
194 if (auto pSecSequence
195 = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(rSeqAny))
197 for (const auto& rPropVal : *pSecSequence)
199 auto _aHashIter(m_aPropPairHashMap.find(PropertyPair(rPropName, rPropVal.Name)));
200 if (_aHashIter != m_aPropPairHashMap.end())
201 m_aPropPairHashMap.erase(_aHashIter); // removing property from pair hashmap
204 sal_Int32 nLength = m_aPropSeq.getLength();
205 if ( nLength )
207 sal_Int32 nIndex = (*aHashIter).second;
208 if ( nIndex != ( nLength - 1 ) ) // resizing sequence
210 PropertyHashMap::iterator aHashIter2( m_aPropHashMap.find( m_aPropSeq[ nLength - 1 ].Name ) );
211 assert(aHashIter2 != m_aPropHashMap.end());
212 (*aHashIter2).second = nIndex;
213 pPropSeq[ nIndex ] = m_aPropSeq[ nLength - 1 ];
215 m_aPropSeq.realloc( nLength - 1 );
217 m_aPropHashMap.erase( aHashIter ); // removing property from hashmap
218 InvalidateHash();
221 SdrCustomShapeGeometryItem::~SdrCustomShapeGeometryItem()
225 bool SdrCustomShapeGeometryItem::operator==( const SfxPoolItem& rCmp ) const
227 if( !SfxPoolItem::operator==( rCmp ))
228 return false;
229 const SdrCustomShapeGeometryItem& other = static_cast<const SdrCustomShapeGeometryItem&>(rCmp);
230 // This is called often by SfxItemPool, and comparing uno sequences is relatively slow.
231 // So keep a hash of the sequence and if either of the sequences has a usable hash,
232 // compare using that.
233 UpdateHash();
234 other.UpdateHash();
235 if( m_aHashState != other.m_aHashState )
236 return false;
237 if( m_aHashState == HashState::Valid && m_aHash != other.m_aHash )
238 return false;
240 return m_aPropSeq == other.m_aPropSeq;
243 void SdrCustomShapeGeometryItem::UpdateHash() const
245 if( m_aHashState != HashState::Unknown )
246 return;
247 std::optional< size_t > hash = comphelper::anyToHash( css::uno::Any( m_aPropSeq ));
248 if( hash.has_value())
250 m_aHash = *hash;
251 m_aHashState = HashState::Valid;
253 else
254 m_aHashState = HashState::Unusable;
257 void SdrCustomShapeGeometryItem::InvalidateHash()
259 m_aHashState = HashState::Unknown;
262 bool SdrCustomShapeGeometryItem::GetPresentation(
263 SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
264 MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
266 rText += " ";
267 if ( ePresentation == SfxItemPresentation::Complete )
269 rText = " " + rText;
270 return true;
272 else if ( ePresentation == SfxItemPresentation::Nameless )
273 return true;
274 return false;
277 SdrCustomShapeGeometryItem* SdrCustomShapeGeometryItem::Clone( SfxItemPool * /*pPool*/ ) const
279 return new SdrCustomShapeGeometryItem( m_aPropSeq );
282 bool SdrCustomShapeGeometryItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
284 rVal <<= m_aPropSeq;
285 return true;
288 bool SdrCustomShapeGeometryItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
290 css::uno::Sequence< css::beans::PropertyValue > propSeq;
291 if ( ! ( rVal >>= propSeq ) )
292 return false;
294 SetPropSeq( propSeq );
295 return true;
298 void SdrCustomShapeGeometryItem::SetPropSeq( const css::uno::Sequence< css::beans::PropertyValue >& rVal )
300 if( m_aPropSeq == rVal )
301 return;
303 m_aPropSeq = rVal;
304 m_aPropHashMap.clear();
305 m_aPropPairHashMap.clear();
306 for ( sal_Int32 i = 0; i < m_aPropSeq.getLength(); i++ )
308 const beans::PropertyValue& rPropVal = m_aPropSeq[ i ];
309 std::pair<PropertyHashMap::iterator, bool> const ret(
310 m_aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
311 assert(ret.second); // serious bug: duplicate xml attribute exported
312 if (!ret.second)
314 throw uno::RuntimeException(
315 "CustomShapeGeometry has duplicate property " + rPropVal.Name);
317 if (auto rPropSeq = o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
318 rPropVal.Value))
320 for ( sal_Int32 j = 0; j < rPropSeq->getLength(); j++ )
322 beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
323 m_aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = j;
327 InvalidateHash();
330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */