defer finding dialog parent until we need it
[LibreOffice.git] / svx / source / items / customshapeitem.cxx
blob24944bf0b88bcb5bb2f1f1bc0d19f8b51d0d6287
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/anytohash.hxx>
24 #include <svx/sdasitm.hxx>
26 #include <com/sun/star/beans/PropertyValue.hpp>
28 using namespace com::sun::star;
31 SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem()
32 : SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
35 SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem( const uno::Sequence< beans::PropertyValue >& rVal )
36 : SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
38 SetPropSeq( rVal );
41 css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName )
43 ASSERT_CHANGE_REFCOUNTED_ITEM;
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 ASSERT_CHANGE_REFCOUNTED_ITEM;
63 css::uno::Any* pRet = nullptr;
64 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
65 if ( pSeqAny )
67 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
69 PropertyPairHashMap::iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
70 if ( aHashIter != m_aPropPairHashMap.end() )
72 pRet = &const_cast<css::uno::Sequence<css::beans::PropertyValue> &>(*rSecSequence).getArray()[ (*aHashIter).second ].Value;
76 return pRet;
79 const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName ) const
81 const css::uno::Any* pRet = nullptr;
82 const css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
83 if ( pSeqAny )
85 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
87 PropertyPairHashMap::const_iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
88 if ( aHashIter != m_aPropPairHashMap.end() )
90 pRet = &(*rSecSequence)[ (*aHashIter).second ].Value;
94 return pRet;
97 void SdrCustomShapeGeometryItem::SetPropertyValue( const css::beans::PropertyValue& rPropVal )
99 ASSERT_CHANGE_REFCOUNTED_ITEM;
100 css::uno::Any* pAny = GetPropertyValueByName( rPropVal.Name );
101 if ( pAny )
102 { // property is already available
103 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
104 { // old property is a sequence->each entry has to be removed from the HashPairMap
105 for ( auto const & i : *rSecSequence )
107 PropertyPairHashMap::iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rPropVal.Name, i.Name ) ) );
108 if ( aHashIter != m_aPropPairHashMap.end() )
109 m_aPropPairHashMap.erase( aHashIter );
112 *pAny = rPropVal.Value;
113 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
114 { // the new property is a sequence->each entry has to be inserted into the HashPairMap
115 for ( sal_Int32 i = 0; i < rSecSequence->getLength(); i++ )
117 beans::PropertyValue const & rPropVal2 = (*rSecSequence)[ i ];
118 m_aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = i;
122 else
123 { // it's a new property
124 assert(std::none_of(std::cbegin(m_aPropSeq), std::cend(m_aPropSeq),
125 [&rPropVal](beans::PropertyValue const& rVal)
126 { return rVal.Name == rPropVal.Name; } ));
127 sal_uInt32 nIndex = m_aPropSeq.getLength();
128 m_aPropSeq.realloc( nIndex + 1 );
129 m_aPropSeq.getArray()[ nIndex ] = rPropVal ;
131 m_aPropHashMap[ rPropVal.Name ] = nIndex;
133 InvalidateHash();
136 void SdrCustomShapeGeometryItem::SetPropertyValue( const OUString& rSequenceName, const css::beans::PropertyValue& rPropVal )
138 ASSERT_CHANGE_REFCOUNTED_ITEM;
139 css::uno::Any* pAny = GetPropertyValueByName( rSequenceName, rPropVal.Name );
140 if ( pAny ) // just replacing
141 *pAny = rPropVal.Value;
142 else
144 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
145 if( pSeqAny == nullptr )
147 css::uno::Sequence < beans::PropertyValue > aSeq;
148 beans::PropertyValue aValue;
149 aValue.Name = rSequenceName;
150 aValue.Value <<= aSeq;
152 assert(std::none_of(std::cbegin(m_aPropSeq), std::cend(m_aPropSeq),
153 [&rSequenceName](beans::PropertyValue const& rV)
154 { return rV.Name == rSequenceName; } ));
155 sal_uInt32 nIndex = m_aPropSeq.getLength();
156 m_aPropSeq.realloc( nIndex + 1 );
157 auto pPropSeq = m_aPropSeq.getArray();
158 pPropSeq[ nIndex ] = std::move(aValue);
159 m_aPropHashMap[ rSequenceName ] = nIndex;
161 pSeqAny = &pPropSeq[ nIndex ].Value;
164 if (auto pSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny))
166 PropertyPairHashMap::iterator aHashIter(
167 m_aPropPairHashMap.find(PropertyPair(rSequenceName, rPropVal.Name)));
168 auto& rSeq = const_cast<css::uno::Sequence<css::beans::PropertyValue>&>(*pSecSequence);
169 if (aHashIter != m_aPropPairHashMap.end())
171 rSeq.getArray()[(*aHashIter).second].Value = rPropVal.Value;
173 else
175 const sal_Int32 nCount = pSecSequence->getLength();
176 rSeq.realloc(nCount + 1);
177 rSeq.getArray()[nCount] = rPropVal;
179 m_aPropPairHashMap[PropertyPair(rSequenceName, rPropVal.Name)] = nCount;
183 InvalidateHash();
186 void SdrCustomShapeGeometryItem::ClearPropertyValue( const OUString& rPropName )
188 ASSERT_CHANGE_REFCOUNTED_ITEM;
189 if ( !m_aPropSeq.hasElements() )
190 return;
192 PropertyHashMap::iterator aHashIter( m_aPropHashMap.find( rPropName ) );
193 if ( aHashIter == m_aPropHashMap.end() )
194 return;
196 auto pPropSeq = m_aPropSeq.getArray();
197 css::uno::Any& rSeqAny = pPropSeq[(*aHashIter).second].Value;
198 if (auto pSecSequence
199 = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(rSeqAny))
201 for (const auto& rPropVal : *pSecSequence)
203 auto _aHashIter(m_aPropPairHashMap.find(PropertyPair(rPropName, rPropVal.Name)));
204 if (_aHashIter != m_aPropPairHashMap.end())
205 m_aPropPairHashMap.erase(_aHashIter); // removing property from pair hashmap
208 sal_Int32 nLength = m_aPropSeq.getLength();
209 if ( nLength )
211 sal_Int32 nIndex = (*aHashIter).second;
212 if ( nIndex != ( nLength - 1 ) ) // resizing sequence
214 PropertyHashMap::iterator aHashIter2( m_aPropHashMap.find( m_aPropSeq[ nLength - 1 ].Name ) );
215 assert(aHashIter2 != m_aPropHashMap.end());
216 (*aHashIter2).second = nIndex;
217 pPropSeq[ nIndex ] = m_aPropSeq[ nLength - 1 ];
219 m_aPropSeq.realloc( nLength - 1 );
221 m_aPropHashMap.erase( aHashIter ); // removing property from hashmap
222 InvalidateHash();
225 SdrCustomShapeGeometryItem::~SdrCustomShapeGeometryItem()
229 bool SdrCustomShapeGeometryItem::operator==( const SfxPoolItem& rCmp ) const
231 if( !SfxPoolItem::operator==( rCmp ))
232 return false;
233 const SdrCustomShapeGeometryItem& other = static_cast<const SdrCustomShapeGeometryItem&>(rCmp);
234 // This is called often by SfxItemPool, and comparing uno sequences is relatively slow.
235 // So keep a hash of the sequence and if either of the sequences has a usable hash,
236 // compare using that.
237 UpdateHash();
238 other.UpdateHash();
239 if( m_aHashState != other.m_aHashState )
240 return false;
241 if( m_aHashState == HashState::Valid && m_aHash != other.m_aHash )
242 return false;
244 return m_aPropSeq == other.m_aPropSeq;
247 void SdrCustomShapeGeometryItem::UpdateHash() const
249 if( m_aHashState != HashState::Unknown )
250 return;
251 std::optional< size_t > hash = comphelper::anyToHash( css::uno::Any( m_aPropSeq ));
252 if( hash.has_value())
254 m_aHash = *hash;
255 m_aHashState = HashState::Valid;
257 else
258 m_aHashState = HashState::Unusable;
261 void SdrCustomShapeGeometryItem::InvalidateHash()
263 m_aHashState = HashState::Unknown;
266 bool SdrCustomShapeGeometryItem::GetPresentation(
267 SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
268 MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
270 rText += " ";
271 if ( ePresentation == SfxItemPresentation::Complete )
273 rText = " " + rText;
274 return true;
276 else if ( ePresentation == SfxItemPresentation::Nameless )
277 return true;
278 return false;
281 SdrCustomShapeGeometryItem* SdrCustomShapeGeometryItem::Clone( SfxItemPool * /*pPool*/ ) const
283 return new SdrCustomShapeGeometryItem( m_aPropSeq );
286 bool SdrCustomShapeGeometryItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
288 rVal <<= m_aPropSeq;
289 return true;
292 bool SdrCustomShapeGeometryItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
294 ASSERT_CHANGE_REFCOUNTED_ITEM;
295 css::uno::Sequence< css::beans::PropertyValue > propSeq;
296 if ( ! ( rVal >>= propSeq ) )
297 return false;
299 SetPropSeq( propSeq );
300 return true;
303 void SdrCustomShapeGeometryItem::SetPropSeq( const css::uno::Sequence< css::beans::PropertyValue >& rVal )
305 ASSERT_CHANGE_REFCOUNTED_ITEM;
306 if( m_aPropSeq == rVal )
307 return;
309 m_aPropSeq = rVal;
310 m_aPropHashMap.clear();
311 m_aPropPairHashMap.clear();
312 for ( sal_Int32 i = 0; i < m_aPropSeq.getLength(); i++ )
314 const beans::PropertyValue& rPropVal = m_aPropSeq[ i ];
315 std::pair<PropertyHashMap::iterator, bool> const ret(
316 m_aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
317 assert(ret.second); // serious bug: duplicate xml attribute exported
318 if (!ret.second)
320 throw uno::RuntimeException(
321 "CustomShapeGeometry has duplicate property " + rPropVal.Name);
323 if (auto rPropSeq = o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
324 rPropVal.Value))
326 for ( sal_Int32 j = 0; j < rPropSeq->getLength(); j++ )
328 beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
329 m_aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = j;
333 InvalidateHash();
336 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */