LibreOffice Module svx (master) 1
customshapeitem.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <o3tl/any.hxx>
25#include <svx/sdasitm.hxx>
26
27#include <com/sun/star/beans/PropertyValue.hpp>
28
29using namespace com::sun::star;
30
31
34{}
35
36SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem( const uno::Sequence< beans::PropertyValue >& rVal )
38{
39 SetPropSeq( rVal );
40}
41
42css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName )
43{
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;
49}
50
51const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName ) const
52{
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;
58}
59
60css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName )
61{
62 css::uno::Any* pRet = nullptr;
63 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
64 if ( pSeqAny )
65 {
66 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
67 {
68 PropertyPairHashMap::iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
69 if ( aHashIter != m_aPropPairHashMap.end() )
70 {
71 pRet = &const_cast<css::uno::Sequence<css::beans::PropertyValue> &>(*rSecSequence).getArray()[ (*aHashIter).second ].Value;
72 }
73 }
74 }
75 return pRet;
76}
77
78const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName ) const
79{
80 const css::uno::Any* pRet = nullptr;
81 const css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
82 if ( pSeqAny )
83 {
84 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
85 {
86 PropertyPairHashMap::const_iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
87 if ( aHashIter != m_aPropPairHashMap.end() )
88 {
89 pRet = &(*rSecSequence)[ (*aHashIter).second ].Value;
90 }
91 }
92 }
93 return pRet;
94}
95
96void SdrCustomShapeGeometryItem::SetPropertyValue( const css::beans::PropertyValue& rPropVal )
97{
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 )
104 {
105 PropertyPairHashMap::iterator aHashIter( m_aPropPairHashMap.find( PropertyPair( rPropVal.Name, i.Name ) ) );
106 if ( aHashIter != m_aPropPairHashMap.end() )
107 m_aPropPairHashMap.erase( aHashIter );
108 }
109 }
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++ )
114 {
115 beans::PropertyValue const & rPropVal2 = (*rSecSequence)[ i ];
116 m_aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = i;
117 }
118 }
119 }
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 ;
128
129 m_aPropHashMap[ rPropVal.Name ] = nIndex;
130 }
132}
133
134void SdrCustomShapeGeometryItem::SetPropertyValue( const OUString& rSequenceName, const css::beans::PropertyValue& rPropVal )
135{
136 css::uno::Any* pAny = GetPropertyValueByName( rSequenceName, rPropVal.Name );
137 if ( pAny ) // just replacing
138 *pAny = rPropVal.Value;
139 else
140 {
141 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
142 if( pSeqAny == nullptr )
143 {
144 css::uno::Sequence < beans::PropertyValue > aSeq;
145 beans::PropertyValue aValue;
146 aValue.Name = rSequenceName;
147 aValue.Value <<= aSeq;
148
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;
157
158 pSeqAny = &pPropSeq[ nIndex ].Value;
159 }
160
161 if (auto pSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny))
162 {
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())
167 {
168 rSeq.getArray()[(*aHashIter).second].Value = rPropVal.Value;
169 }
170 else
171 {
172 const sal_Int32 nCount = pSecSequence->getLength();
173 rSeq.realloc(nCount + 1);
174 rSeq.getArray()[nCount] = rPropVal;
175
176 m_aPropPairHashMap[PropertyPair(rSequenceName, rPropVal.Name)] = nCount;
177 }
178 }
179 }
181}
182
183void SdrCustomShapeGeometryItem::ClearPropertyValue( const OUString& rPropName )
184{
185 if ( !m_aPropSeq.hasElements() )
186 return;
187
188 PropertyHashMap::iterator aHashIter( m_aPropHashMap.find( rPropName ) );
189 if ( aHashIter == m_aPropHashMap.end() )
190 return;
191
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))
196 {
197 for (const auto& rPropVal : *pSecSequence)
198 {
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
202 }
203 }
204 sal_Int32 nLength = m_aPropSeq.getLength();
205 if ( nLength )
206 {
207 sal_Int32 nIndex = (*aHashIter).second;
208 if ( nIndex != ( nLength - 1 ) ) // resizing sequence
209 {
210 PropertyHashMap::iterator aHashIter2( m_aPropHashMap.find( m_aPropSeq[ nLength - 1 ].Name ) );
211 (*aHashIter2).second = nIndex;
212 pPropSeq[ nIndex ] = m_aPropSeq[ nLength - 1 ];
213 }
214 m_aPropSeq.realloc( nLength - 1 );
215 }
216 m_aPropHashMap.erase( aHashIter ); // removing property from hashmap
218}
219
221{
222}
223
225{
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( m_aHashState != other.m_aHashState )
235 return false;
236 if( m_aHashState == HashState::Valid && m_aHash != other.m_aHash )
237 return false;
238
239 return m_aPropSeq == other.m_aPropSeq;
240}
241
243{
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( m_aHashState != other.m_aHashState )
251 return m_aHashState < other.m_aHashState;
252 if( m_aHashState == HashState::Valid )
253 return m_aHash < other.m_aHash;
254
255 return comphelper::anyLess( css::uno::Any( m_aPropSeq ),
256 css::uno::Any( other.m_aPropSeq ));
257}
258
260{
261 if( m_aHashState != HashState::Unknown )
262 return;
263 std::optional< size_t > hash = comphelper::anyToHash( css::uno::Any( m_aPropSeq ));
264 if( hash.has_value())
265 {
266 m_aHash = *hash;
267 m_aHashState = HashState::Valid;
268 }
269 else
270 m_aHashState = HashState::Unusable;
271}
272
274{
275 m_aHashState = HashState::Unknown;
276}
277
279 SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
280 MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
281{
282 rText += " ";
283 if ( ePresentation == SfxItemPresentation::Complete )
284 {
285 rText = " " + rText;
286 return true;
287 }
288 else if ( ePresentation == SfxItemPresentation::Nameless )
289 return true;
290 return false;
291}
292
294{
296}
297
299{
300 rVal <<= m_aPropSeq;
301 return true;
302}
303
305{
306 css::uno::Sequence< css::beans::PropertyValue > propSeq;
307 if ( ! ( rVal >>= propSeq ) )
308 return false;
309
310 SetPropSeq( propSeq );
311 return true;
312}
313
314void SdrCustomShapeGeometryItem::SetPropSeq( const css::uno::Sequence< css::beans::PropertyValue >& rVal )
315{
316 if( m_aPropSeq == rVal )
317 return;
318
319 m_aPropSeq = rVal;
320 m_aPropHashMap.clear();
321 m_aPropPairHashMap.clear();
322 for ( sal_Int32 i = 0; i < m_aPropSeq.getLength(); i++ )
323 {
324 const beans::PropertyValue& rPropVal = m_aPropSeq[ i ];
325 std::pair<PropertyHashMap::iterator, bool> const ret(
326 m_aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
327 assert(ret.second); // serious bug: duplicate xml attribute exported
328 if (!ret.second)
329 {
330 throw uno::RuntimeException(
331 "CustomShapeGeometry has duplicate property " + rPropVal.Name);
332 }
333 if (auto rPropSeq = o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
334 rPropVal.Value))
335 {
336 for ( sal_Int32 j = 0; j < rPropSeq->getLength(); j++ )
337 {
338 beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
339 m_aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = j;
340 }
341 }
342 }
344}
345
346/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual SdrCustomShapeGeometryItem * Clone(SfxItemPool *pPool=nullptr) const override
css::uno::Sequence< css::beans::PropertyValue > m_aPropSeq
Definition: sdasitm.hxx:49
virtual bool QueryValue(css::uno::Any &rVal, sal_uInt8 nMemberId=0) const override
std::pair< const OUString, const OUString > PropertyPair
Definition: sdasitm.hxx:36
virtual bool PutValue(const css::uno::Any &rVal, sal_uInt8 nMemberId) override
virtual bool GetPresentation(SfxItemPresentation ePresentation, MapUnit eCoreMetric, MapUnit ePresentationMetric, OUString &rText, const IntlWrapper &) const override
void SetPropertyValue(const css::beans::PropertyValue &rPropVal)
virtual bool operator<(const SfxPoolItem &) const override
PropertyPairHashMap m_aPropPairHashMap
Definition: sdasitm.hxx:47
css::uno::Any * GetPropertyValueByName(const OUString &rPropName)
virtual ~SdrCustomShapeGeometryItem() override
void ClearPropertyValue(const OUString &rPropertyName)
PropertyHashMap m_aPropHashMap
Definition: sdasitm.hxx:46
void SetPropSeq(const css::uno::Sequence< css::beans::PropertyValue > &rPropSeq)
virtual bool operator==(const SfxPoolItem &) const override
int nCount
sal_Int32 nIndex
Sequence< sal_Int8 > aSeq
MapUnit
std::optional< size_t > anyToHash(uno::Any const &value)
bool anyLess(css::uno::Any const &lhs, css::uno::Any const &rhs)
int i
std::enable_if<!(detail::IsDerivedReference< T >::value||detail::IsUnoSequenceType< T >::value||std::is_base_of< css::uno::XInterface, T >::value), typenamedetail::Optional< T >::type >::type tryAccess(css::uno::Any const &any)
SfxItemPresentation
constexpr TypedWhichId< SdrCustomShapeGeometryItem > SDRATTR_CUSTOMSHAPE_GEOMETRY(SDRATTR_CUSTOMSHAPE_FIRST+2)
unsigned char sal_uInt8
sal_Int32 nLength