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 ::std;
30using namespace com::sun::star;
31
32
35{}
36
37SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem( const uno::Sequence< beans::PropertyValue >& rVal )
39{
40 SetPropSeq( rVal );
41}
42
43css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName )
44{
45 css::uno::Any* pRet = nullptr;
46 PropertyHashMap::iterator aHashIter( aPropHashMap.find( rPropName ) );
47 if ( aHashIter != aPropHashMap.end() )
48 pRet = &aPropSeq.getArray()[ (*aHashIter).second ].Value;
49 return pRet;
50}
51
52const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName ) const
53{
54 const css::uno::Any* pRet = nullptr;
55 PropertyHashMap::const_iterator aHashIter( aPropHashMap.find( rPropName ) );
56 if ( aHashIter != aPropHashMap.end() )
57 pRet = &aPropSeq[ (*aHashIter).second ].Value;
58 return pRet;
59}
60
61css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName )
62{
63 css::uno::Any* pRet = nullptr;
64 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
65 if ( pSeqAny )
66 {
67 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
68 {
69 PropertyPairHashMap::iterator aHashIter( aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
70 if ( aHashIter != aPropPairHashMap.end() )
71 {
72 pRet = &const_cast<css::uno::Sequence<css::beans::PropertyValue> &>(*rSecSequence).getArray()[ (*aHashIter).second ].Value;
73 }
74 }
75 }
76 return pRet;
77}
78
79const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName ) const
80{
81 const css::uno::Any* pRet = nullptr;
82 const css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
83 if ( pSeqAny )
84 {
85 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
86 {
87 PropertyPairHashMap::const_iterator aHashIter( aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
88 if ( aHashIter != aPropPairHashMap.end() )
89 {
90 pRet = &(*rSecSequence)[ (*aHashIter).second ].Value;
91 }
92 }
93 }
94 return pRet;
95}
96
97void SdrCustomShapeGeometryItem::SetPropertyValue( const css::beans::PropertyValue& rPropVal )
98{
99 css::uno::Any* pAny = GetPropertyValueByName( rPropVal.Name );
100 if ( pAny )
101 { // property is already available
102 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
103 { // old property is a sequence->each entry has to be removed from the HashPairMap
104 for ( auto const & i : *rSecSequence )
105 {
106 PropertyPairHashMap::iterator aHashIter( aPropPairHashMap.find( PropertyPair( rPropVal.Name, i.Name ) ) );
107 if ( aHashIter != aPropPairHashMap.end() )
108 aPropPairHashMap.erase( aHashIter );
109 }
110 }
111 *pAny = rPropVal.Value;
112 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
113 { // the new property is a sequence->each entry has to be inserted into the HashPairMap
114 for ( sal_Int32 i = 0; i < rSecSequence->getLength(); i++ )
115 {
116 beans::PropertyValue const & rPropVal2 = (*rSecSequence)[ i ];
117 aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = i;
118 }
119 }
120 }
121 else
122 { // it's a new property
123 assert(std::none_of(std::cbegin(aPropSeq), std::cend(aPropSeq),
124 [&rPropVal](beans::PropertyValue const& rVal)
125 { return rVal.Name == rPropVal.Name; } ));
126 sal_uInt32 nIndex = aPropSeq.getLength();
127 aPropSeq.realloc( nIndex + 1 );
128 aPropSeq.getArray()[ nIndex ] = rPropVal ;
129
130 aPropHashMap[ rPropVal.Name ] = nIndex;
131 }
133}
134
135void SdrCustomShapeGeometryItem::SetPropertyValue( const OUString& rSequenceName, const css::beans::PropertyValue& rPropVal )
136{
137 css::uno::Any* pAny = GetPropertyValueByName( rSequenceName, rPropVal.Name );
138 if ( pAny ) // just replacing
139 *pAny = rPropVal.Value;
140 else
141 {
142 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
143 if( pSeqAny == nullptr )
144 {
145 css::uno::Sequence < beans::PropertyValue > aSeq;
146 beans::PropertyValue aValue;
147 aValue.Name = rSequenceName;
148 aValue.Value <<= aSeq;
149
150 assert(std::none_of(std::cbegin(aPropSeq), std::cend(aPropSeq),
151 [&rSequenceName](beans::PropertyValue const& rV)
152 { return rV.Name == rSequenceName; } ));
153 sal_uInt32 nIndex = aPropSeq.getLength();
154 aPropSeq.realloc( nIndex + 1 );
155 auto pPropSeq = aPropSeq.getArray();
156 pPropSeq[ nIndex ] = aValue;
157 aPropHashMap[ rSequenceName ] = nIndex;
158
159 pSeqAny = &pPropSeq[ nIndex ].Value;
160 }
161
162 if (auto pSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny))
163 {
164 PropertyPairHashMap::iterator aHashIter(
165 aPropPairHashMap.find(PropertyPair(rSequenceName, rPropVal.Name)));
166 auto& rSeq = const_cast<css::uno::Sequence<css::beans::PropertyValue>&>(*pSecSequence);
167 if (aHashIter != aPropPairHashMap.end())
168 {
169 rSeq.getArray()[(*aHashIter).second].Value = rPropVal.Value;
170 }
171 else
172 {
173 const sal_Int32 nCount = pSecSequence->getLength();
174 rSeq.realloc(nCount + 1);
175 rSeq.getArray()[nCount] = rPropVal;
176
177 aPropPairHashMap[PropertyPair(rSequenceName, rPropVal.Name)] = nCount;
178 }
179 }
180 }
182}
183
184void SdrCustomShapeGeometryItem::ClearPropertyValue( const OUString& rPropName )
185{
186 if ( !aPropSeq.hasElements() )
187 return;
188
189 PropertyHashMap::iterator aHashIter( aPropHashMap.find( rPropName ) );
190 if ( aHashIter == aPropHashMap.end() )
191 return;
192
193 auto pPropSeq = aPropSeq.getArray();
194 css::uno::Any& rSeqAny = pPropSeq[(*aHashIter).second].Value;
195 if (auto pSecSequence
196 = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(rSeqAny))
197 {
198 for (const auto& rPropVal : *pSecSequence)
199 {
200 auto _aHashIter(aPropPairHashMap.find(PropertyPair(rPropName, rPropVal.Name)));
201 if (_aHashIter != aPropPairHashMap.end())
202 aPropPairHashMap.erase(_aHashIter); // removing property from pair hashmap
203 }
204 }
205 sal_Int32 nLength = aPropSeq.getLength();
206 if ( nLength )
207 {
208 sal_Int32 nIndex = (*aHashIter).second;
209 if ( nIndex != ( nLength - 1 ) ) // resizing sequence
210 {
211 PropertyHashMap::iterator aHashIter2( aPropHashMap.find( aPropSeq[ nLength - 1 ].Name ) );
212 (*aHashIter2).second = nIndex;
213 pPropSeq[ nIndex ] = aPropSeq[ nLength - 1 ];
214 }
215 aPropSeq.realloc( nLength - 1 );
216 }
217 aPropHashMap.erase( aHashIter ); // removing property from hashmap
219}
220
222{
223}
224
226{
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( aHashState != other.aHashState )
236 return false;
237 if( aHashState == HashState::Valid && aHash != other.aHash )
238 return false;
239
240 return aPropSeq == other.aPropSeq;
241}
242
244{
245 assert(dynamic_cast<const SdrCustomShapeGeometryItem*>( &rCmp ));
246 const SdrCustomShapeGeometryItem& other = static_cast<const SdrCustomShapeGeometryItem&>(rCmp);
247 // Again, try to optimize by checking hashes first (this is operator< for sorting purposes,
248 // so the ordering can be somewhat arbitrary).
249 UpdateHash();
250 other.UpdateHash();
251 if( aHashState != other.aHashState )
252 return aHashState < other.aHashState;
253 if( aHashState == HashState::Valid )
254 return aHash < other.aHash;
255
256 return comphelper::anyLess( css::uno::Any( aPropSeq ),
257 css::uno::Any( other.aPropSeq ));
258}
259
261{
262 if( aHashState != HashState::Unknown )
263 return;
264 std::optional< size_t > hash = comphelper::anyToHash( css::uno::Any( aPropSeq ));
265 if( hash.has_value())
266 {
267 aHash = *hash;
268 aHashState = HashState::Valid;
269 }
270 else
271 aHashState = HashState::Unusable;
272}
273
275{
276 aHashState = HashState::Unknown;
277}
278
280 SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
281 MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
282{
283 rText += " ";
284 if ( ePresentation == SfxItemPresentation::Complete )
285 {
286 rText = " " + rText;
287 return true;
288 }
289 else if ( ePresentation == SfxItemPresentation::Nameless )
290 return true;
291 return false;
292}
293
295{
297}
298
300{
301 rVal <<= aPropSeq;
302 return true;
303}
304
306{
307 css::uno::Sequence< css::beans::PropertyValue > propSeq;
308 if ( ! ( rVal >>= propSeq ) )
309 return false;
310
311 SetPropSeq( propSeq );
312 return true;
313}
314
315void SdrCustomShapeGeometryItem::SetPropSeq( const css::uno::Sequence< css::beans::PropertyValue >& rVal )
316{
317 if( aPropSeq == rVal )
318 return;
319
320 aPropSeq = rVal;
321 aPropHashMap.clear();
322 aPropPairHashMap.clear();
323 for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
324 {
325 const beans::PropertyValue& rPropVal = aPropSeq[ i ];
326 std::pair<PropertyHashMap::iterator, bool> const ret(
327 aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
328 assert(ret.second); // serious bug: duplicate xml attribute exported
329 if (!ret.second)
330 {
331 throw uno::RuntimeException(
332 "CustomShapeGeometry has duplicate property " + rPropVal.Name);
333 }
334 if (auto rPropSeq = o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
335 rPropVal.Value))
336 {
337 for ( sal_Int32 j = 0; j < rPropSeq->getLength(); j++ )
338 {
339 beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
340 aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = j;
341 }
342 }
343 }
345}
346
347/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual SdrCustomShapeGeometryItem * Clone(SfxItemPool *pPool=nullptr) const override
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
PropertyPairHashMap aPropPairHashMap
Definition: sdasitm.hxx:47
void SetPropertyValue(const css::beans::PropertyValue &rPropVal)
virtual bool operator<(const SfxPoolItem &) const override
PropertyHashMap aPropHashMap
Definition: sdasitm.hxx:46
css::uno::Any * GetPropertyValueByName(const OUString &rPropName)
virtual ~SdrCustomShapeGeometryItem() override
css::uno::Sequence< css::beans::PropertyValue > aPropSeq
Definition: sdasitm.hxx:49
void ClearPropertyValue(const OUString &rPropertyName)
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