1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
)
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
;
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
;
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
);
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
;
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
);
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
;
96 void SdrCustomShapeGeometryItem::SetPropertyValue( const css::beans::PropertyValue
& rPropVal
)
98 css::uno::Any
* pAny
= GetPropertyValueByName( rPropVal
.Name
);
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
;
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
;
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
;
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
;
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
;
183 void SdrCustomShapeGeometryItem::ClearPropertyValue( const OUString
& rPropName
)
185 if ( !m_aPropSeq
.hasElements() )
188 PropertyHashMap::iterator
aHashIter( m_aPropHashMap
.find( rPropName
) );
189 if ( aHashIter
== m_aPropHashMap
.end() )
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();
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
221 SdrCustomShapeGeometryItem::~SdrCustomShapeGeometryItem()
225 bool SdrCustomShapeGeometryItem::operator==( const SfxPoolItem
& rCmp
) const
227 if( !SfxPoolItem::operator==( rCmp
))
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.
235 if( m_aHashState
!= other
.m_aHashState
)
237 if( m_aHashState
== HashState::Valid
&& m_aHash
!= other
.m_aHash
)
240 return m_aPropSeq
== other
.m_aPropSeq
;
243 void SdrCustomShapeGeometryItem::UpdateHash() const
245 if( m_aHashState
!= HashState::Unknown
)
247 std::optional
< size_t > hash
= comphelper::anyToHash( css::uno::Any( m_aPropSeq
));
248 if( hash
.has_value())
251 m_aHashState
= HashState::Valid
;
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
267 if ( ePresentation
== SfxItemPresentation::Complete
)
272 else if ( ePresentation
== SfxItemPresentation::Nameless
)
277 SdrCustomShapeGeometryItem
* SdrCustomShapeGeometryItem::Clone( SfxItemPool
* /*pPool*/ ) const
279 return new SdrCustomShapeGeometryItem( m_aPropSeq
);
282 bool SdrCustomShapeGeometryItem::QueryValue( uno::Any
& rVal
, sal_uInt8
/*nMemberId*/ ) const
288 bool SdrCustomShapeGeometryItem::PutValue( const uno::Any
& rVal
, sal_uInt8
/*nMemberId*/ )
290 css::uno::Sequence
< css::beans::PropertyValue
> propSeq
;
291 if ( ! ( rVal
>>= propSeq
) )
294 SetPropSeq( propSeq
);
298 void SdrCustomShapeGeometryItem::SetPropSeq( const css::uno::Sequence
< css::beans::PropertyValue
>& rVal
)
300 if( 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
314 throw uno::RuntimeException(
315 "CustomShapeGeometry has duplicate property " + rPropVal
.Name
);
317 if (auto rPropSeq
= o3tl::tryAccess
<uno::Sequence
<beans::PropertyValue
>>(
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
;
330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */