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>
23 #include <svx/sdasitm.hxx>
24
25 #include <com/sun/star/beans/PropertyValue.hpp>
26
27 using namespace ::std;
28 using namespace com::sun::star;
29
30
SdrCustomShapeGeometryItem()31 SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem()
32 : SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
33 {}
34
SdrCustomShapeGeometryItem(const uno::Sequence<beans::PropertyValue> & rVal)35 SdrCustomShapeGeometryItem::SdrCustomShapeGeometryItem( const uno::Sequence< beans::PropertyValue >& rVal )
36 : SfxPoolItem( SDRATTR_CUSTOMSHAPE_GEOMETRY )
37 {
38 sal_Int32 i, j;
39 aPropSeq = rVal;
40
41 for ( i = 0; i < aPropSeq.getLength(); i++ )
42 {
43 beans::PropertyValue& rPropVal = aPropSeq[ i ];
44 std::pair<PropertyHashMap::iterator, bool> const ret(
45 aPropHashMap.insert(std::make_pair(rPropVal.Name, i)));
46 assert(ret.second); // serious bug: duplicate xml attribute exported
47 if (!ret.second)
48 {
49 throw uno::RuntimeException(
50 "CustomShapeGeometry has duplicate property " + rPropVal.Name);
51 }
52 if (auto rPropSeq = o3tl::tryAccess<uno::Sequence<beans::PropertyValue>>(
53 rPropVal.Value))
54 {
55 for ( j = 0; j < rPropSeq->getLength(); j++ )
56 {
57 beans::PropertyValue const & rPropVal2 = (*rPropSeq)[ j ];
58 aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = j;
59 }
60 }
61 }
62 }
63
GetPropertyValueByName(const OUString & rPropName)64 css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName )
65 {
66 css::uno::Any* pRet = nullptr;
67 PropertyHashMap::iterator aHashIter( aPropHashMap.find( rPropName ) );
68 if ( aHashIter != aPropHashMap.end() )
69 pRet = &aPropSeq[ (*aHashIter).second ].Value;
70 return pRet;
71 }
72
GetPropertyValueByName(const OUString & rPropName) const73 const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rPropName ) const
74 {
75 const css::uno::Any* pRet = nullptr;
76 PropertyHashMap::const_iterator aHashIter( aPropHashMap.find( rPropName ) );
77 if ( aHashIter != aPropHashMap.end() )
78 pRet = &aPropSeq[ (*aHashIter).second ].Value;
79 return pRet;
80 }
81
GetPropertyValueByName(const OUString & rSequenceName,const OUString & rPropName)82 css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName )
83 {
84 css::uno::Any* pRet = nullptr;
85 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
86 if ( pSeqAny )
87 {
88 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
89 {
90 PropertyPairHashMap::iterator aHashIter( aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
91 if ( aHashIter != aPropPairHashMap.end() )
92 {
93 pRet = &const_cast<css::uno::Sequence<css::beans::PropertyValue> &>(*rSecSequence)[ (*aHashIter).second ].Value;
94 }
95 }
96 }
97 return pRet;
98 }
99
GetPropertyValueByName(const OUString & rSequenceName,const OUString & rPropName) const100 const css::uno::Any* SdrCustomShapeGeometryItem::GetPropertyValueByName( const OUString& rSequenceName, const OUString& rPropName ) const
101 {
102 const css::uno::Any* pRet = nullptr;
103 const css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
104 if ( pSeqAny )
105 {
106 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny) )
107 {
108 PropertyPairHashMap::const_iterator aHashIter( aPropPairHashMap.find( PropertyPair( rSequenceName, rPropName ) ) );
109 if ( aHashIter != aPropPairHashMap.end() )
110 {
111 pRet = &(*rSecSequence)[ (*aHashIter).second ].Value;
112 }
113 }
114 }
115 return pRet;
116 }
117
SetPropertyValue(const css::beans::PropertyValue & rPropVal)118 void SdrCustomShapeGeometryItem::SetPropertyValue( const css::beans::PropertyValue& rPropVal )
119 {
120 css::uno::Any* pAny = GetPropertyValueByName( rPropVal.Name );
121 if ( pAny )
122 { // property is already available
123 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
124 { // old property is a sequence->each entry has to be removed from the HashPairMap
125 for ( auto const & i : *rSecSequence )
126 {
127 PropertyPairHashMap::iterator aHashIter( aPropPairHashMap.find( PropertyPair( rPropVal.Name, i.Name ) ) );
128 if ( aHashIter != aPropPairHashMap.end() )
129 aPropPairHashMap.erase( aHashIter );
130 }
131 }
132 *pAny = rPropVal.Value;
133 if ( auto rSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pAny) )
134 { // the new property is a sequence->each entry has to be inserted into the HashPairMap
135 for ( sal_Int32 i = 0; i < rSecSequence->getLength(); i++ )
136 {
137 beans::PropertyValue const & rPropVal2 = (*rSecSequence)[ i ];
138 aPropPairHashMap[ PropertyPair( rPropVal.Name, rPropVal2.Name ) ] = i;
139 }
140 }
141 }
142 else
143 { // it's a new property
144 assert(std::none_of(aPropSeq.begin(), aPropSeq.end(),
145 [&rPropVal](beans::PropertyValue const& rVal)
146 { return rVal.Name == rPropVal.Name; } ));
147 sal_uInt32 nIndex = aPropSeq.getLength();
148 aPropSeq.realloc( nIndex + 1 );
149 aPropSeq[ nIndex ] = rPropVal ;
150
151 aPropHashMap[ rPropVal.Name ] = nIndex;
152 }
153 }
154
SetPropertyValue(const OUString & rSequenceName,const css::beans::PropertyValue & rPropVal)155 void SdrCustomShapeGeometryItem::SetPropertyValue( const OUString& rSequenceName, const css::beans::PropertyValue& rPropVal )
156 {
157 css::uno::Any* pAny = GetPropertyValueByName( rSequenceName, rPropVal.Name );
158 if ( pAny ) // just replacing
159 *pAny = rPropVal.Value;
160 else
161 {
162 css::uno::Any* pSeqAny = GetPropertyValueByName( rSequenceName );
163 if( pSeqAny == nullptr )
164 {
165 css::uno::Sequence < beans::PropertyValue > aSeq;
166 beans::PropertyValue aValue;
167 aValue.Name = rSequenceName;
168 aValue.Value <<= aSeq;
169
170 assert(std::none_of(aPropSeq.begin(), aPropSeq.end(),
171 [&rSequenceName](beans::PropertyValue const& rV)
172 { return rV.Name == rSequenceName; } ));
173 sal_uInt32 nIndex = aPropSeq.getLength();
174 aPropSeq.realloc( nIndex + 1 );
175 aPropSeq[ nIndex ] = aValue;
176 aPropHashMap[ rSequenceName ] = nIndex;
177
178 pSeqAny = &aPropSeq[ nIndex ].Value;
179 }
180
181 if (auto pSecSequence = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(*pSeqAny))
182 {
183 PropertyPairHashMap::iterator aHashIter(
184 aPropPairHashMap.find(PropertyPair(rSequenceName, rPropVal.Name)));
185 auto& rSeq = const_cast<css::uno::Sequence<css::beans::PropertyValue>&>(*pSecSequence);
186 if (aHashIter != aPropPairHashMap.end())
187 {
188 rSeq[(*aHashIter).second].Value = rPropVal.Value;
189 }
190 else
191 {
192 const sal_Int32 nCount = pSecSequence->getLength();
193 rSeq.realloc(nCount + 1);
194 rSeq[nCount] = rPropVal;
195
196 aPropPairHashMap[PropertyPair(rSequenceName, rPropVal.Name)] = nCount;
197 }
198 }
199 }
200 }
201
ClearPropertyValue(const OUString & rPropName)202 void SdrCustomShapeGeometryItem::ClearPropertyValue( const OUString& rPropName )
203 {
204 if ( !aPropSeq.hasElements() )
205 return;
206
207 PropertyHashMap::iterator aHashIter( aPropHashMap.find( rPropName ) );
208 if ( aHashIter == aPropHashMap.end() )
209 return;
210
211 css::uno::Any& rSeqAny = aPropSeq[(*aHashIter).second].Value;
212 if (auto pSecSequence
213 = o3tl::tryAccess<css::uno::Sequence<beans::PropertyValue>>(rSeqAny))
214 {
215 for (const auto& rPropVal : *pSecSequence)
216 {
217 auto _aHashIter(aPropPairHashMap.find(PropertyPair(rPropName, rPropVal.Name)));
218 if (_aHashIter != aPropPairHashMap.end())
219 aPropPairHashMap.erase(_aHashIter); // removing property from pair hashmap
220 }
221 }
222 sal_Int32 nLength = aPropSeq.getLength();
223 if ( nLength )
224 {
225 sal_Int32 nIndex = (*aHashIter).second;
226 if ( nIndex != ( nLength - 1 ) ) // resizing sequence
227 {
228 PropertyHashMap::iterator aHashIter2( aPropHashMap.find( aPropSeq[ nLength - 1 ].Name ) );
229 (*aHashIter2).second = nIndex;
230 aPropSeq[ nIndex ] = aPropSeq[ nLength - 1 ];
231 }
232 aPropSeq.realloc( nLength - 1 );
233 }
234 aPropHashMap.erase( aHashIter ); // removing property from hashmap
235 }
236
~SdrCustomShapeGeometryItem()237 SdrCustomShapeGeometryItem::~SdrCustomShapeGeometryItem()
238 {
239 }
operator ==(const SfxPoolItem & rCmp) const240 bool SdrCustomShapeGeometryItem::operator==( const SfxPoolItem& rCmp ) const
241 {
242 bool bRet = SfxPoolItem::operator==( rCmp );
243 if ( bRet )
244 bRet = static_cast<const SdrCustomShapeGeometryItem&>(rCmp).aPropSeq == aPropSeq;
245 return bRet;
246 }
247
GetPresentation(SfxItemPresentation ePresentation,MapUnit,MapUnit,OUString & rText,const IntlWrapper &) const248 bool SdrCustomShapeGeometryItem::GetPresentation(
249 SfxItemPresentation ePresentation, MapUnit /*eCoreMetric*/,
250 MapUnit /*ePresentationMetric*/, OUString &rText, const IntlWrapper&) const
251 {
252 rText += " ";
253 if ( ePresentation == SfxItemPresentation::Complete )
254 {
255 rText = " " + rText;
256 return true;
257 }
258 else if ( ePresentation == SfxItemPresentation::Nameless )
259 return true;
260 return false;
261 }
262
Clone(SfxItemPool *) const263 SdrCustomShapeGeometryItem* SdrCustomShapeGeometryItem::Clone( SfxItemPool * /*pPool*/ ) const
264 {
265 return new SdrCustomShapeGeometryItem( aPropSeq );
266 }
267
QueryValue(uno::Any & rVal,sal_uInt8) const268 bool SdrCustomShapeGeometryItem::QueryValue( uno::Any& rVal, sal_uInt8 /*nMemberId*/ ) const
269 {
270 rVal <<= aPropSeq;
271 return true;
272 }
273
PutValue(const uno::Any & rVal,sal_uInt8)274 bool SdrCustomShapeGeometryItem::PutValue( const uno::Any& rVal, sal_uInt8 /*nMemberId*/ )
275 {
276 if ( ! ( rVal >>= aPropSeq ) )
277 return false;
278
279 for (sal_Int32 i = 0; i < aPropSeq.getLength(); ++i)
280 {
281 const auto& rName = aPropSeq[i].Name;
282 bool isDuplicated = std::any_of(std::next(aPropSeq.begin(), i + 1), aPropSeq.end(),
283 [&rName](const css::beans::PropertyValue& rProp) { return rProp.Name == rName; });
284 if (isDuplicated)
285 {
286 assert(false); // serious bug: duplicate xml attribute exported
287 OUString const name(aPropSeq[i].Name);
288 aPropSeq.realloc(0);
289 throw uno::RuntimeException(
290 "CustomShapeGeometry has duplicate property " + name);
291 }
292 }
293 return true;
294 }
295
296 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
297