Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / items / customshapeitem.cxx
blob5f2ef96a251b497442cad87a37cc48eb96d1f0ef
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( aPropHashMap.find( rPropName ) );
46 if ( aHashIter != aPropHashMap.end() )
47 pRet = &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( aPropHashMap.find( rPropName ) );
55 if ( aHashIter != aPropHashMap.end() )
56 pRet = &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( aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
69 if ( aHashIter != 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( aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
87 if ( aHashIter != 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( aPropPairHashMap.find( PropertyPair( rPropVal.Name, i.Name ) ) );
106 if ( aHashIter != aPropPairHashMap.end() )
107 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 aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = i;
120 else
121 { // it's a new property
122 assert(std::none_of(std::cbegin(aPropSeq), std::cend(aPropSeq),
123 [&rPropVal](beans::PropertyValue const& rVal)
124 { return rVal.Name == rPropVal.Name; } ));
125 sal_uInt32 nIndex = aPropSeq.getLength();
126 aPropSeq.realloc( nIndex + 1 );
127 aPropSeq.getArray()[ nIndex ] = rPropVal ;
129 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(aPropSeq), std::cend(aPropSeq),
150 [&rSequenceName](beans::PropertyValue const& rV)
151 { return rV.Name == rSequenceName; } ));
152 sal_uInt32 nIndex = aPropSeq.getLength();
153 aPropSeq.realloc( nIndex + 1 );
154 auto pPropSeq = aPropSeq.getArray();
155 pPropSeq[ nIndex ] = aValue;
156 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 aPropPairHashMap.find(PropertyPair(rSequenceName, rPropVal.Name)));
165 auto& rSeq = const_cast<css::uno::Sequence<css::beans::PropertyValue>&>(*pSecSequence);
166 if (aHashIter != 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 aPropPairHashMap[PropertyPair(rSequenceName, rPropVal.Name)] = nCount;
180 InvalidateHash();
183 void SdrCustomShapeGeometryItem::ClearPropertyValue( const OUString& rPropName )
185 if ( !aPropSeq.hasElements() )
186 return;
188 PropertyHashMap::iterator aHashIter( aPropHashMap.find( rPropName ) );
189 if ( aHashIter == aPropHashMap.end() )
190 return;
192 auto pPropSeq = 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(aPropPairHashMap.find(PropertyPair(rPropName, rPropVal.Name)));
200 if (_aHashIter != aPropPairHashMap.end())
201 aPropPairHashMap.erase(_aHashIter); // removing property from pair hashmap
204 sal_Int32 nLength = aPropSeq.getLength();
205 if ( nLength )
207 sal_Int32 nIndex = (*aHashIter).second;
208 if ( nIndex != ( nLength - 1 ) ) // resizing sequence
210 PropertyHashMap::iterator aHashIter2( aPropHashMap.find( aPropSeq[ nLength - 1 ].Name ) );
211 (*aHashIter2).second = nIndex;
212 pPropSeq[ nIndex ] = aPropSeq[ nLength - 1 ];
214 aPropSeq.realloc( nLength - 1 );
216 aPropHashMap.erase( aHashIter ); // removing property from hashmap
217 InvalidateHash();
220 SdrCustomShapeGeometryItem::~SdrCustomShapeGeometryItem()
224 bool SdrCustomShapeGeometryItem::operator==( const SfxPoolItem& rCmp ) const
226 if( !SfxPoolItem::operator==( rCmp ))
227 return false;
228 const SdrCustomShapeGeometryItem& other = static_cast<const SdrCustomShapeGeometryItem&>(rCmp);
229 // This is called often by SfxItemPool, and comparing uno sequences is relatively slow.
230 // So keep a hash of the sequence and if either of the sequences has a usable hash,
231 // compare using that.
232 UpdateHash();
233 other.UpdateHash();
234 if( aHashState != other.aHashState )
235 return false;
236 if( aHashState == HashState::Valid && aHash != other.aHash )
237 return false;
239 return aPropSeq == other.aPropSeq;
242 bool SdrCustomShapeGeometryItem::operator<( const SfxPoolItem& rCmp ) const
244 assert(dynamic_cast<const SdrCustomShapeGeometryItem*>( &rCmp ));
245 const SdrCustomShapeGeometryItem& other = static_cast<const SdrCustomShapeGeometryItem&>(rCmp);
246 // Again, try to optimize by checking hashes first (this is operator< for sorting purposes,
247 // so the ordering can be somewhat arbitrary).
248 UpdateHash();
249 other.UpdateHash();
250 if( aHashState != other.aHashState )
251 return aHashState < other.aHashState;
252 if( aHashState == HashState::Valid )
253 return aHash < other.aHash;
255 return comphelper::anyLess( css::uno::Any( aPropSeq ),
256 css::uno::Any( other.aPropSeq ));
259 void SdrCustomShapeGeometryItem::UpdateHash() const
261 if( aHashState != HashState::Unknown )
262 return;
263 std::optional< size_t > hash = comphelper::anyToHash( css::uno::Any( aPropSeq ));
264 if( hash.has_value())
266 aHash = *hash;
267 aHashState = HashState::Valid;
269 else
270 aHashState = HashState::Unusable;
273 void SdrCustomShapeGeometryItem::InvalidateHash()
275 aHashState = HashState::Unknown;
278 bool SdrCustomShapeGeometryItem::GetPresentation(
279 SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
280 MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
282 rText += " ";
283 if ( ePresentation == SfxItemPresentation::Complete )
285 rText = " " + rText;
286 return true;
288 else if ( ePresentation == SfxItemPresentation::Nameless )
289 return true;
290 return false;
293 SdrCustomShapeGeometryItem* SdrCustomShapeGeometryItem::Clone( SfxItemPool * /*pPool*/ ) const
295 return new SdrCustomShapeGeometryItem( aPropSeq );
298 bool SdrCustomShapeGeometryItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
300 rVal <<= aPropSeq;
301 return true;
304 bool SdrCustomShapeGeometryItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
306 css::uno::Sequence< css::beans::PropertyValue > propSeq;
307 if ( ! ( rVal >>= propSeq ) )
308 return false;
310 SetPropSeq( propSeq );
311 return true;
314 void SdrCustomShapeGeometryItem::SetPropSeq( const css::uno::Sequence< css::beans::PropertyValue >& rVal )
316 if( aPropSeq == rVal )
317 return;
319 aPropSeq = rVal;
320 aPropHashMap.clear();
321 aPropPairHashMap.clear();
322 for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
324 const beans::PropertyValue& rPropVal = aPropSeq[ i ];
325 std::pair<PropertyHashMap::iterator, bool> const ret(
326 aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
327 assert(ret.second); // serious bug: duplicate xml attribute exported
328 if (!ret.second)
330 throw uno::RuntimeException(
331 "CustomShapeGeometry has duplicate property " + rPropVal.Name);
333 if (auto rPropSeq = o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
334 rPropVal.Value))
336 for ( sal_Int32 j = 0; j < rPropSeq->getLength(); j++ )
338 beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
339 aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = j;
343 InvalidateHash();
346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */