/src/libreoffice/xmloff/source/forms/elementimport.cxx
Line | Count | Source |
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 "elementimport.hxx" |
21 | | #include <utility> |
22 | | #include <xmloff/xmlimp.hxx> |
23 | | #include <xmloff/namespacemap.hxx> |
24 | | #include "strings.hxx" |
25 | | #include "callbacks.hxx" |
26 | | #include <xmloff/xmlnamespace.hxx> |
27 | | #include "eventimport.hxx" |
28 | | #include <xmloff/txtstyli.hxx> |
29 | | #include "formenums.hxx" |
30 | | #include <xmloff/xmltoken.hxx> |
31 | | #include "gridcolumnproptranslator.hxx" |
32 | | #include "property_description.hxx" |
33 | | #include "property_meta_data.hxx" |
34 | | |
35 | | #include <com/sun/star/uno/XComponentContext.hpp> |
36 | | #include <com/sun/star/text/XText.hpp> |
37 | | #include <com/sun/star/util/XCloneable.hpp> |
38 | | #include <com/sun/star/util/Duration.hpp> |
39 | | #include <com/sun/star/form/FormComponentType.hpp> |
40 | | #include <com/sun/star/awt/ImagePosition.hpp> |
41 | | #include <com/sun/star/beans/XMultiPropertySet.hpp> |
42 | | #include <com/sun/star/beans/XPropertyContainer.hpp> |
43 | | #include <com/sun/star/beans/PropertyAttribute.hpp> |
44 | | |
45 | | #include <sax/tools/converter.hxx> |
46 | | #include <tools/urlobj.hxx> |
47 | | #include <comphelper/diagnose_ex.hxx> |
48 | | #include <rtl/strbuf.hxx> |
49 | | #include <sal/log.hxx> |
50 | | #include <comphelper/extract.hxx> |
51 | | #include <comphelper/types.hxx> |
52 | | #include <comphelper/sequence.hxx> |
53 | | #include <o3tl/string_view.hxx> |
54 | | |
55 | | #include <algorithm> |
56 | | |
57 | | namespace xmloff |
58 | | { |
59 | | |
60 | | using namespace ::xmloff::token; |
61 | | using namespace ::com::sun::star; |
62 | | using namespace ::com::sun::star::uno; |
63 | | using namespace ::com::sun::star::awt; |
64 | | using namespace ::com::sun::star::container; |
65 | | using namespace ::com::sun::star::beans; |
66 | | using namespace ::com::sun::star::script; |
67 | | using namespace ::com::sun::star::lang; |
68 | | using namespace ::com::sun::star::form; |
69 | | using namespace ::com::sun::star::xml; |
70 | | using namespace ::com::sun::star::xml::sax; |
71 | | using namespace ::com::sun::star::util; |
72 | | using namespace ::com::sun::star::text; |
73 | | using namespace ::comphelper; |
74 | | |
75 | 0 | #define PROPID_VALUE 1 |
76 | 0 | #define PROPID_CURRENT_VALUE 2 |
77 | 0 | #define PROPID_MIN_VALUE 3 |
78 | 0 | #define PROPID_MAX_VALUE 4 |
79 | | |
80 | | namespace { |
81 | | |
82 | | struct PropertyValueLess |
83 | | { |
84 | | bool operator()(const PropertyValue& _rLeft, const PropertyValue& _rRight) |
85 | 0 | { |
86 | 0 | return _rLeft.Name < _rRight.Name; |
87 | 0 | } |
88 | | }; |
89 | | |
90 | | } |
91 | | |
92 | | //= OElementNameMap |
93 | | std::map<sal_Int32, OControlElement::ElementType> OElementNameMap::s_sElementTranslations2; |
94 | | |
95 | | const OControlElement::ElementType& operator ++(OControlElement::ElementType& _e) |
96 | 0 | { |
97 | 0 | OControlElement::ElementType e = _e; |
98 | 0 | sal_Int32 nAsInt = static_cast<sal_Int32>(e); |
99 | 0 | _e = static_cast<OControlElement::ElementType>( ++nAsInt ); |
100 | 0 | return _e; |
101 | 0 | } |
102 | | |
103 | | OControlElement::ElementType OElementNameMap::getElementType(sal_Int32 nElement) |
104 | 0 | { |
105 | 0 | if ( s_sElementTranslations2.empty() ) |
106 | 0 | { // initialize |
107 | 0 | for (ElementType eType=ElementType(0); eType<UNKNOWN; ++eType) |
108 | 0 | s_sElementTranslations2[getElementToken(eType)] = eType; |
109 | 0 | } |
110 | 0 | auto aPos = s_sElementTranslations2.find(nElement & TOKEN_MASK); |
111 | 0 | if (s_sElementTranslations2.end() != aPos) |
112 | 0 | return aPos->second; |
113 | | |
114 | 0 | return UNKNOWN; |
115 | 0 | } |
116 | | |
117 | | //= OElementImport |
118 | | OElementImport::OElementImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
119 | | const Reference< XNameContainer >& _rxParentContainer) |
120 | 0 | :OPropertyImport(_rImport) |
121 | 0 | ,m_rFormImport(_rImport) |
122 | 0 | ,m_rEventManager(_rEventManager) |
123 | 0 | ,m_pStyleElement( nullptr ) |
124 | 0 | ,m_xParentContainer(_rxParentContainer) |
125 | 0 | ,m_bImplicitGenericAttributeHandling( true ) |
126 | 0 | { |
127 | 0 | OSL_ENSURE(m_xParentContainer.is(), "OElementImport::OElementImport: invalid parent container!"); |
128 | 0 | } |
129 | | |
130 | | OElementImport::~OElementImport() |
131 | 0 | { |
132 | 0 | } |
133 | | |
134 | | OUString OElementImport::determineDefaultServiceName() const |
135 | 0 | { |
136 | 0 | return OUString(); |
137 | 0 | } |
138 | | |
139 | | void OElementImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) |
140 | 0 | { |
141 | 0 | ENTER_LOG_CONTEXT( "xmloff::OElementImport - importing one element" ); |
142 | |
|
143 | 0 | const OUString sControlImplementation = _rxAttrList->getOptionalValue( XML_ELEMENT(FORM, XML_CONTROL_IMPLEMENTATION) ); |
144 | | |
145 | | // retrieve the service name |
146 | 0 | if ( !sControlImplementation.isEmpty() ) |
147 | 0 | { |
148 | 0 | OUString sOOoImplementationName; |
149 | 0 | const sal_uInt16 nImplPrefix = GetImport().GetNamespaceMap().GetKeyByAttrValueQName( sControlImplementation, &sOOoImplementationName ); |
150 | 0 | m_sServiceName = ( nImplPrefix == XML_NAMESPACE_OOO ) ? sOOoImplementationName : sControlImplementation; |
151 | 0 | } |
152 | |
|
153 | 0 | if ( m_sServiceName.isEmpty() ) |
154 | 0 | m_sServiceName = determineDefaultServiceName(); |
155 | | |
156 | | // create the object *now*. This allows setting properties in the various handleAttribute methods. |
157 | | // (Though currently not all code is migrated to this pattern, most attributes are still handled |
158 | | // by remembering the value (via implPushBackPropertyValue), and setting the correct property value |
159 | | // later (in OControlImport::StartElement).) |
160 | 0 | m_xElement = createElement(); |
161 | 0 | if ( m_xElement.is() ) |
162 | 0 | m_xInfo = m_xElement->getPropertySetInfo(); |
163 | | |
164 | | // call the base class |
165 | 0 | OPropertyImport::startFastElement( nElement, _rxAttrList ); |
166 | 0 | } |
167 | | |
168 | | css::uno::Reference< css::xml::sax::XFastContextHandler > OElementImport::createFastChildContext( |
169 | | sal_Int32 nElement, |
170 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList ) |
171 | 0 | { |
172 | 0 | if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) |
173 | 0 | return new OFormEventsImportContext(m_rFormImport.getGlobalContext(), *this); |
174 | | |
175 | 0 | return OPropertyImport::createFastChildContext(nElement, _rxAttrList); |
176 | 0 | } |
177 | | |
178 | | void OElementImport::endFastElement(sal_Int32 ) |
179 | 0 | { |
180 | 0 | OSL_ENSURE(m_xElement.is(), "OElementImport::EndElement: invalid element created!"); |
181 | 0 | if (!m_xElement.is()) |
182 | 0 | return; |
183 | | |
184 | | // apply the non-generic properties |
185 | 0 | implApplySpecificProperties(); |
186 | | |
187 | | // set the generic properties |
188 | 0 | implApplyGenericProperties(); |
189 | | |
190 | | // set the style properties |
191 | 0 | if ( m_pStyleElement && m_xElement.is() ) |
192 | 0 | { |
193 | 0 | Reference< XPropertySet > xPropTranslation = |
194 | 0 | new OGridColumnPropertyTranslator( Reference< XMultiPropertySet >( m_xElement, UNO_QUERY ) ); |
195 | 0 | const_cast< XMLTextStyleContext* >( m_pStyleElement )->FillPropertySet( xPropTranslation ); |
196 | |
|
197 | 0 | const OUString sNumberStyleName = m_pStyleElement->GetDataStyleName( ); |
198 | 0 | if ( !sNumberStyleName.isEmpty() ) |
199 | | // the style also has a number (sub) style |
200 | 0 | m_rContext.applyControlNumberStyle( m_xElement, sNumberStyleName ); |
201 | 0 | } |
202 | | |
203 | | // insert the element into the parent container |
204 | 0 | if (m_sName.isEmpty()) |
205 | 0 | { |
206 | 0 | OSL_FAIL("OElementImport::EndElement: did not find a name attribute!"); |
207 | 0 | m_sName = implGetDefaultName(); |
208 | 0 | } |
209 | |
|
210 | 0 | if (m_xParentContainer.is()) |
211 | 0 | m_xParentContainer->insertByName(m_sName, Any(m_xElement)); |
212 | |
|
213 | 0 | LEAVE_LOG_CONTEXT( ); |
214 | 0 | } |
215 | | |
216 | | void OElementImport::implApplySpecificProperties() |
217 | 0 | { |
218 | 0 | if ( m_aValues.empty() ) |
219 | 0 | return; |
220 | | |
221 | | // set all the properties we collected |
222 | | #if OSL_DEBUG_LEVEL > 0 |
223 | | // check if the object has all the properties |
224 | | // (We do this in the non-pro version only. Doing it all the time would be too much expensive) |
225 | | if ( m_xInfo.is() ) |
226 | | { |
227 | | for ( const auto& rCheck : m_aValues ) |
228 | | { |
229 | | OSL_ENSURE(m_xInfo->hasPropertyByName(rCheck.Name), |
230 | | OStringBuffer("OElementImport::implApplySpecificProperties: read a property (" + |
231 | | OUStringToOString(rCheck.Name, RTL_TEXTENCODING_ASCII_US) + |
232 | | ") which does not exist on the element!").getStr()); |
233 | | } |
234 | | } |
235 | | #endif |
236 | | |
237 | | // set the properties |
238 | 0 | const Reference< XMultiPropertySet > xMultiProps(m_xElement, UNO_QUERY); |
239 | 0 | bool bSuccess = false; |
240 | 0 | if (xMultiProps.is()) |
241 | 0 | { |
242 | | // translate our properties so that the XMultiPropertySet can handle them |
243 | | |
244 | | // sort our property value array so that we can use it in a setPropertyValues |
245 | 0 | ::std::sort( m_aValues.begin(), m_aValues.end(), PropertyValueLess()); |
246 | | |
247 | | // the names |
248 | 0 | Sequence< OUString > aNames(m_aValues.size()); |
249 | 0 | OUString* pNames = aNames.getArray(); |
250 | | // the values |
251 | 0 | Sequence< Any > aValues(m_aValues.size()); |
252 | 0 | Any* pValues = aValues.getArray(); |
253 | | // copy |
254 | |
|
255 | 0 | for ( const auto& rPropValues : m_aValues ) |
256 | 0 | { |
257 | 0 | *pNames = rPropValues.Name; |
258 | 0 | *pValues = rPropValues.Value; |
259 | 0 | ++pNames; |
260 | 0 | ++pValues; |
261 | 0 | } |
262 | |
|
263 | 0 | try |
264 | 0 | { |
265 | 0 | xMultiProps->setPropertyValues(aNames, aValues); |
266 | 0 | bSuccess = true; |
267 | 0 | } |
268 | 0 | catch(const Exception&) |
269 | 0 | { |
270 | 0 | DBG_UNHANDLED_EXCEPTION("xmloff.forms"); |
271 | 0 | OSL_FAIL("OElementImport::implApplySpecificProperties: could not set the properties (using the XMultiPropertySet)!"); |
272 | 0 | } |
273 | 0 | } |
274 | |
|
275 | 0 | if (bSuccess) |
276 | 0 | return; |
277 | | |
278 | | // no XMultiPropertySet or setting all properties at once failed |
279 | 0 | for ( const auto& rPropValues : m_aValues ) |
280 | 0 | { |
281 | | // this try/catch here is expensive, but because this is just a fallback which should normally not be |
282 | | // used it's acceptable this way ... |
283 | 0 | try |
284 | 0 | { |
285 | 0 | m_xElement->setPropertyValue(rPropValues.Name, rPropValues.Value); |
286 | 0 | } |
287 | 0 | catch(const Exception&) |
288 | 0 | { |
289 | 0 | DBG_UNHANDLED_EXCEPTION("xmloff.forms"); |
290 | 0 | OSL_FAIL(OStringBuffer("OElementImport::implApplySpecificProperties: could not set the property \"" + |
291 | 0 | OUStringToOString(rPropValues.Name, RTL_TEXTENCODING_ASCII_US) + |
292 | 0 | "\"!").getStr()); |
293 | 0 | } |
294 | 0 | } |
295 | 0 | } |
296 | | |
297 | | void OElementImport::implApplyGenericProperties() |
298 | 0 | { |
299 | 0 | if ( m_aGenericValues.empty() ) |
300 | 0 | return; |
301 | | |
302 | 0 | Reference< XPropertyContainer > xDynamicProperties( m_xElement, UNO_QUERY ); |
303 | | |
304 | | // PropertyValueArray::iterator aEnd = m_aGenericValues.end(); |
305 | 0 | for ( auto& rPropValues : m_aGenericValues ) |
306 | 0 | { |
307 | | // check property type for numeric types before setting |
308 | | // the property |
309 | 0 | try |
310 | 0 | { |
311 | | // if such a property does not yet exist at the element, create it if necessary |
312 | 0 | const bool bExistentProperty = m_xInfo->hasPropertyByName( rPropValues.Name ); |
313 | 0 | if ( !bExistentProperty ) |
314 | 0 | { |
315 | 0 | if ( !xDynamicProperties.is() ) |
316 | 0 | { |
317 | 0 | SAL_WARN( "xmloff", "OElementImport::implApplyGenericProperties: encountered an unknown property (" |
318 | 0 | << rPropValues.Name << "), but component is no PropertyBag!"); |
319 | 0 | continue; |
320 | 0 | } |
321 | | |
322 | 0 | xDynamicProperties->addProperty( |
323 | 0 | rPropValues.Name, |
324 | 0 | PropertyAttribute::BOUND | PropertyAttribute::REMOVABLE, |
325 | 0 | rPropValues.Value |
326 | 0 | ); |
327 | | |
328 | | // re-fetch the PropertySetInfo |
329 | 0 | m_xInfo = m_xElement->getPropertySetInfo(); |
330 | 0 | } |
331 | | |
332 | | // determine the type of the value (source for the following conversion) |
333 | 0 | TypeClass eValueTypeClass = rPropValues.Value.getValueTypeClass(); |
334 | 0 | const bool bValueIsSequence = TypeClass_SEQUENCE == eValueTypeClass; |
335 | 0 | if ( bValueIsSequence ) |
336 | 0 | { |
337 | 0 | uno::Type aSimpleType( getSequenceElementType( rPropValues.Value.getValueType() ) ); |
338 | 0 | eValueTypeClass = aSimpleType.getTypeClass(); |
339 | 0 | } |
340 | | |
341 | | // determine the type of the property (target for the following conversion) |
342 | 0 | const Property aProperty( m_xInfo->getPropertyByName( rPropValues.Name ) ); |
343 | 0 | TypeClass ePropTypeClass = aProperty.Type.getTypeClass(); |
344 | 0 | const bool bPropIsSequence = TypeClass_SEQUENCE == ePropTypeClass; |
345 | 0 | if( bPropIsSequence ) |
346 | 0 | { |
347 | 0 | uno::Type aSimpleType( ::comphelper::getSequenceElementType( aProperty.Type ) ); |
348 | 0 | ePropTypeClass = aSimpleType.getTypeClass(); |
349 | 0 | } |
350 | |
|
351 | 0 | if ( bPropIsSequence != bValueIsSequence ) |
352 | 0 | { |
353 | 0 | OSL_FAIL( "OElementImport::implImportGenericProperties: either both value and property should be a sequence, or none of them!" ); |
354 | 0 | continue; |
355 | 0 | } |
356 | | |
357 | 0 | if ( bValueIsSequence ) |
358 | 0 | { |
359 | 0 | Sequence< Any > aXMLValueList; |
360 | 0 | rPropValues.Value >>= aXMLValueList; |
361 | | // just skip this part if empty sequence |
362 | 0 | if (!aXMLValueList.getLength()) |
363 | 0 | continue; |
364 | | |
365 | 0 | Sequence< sal_Int16 > aPropertyValueList( aXMLValueList.getLength() ); |
366 | |
|
367 | 0 | SAL_WARN_IF( eValueTypeClass != TypeClass_ANY, "xmloff", |
368 | 0 | "OElementImport::implApplyGenericProperties: only ANYs should have been imported as generic list property!" ); |
369 | | // (OPropertyImport should produce only Sequencer< Any >, since it cannot know the real type |
370 | | |
371 | 0 | SAL_WARN_IF( ePropTypeClass != TypeClass_SHORT, "xmloff", |
372 | 0 | "OElementImport::implApplyGenericProperties: conversion to sequences other than 'sequence< short >' not implemented, yet!" ); |
373 | | |
374 | | |
375 | 0 | std::transform(std::cbegin(aXMLValueList), std::cend(aXMLValueList), aPropertyValueList.getArray(), |
376 | 0 | [](const Any& rXMLValue) -> sal_Int16 { |
377 | | // only value sequences of numeric types implemented so far. |
378 | 0 | double nVal( 0 ); |
379 | 0 | OSL_VERIFY( rXMLValue >>= nVal ); |
380 | 0 | return static_cast< sal_Int16 >( nVal ); |
381 | 0 | }); |
382 | |
|
383 | 0 | rPropValues.Value <<= aPropertyValueList; |
384 | 0 | } |
385 | 0 | else if ( ePropTypeClass != eValueTypeClass ) |
386 | 0 | { |
387 | 0 | switch ( eValueTypeClass ) |
388 | 0 | { |
389 | 0 | case TypeClass_DOUBLE: |
390 | 0 | { |
391 | 0 | double nVal = 0; |
392 | 0 | rPropValues.Value >>= nVal; |
393 | 0 | switch( ePropTypeClass ) |
394 | 0 | { |
395 | 0 | case TypeClass_BYTE: |
396 | 0 | rPropValues.Value <<= static_cast< sal_Int8 >( nVal ); |
397 | 0 | break; |
398 | 0 | case TypeClass_SHORT: |
399 | 0 | rPropValues.Value <<= static_cast< sal_Int16 >( nVal ); |
400 | 0 | break; |
401 | 0 | case TypeClass_UNSIGNED_SHORT: |
402 | 0 | rPropValues.Value <<= static_cast< sal_uInt16 >( nVal ); |
403 | 0 | break; |
404 | 0 | case TypeClass_LONG: |
405 | 0 | case TypeClass_ENUM: |
406 | 0 | rPropValues.Value <<= static_cast< sal_Int32 >( nVal ); |
407 | 0 | break; |
408 | 0 | case TypeClass_UNSIGNED_LONG: |
409 | 0 | rPropValues.Value <<= static_cast< sal_uInt32 >( nVal ); |
410 | 0 | break; |
411 | 0 | case TypeClass_UNSIGNED_HYPER: |
412 | 0 | rPropValues.Value <<= static_cast< sal_uInt64 >( nVal ); |
413 | 0 | break; |
414 | 0 | case TypeClass_HYPER: |
415 | 0 | rPropValues.Value <<= static_cast< sal_Int64 >( nVal ); |
416 | 0 | break; |
417 | 0 | default: |
418 | 0 | OSL_FAIL( "OElementImport::implImportGenericProperties: unsupported value type!" ); |
419 | 0 | break; |
420 | 0 | } |
421 | 0 | } |
422 | 0 | break; |
423 | 0 | default: |
424 | 0 | OSL_FAIL( "OElementImport::implImportGenericProperties: non-double values not supported!" ); |
425 | 0 | break; |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | 0 | m_xElement->setPropertyValue( rPropValues.Name, rPropValues.Value ); |
430 | 0 | } |
431 | 0 | catch(const Exception&) |
432 | 0 | { |
433 | 0 | DBG_UNHANDLED_EXCEPTION("xmloff.forms"); |
434 | 0 | OSL_FAIL(OStringBuffer("OElementImport::EndElement: could not set the property \"" + |
435 | 0 | OUStringToOString(rPropValues.Name, RTL_TEXTENCODING_ASCII_US) + |
436 | 0 | "\"!").getStr()); |
437 | 0 | } |
438 | 0 | } |
439 | 0 | } |
440 | | |
441 | | OUString OElementImport::implGetDefaultName() const |
442 | 0 | { |
443 | | // no optimization here. If this method gets called, the XML stream did not contain a name for the |
444 | | // element, which is a heavy error. So in this case we don't care for performance |
445 | 0 | static constexpr OUString sUnnamedName = u"unnamed"_ustr; |
446 | 0 | OSL_ENSURE(m_xParentContainer.is(), "OElementImport::implGetDefaultName: no parent container!"); |
447 | 0 | if (!m_xParentContainer.is()) |
448 | 0 | return sUnnamedName; |
449 | 0 | Sequence< OUString > aNames = m_xParentContainer->getElementNames(); |
450 | |
|
451 | 0 | for (sal_Int32 i=0; i<32768; ++i) // the limit is nearly arbitrary... |
452 | 0 | { |
453 | | // assemble the new name (suggestion) |
454 | 0 | OUString sReturn = sUnnamedName + OUString::number(i); |
455 | | // check the existence (this is the bad performance part...) |
456 | 0 | if (comphelper::findValue(aNames, sReturn) == -1) |
457 | | // not found the name |
458 | 0 | return sReturn; |
459 | 0 | } |
460 | 0 | OSL_FAIL("OElementImport::implGetDefaultName: did not find a free name!"); |
461 | 0 | return sUnnamedName; |
462 | 0 | } |
463 | | |
464 | | PropertyGroups::const_iterator OElementImport::impl_matchPropertyGroup( const PropertyGroups& i_propertyGroups ) const |
465 | 0 | { |
466 | 0 | ENSURE_OR_RETURN( m_xInfo.is(), "OElementImport::impl_matchPropertyGroup: no property set info!", i_propertyGroups.end() ); |
467 | |
|
468 | 0 | return std::find_if(i_propertyGroups.cbegin(), i_propertyGroups.cend(), [&](const PropertyDescriptionList& rGroup) { |
469 | 0 | return std::all_of(rGroup.cbegin(), rGroup.cend(), [&](const PropertyDescription* prop) { |
470 | 0 | return m_xInfo->hasPropertyByName( prop->propertyName ); |
471 | 0 | }); |
472 | 0 | }); |
473 | 0 | } |
474 | | |
475 | | bool OElementImport::tryGenericAttribute( sal_Int32 nElement, const OUString& _rValue ) |
476 | 0 | { |
477 | | // the generic approach (which I hope all props will be migrated to, on the medium term): property handlers |
478 | 0 | const AttributeDescription attribute( metadata::getAttributeDescription( nElement ) ); |
479 | 0 | if ( attribute.attributeToken != XML_TOKEN_INVALID ) |
480 | 0 | { |
481 | 0 | PropertyGroups propertyGroups; |
482 | 0 | metadata::getPropertyGroupList( attribute, propertyGroups ); |
483 | 0 | const PropertyGroups::const_iterator pos = impl_matchPropertyGroup( propertyGroups ); |
484 | 0 | if ( pos == propertyGroups.end() ) |
485 | 0 | return false; |
486 | | |
487 | 0 | do |
488 | 0 | { |
489 | 0 | const PropertyDescriptionList& rProperties( *pos ); |
490 | 0 | const PropertyDescription* first = *rProperties.begin(); |
491 | 0 | if ( !first ) |
492 | 0 | { |
493 | 0 | SAL_WARN( "xmloff.forms", "OElementImport::handleAttribute: invalid property description!" ); |
494 | 0 | break; |
495 | 0 | } |
496 | | |
497 | 0 | const PPropertyHandler handler = (*first->factory)( first->propertyId ); |
498 | 0 | if ( !handler ) |
499 | 0 | { |
500 | 0 | SAL_WARN( "xmloff.forms", "OElementImport::handleAttribute: invalid property handler!" ); |
501 | 0 | break; |
502 | 0 | } |
503 | | |
504 | 0 | PropertyValues aValues; |
505 | 0 | for ( const auto& propDesc : rProperties ) |
506 | 0 | { |
507 | 0 | aValues[ propDesc->propertyId ] = Any(); |
508 | 0 | } |
509 | 0 | if ( handler->getPropertyValues( _rValue, aValues ) ) |
510 | 0 | { |
511 | 0 | for ( const auto& propDesc : rProperties ) |
512 | 0 | { |
513 | 0 | implPushBackPropertyValue( propDesc->propertyName, aValues[ propDesc->propertyId ] ); |
514 | 0 | } |
515 | 0 | } |
516 | 0 | } |
517 | 0 | while ( false ); |
518 | | |
519 | | // handled |
520 | 0 | return true; |
521 | 0 | } |
522 | 0 | return false; |
523 | 0 | } |
524 | | |
525 | | bool OElementImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) |
526 | 0 | { |
527 | 0 | auto nLocal = nElement & TOKEN_MASK; |
528 | 0 | if ( nLocal == XML_CONTROL_IMPLEMENTATION ) |
529 | | // ignore this, it has already been handled in OElementImport::StartElement |
530 | 0 | return true; |
531 | | |
532 | 0 | if ( nLocal == XML_NAME ) |
533 | 0 | { |
534 | 0 | if ( m_sName.isEmpty() ) |
535 | | // remember the name for later use in EndElement |
536 | 0 | m_sName = _rValue; |
537 | 0 | return true; |
538 | 0 | } |
539 | | |
540 | | // maybe it's the style attribute? |
541 | 0 | if ( nLocal == XML_TEXT_STYLE_NAME ) |
542 | 0 | { |
543 | 0 | const SvXMLStyleContext* pStyleContext = m_rContext.getStyleElement( _rValue ); |
544 | 0 | OSL_ENSURE( pStyleContext, "OElementImport::handleAttribute: do not know the style!" ); |
545 | | // remember the element for later usage. |
546 | 0 | m_pStyleElement = dynamic_cast<const XMLTextStyleContext*>( pStyleContext ); |
547 | 0 | return true; |
548 | 0 | } |
549 | | |
550 | 0 | if ( m_bImplicitGenericAttributeHandling ) |
551 | 0 | if ( tryGenericAttribute( nElement, _rValue ) ) |
552 | 0 | return true; |
553 | | |
554 | | // let the base class handle it |
555 | 0 | return OPropertyImport::handleAttribute( nElement, _rValue); |
556 | 0 | } |
557 | | |
558 | | Reference< XPropertySet > OElementImport::createElement() |
559 | 0 | { |
560 | 0 | Reference< XPropertySet > xReturn; |
561 | 0 | if (!m_sServiceName.isEmpty()) |
562 | 0 | { |
563 | 0 | Reference< XComponentContext > xContext = m_rFormImport.getGlobalContext().GetComponentContext(); |
564 | 0 | Reference< XInterface > xPure = xContext->getServiceManager()->createInstanceWithContext(m_sServiceName, xContext); |
565 | 0 | OSL_ENSURE(xPure.is(), |
566 | 0 | OStringBuffer("OElementImport::createElement: service factory gave me no object (service name: " + |
567 | 0 | OUStringToOString(m_sServiceName, RTL_TEXTENCODING_ASCII_US) + |
568 | 0 | ")!").getStr()); |
569 | 0 | xReturn.set(xPure, UNO_QUERY); |
570 | 0 | if (auto const props = Reference<css::beans::XPropertySet>(xPure, css::uno::UNO_QUERY)) |
571 | 0 | { |
572 | 0 | try { |
573 | 0 | props->setPropertyValue( |
574 | 0 | u"Referer"_ustr, css::uno::Any(m_rFormImport.getGlobalContext().GetBaseURL())); |
575 | 0 | } catch (css::uno::Exception &) { |
576 | 0 | TOOLS_INFO_EXCEPTION("xmloff.forms", "setPropertyValue Referer failed"); |
577 | 0 | } |
578 | 0 | } |
579 | 0 | } |
580 | 0 | else |
581 | 0 | OSL_FAIL("OElementImport::createElement: no service name to create an element!"); |
582 | | |
583 | 0 | return xReturn; |
584 | 0 | } |
585 | | |
586 | | void OElementImport::registerEvents(const Sequence< ScriptEventDescriptor >& _rEvents) |
587 | 0 | { |
588 | 0 | OSL_ENSURE(m_xElement.is(), "OElementImport::registerEvents: no element to register events for!"); |
589 | 0 | m_rEventManager.registerEvents(m_xElement, _rEvents); |
590 | 0 | } |
591 | | |
592 | | void OElementImport::simulateDefaultedAttribute(sal_Int32 nElement, const OUString& _rPropertyName, const OUString& _pAttributeDefault) |
593 | 0 | { |
594 | 0 | OSL_ENSURE( m_xInfo.is(), "OPropertyImport::simulateDefaultedAttribute: the component should be more gossipy about it's properties!" ); |
595 | |
|
596 | 0 | if ( !m_xInfo.is() || m_xInfo->hasPropertyByName( _rPropertyName ) ) |
597 | 0 | { |
598 | 0 | if ( !encounteredAttribute( nElement ) ) |
599 | 0 | OSL_VERIFY( handleAttribute( XML_ELEMENT(FORM, (nElement & TOKEN_MASK)), _pAttributeDefault ) ); |
600 | 0 | } |
601 | 0 | } |
602 | | |
603 | | //= OControlImport |
604 | | OControlImport::OControlImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
605 | | const Reference< XNameContainer >& _rxParentContainer) |
606 | 0 | :OElementImport(_rImport, _rEventManager, _rxParentContainer) |
607 | 0 | ,m_eElementType(OControlElement::UNKNOWN) |
608 | 0 | { |
609 | 0 | disableImplicitGenericAttributeHandling(); |
610 | 0 | } |
611 | | |
612 | | OControlImport::OControlImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
613 | | const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType) |
614 | 0 | :OElementImport(_rImport, _rEventManager, _rxParentContainer) |
615 | 0 | ,m_eElementType(_eType) |
616 | 0 | { |
617 | 0 | disableImplicitGenericAttributeHandling(); |
618 | 0 | } |
619 | | |
620 | | OUString OControlImport::determineDefaultServiceName() const |
621 | 0 | { |
622 | 0 | const char* pServiceName = nullptr; |
623 | 0 | switch ( m_eElementType ) |
624 | 0 | { |
625 | 0 | case OControlElement::TEXT: |
626 | 0 | case OControlElement::TEXT_AREA: |
627 | 0 | case OControlElement::PASSWORD: pServiceName = "com.sun.star.form.component.TextField"; break; |
628 | 0 | case OControlElement::FILE: pServiceName = "com.sun.star.form.component.FileControl"; break; |
629 | 0 | case OControlElement::FORMATTED_TEXT: pServiceName = "com.sun.star.form.component.FormattedField"; break; |
630 | 0 | case OControlElement::FIXED_TEXT: pServiceName = "com.sun.star.form.component.FixedText"; break; |
631 | 0 | case OControlElement::COMBOBOX: pServiceName = "com.sun.star.form.component.ComboBox"; break; |
632 | 0 | case OControlElement::LISTBOX: pServiceName = "com.sun.star.form.component.ListBox"; break; |
633 | 0 | case OControlElement::BUTTON: pServiceName = "com.sun.star.form.component.CommandButton"; break; |
634 | 0 | case OControlElement::IMAGE: pServiceName = "com.sun.star.form.component.ImageButton"; break; |
635 | 0 | case OControlElement::CHECKBOX: pServiceName = "com.sun.star.form.component.CheckBox"; break; |
636 | 0 | case OControlElement::RADIO: pServiceName = "com.sun.star.form.component.RadioButton"; break; |
637 | 0 | case OControlElement::FRAME: pServiceName = "com.sun.star.form.component.GroupBox"; break; |
638 | 0 | case OControlElement::IMAGE_FRAME: pServiceName = "com.sun.star.form.component.DatabaseImageControl"; break; |
639 | 0 | case OControlElement::HIDDEN: pServiceName = "com.sun.star.form.component.HiddenControl"; break; |
640 | 0 | case OControlElement::GRID: pServiceName = "com.sun.star.form.component.GridControl"; break; |
641 | 0 | case OControlElement::VALUERANGE: pServiceName = "com.sun.star.form.component.ScrollBar"; break; |
642 | 0 | case OControlElement::TIME: pServiceName = "com.sun.star.form.component.TimeField"; break; |
643 | 0 | case OControlElement::DATE: pServiceName = "com.sun.star.form.component.DateField"; break; |
644 | 0 | default: break; |
645 | 0 | } |
646 | 0 | if ( pServiceName != nullptr ) |
647 | 0 | return OUString::createFromAscii( pServiceName ); |
648 | 0 | return OUString(); |
649 | 0 | } |
650 | | |
651 | | void OControlImport::addOuterAttributes(const Reference< XFastAttributeList >& _rxOuterAttribs) |
652 | 0 | { |
653 | 0 | OSL_ENSURE(!m_xOuterAttributes.is(), "OControlImport::addOuterAttributes: already have these attributes!"); |
654 | 0 | m_xOuterAttributes = _rxOuterAttribs; |
655 | 0 | } |
656 | | |
657 | | bool OControlImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) |
658 | 0 | { |
659 | 0 | static sal_Int32 nLinkedCellAttributeName = OAttributeMetaData::getBindingAttributeToken(BAFlags::LinkedCell); |
660 | |
|
661 | 0 | if ((nElement & TOKEN_MASK) == XML_ID) |
662 | 0 | { // it's the control id |
663 | 0 | if (IsTokenInNamespace(nElement, XML_NAMESPACE_XML)) |
664 | 0 | { |
665 | 0 | m_sControlId = _rValue; |
666 | 0 | } |
667 | 0 | else if (IsTokenInNamespace(nElement, XML_NAMESPACE_FORM)) |
668 | 0 | { |
669 | 0 | if (m_sControlId.isEmpty()) |
670 | 0 | { |
671 | 0 | m_sControlId = _rValue; |
672 | 0 | } |
673 | 0 | } |
674 | 0 | return true; |
675 | 0 | } |
676 | | |
677 | 0 | if ( (nElement & TOKEN_MASK) == nLinkedCellAttributeName ) |
678 | 0 | { // it's the address of a spreadsheet cell |
679 | 0 | m_sBoundCellAddress = _rValue; |
680 | 0 | return true; |
681 | 0 | } |
682 | | |
683 | 0 | if ( nElement == XML_ELEMENT(XFORMS, XML_BIND ) ) |
684 | 0 | { |
685 | 0 | m_sBindingID = _rValue; |
686 | 0 | return true; |
687 | 0 | } |
688 | | |
689 | 0 | if ( nElement == XML_ELEMENT(FORM, XML_XFORMS_LIST_SOURCE) ) |
690 | 0 | { |
691 | 0 | m_sListBindingID = _rValue; |
692 | 0 | return true; |
693 | 0 | } |
694 | | |
695 | 0 | if ( nElement == XML_ELEMENT(FORM, XML_XFORMS_SUBMISSION) |
696 | 0 | || nElement == XML_ELEMENT(XFORMS, XML_SUBMISSION) ) |
697 | 0 | { |
698 | 0 | m_sSubmissionID = _rValue; |
699 | 0 | return true; |
700 | 0 | } |
701 | | |
702 | 0 | if ( OElementImport::tryGenericAttribute( nElement, _rValue ) ) |
703 | 0 | return true; |
704 | | |
705 | 0 | static const sal_Int32 nValueAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Value); |
706 | 0 | static const sal_Int32 nCurrentValueAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentValue); |
707 | 0 | static const sal_Int32 nMinValueAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::MinValue); |
708 | 0 | static const sal_Int32 nMaxValueAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::MaxValue); |
709 | 0 | static const sal_Int32 nRepeatDelayAttributeName = OAttributeMetaData::getSpecialAttributeToken( SCAFlags::RepeatDelay ); |
710 | |
|
711 | 0 | sal_Int32 nHandle = -1; |
712 | 0 | if ( (nElement & TOKEN_MASK) == nValueAttributeName ) |
713 | 0 | nHandle = PROPID_VALUE; |
714 | 0 | else if ( (nElement & TOKEN_MASK) == nCurrentValueAttributeName ) |
715 | 0 | nHandle = PROPID_CURRENT_VALUE; |
716 | 0 | else if ( (nElement & TOKEN_MASK) == nMinValueAttributeName ) |
717 | 0 | nHandle = PROPID_MIN_VALUE; |
718 | 0 | else if ( (nElement & TOKEN_MASK) == nMaxValueAttributeName ) |
719 | 0 | nHandle = PROPID_MAX_VALUE; |
720 | 0 | if ( nHandle != -1 ) |
721 | 0 | { |
722 | | // for the moment, simply remember the name and the value |
723 | 0 | PropertyValue aProp; |
724 | 0 | aProp.Name = SvXMLImport::getNameFromToken(nElement); |
725 | 0 | aProp.Handle = nHandle; |
726 | 0 | aProp.Value <<= _rValue; |
727 | 0 | m_aValueProperties.push_back(aProp); |
728 | 0 | return true; |
729 | 0 | } |
730 | | |
731 | 0 | if ( (nElement & TOKEN_MASK) == nRepeatDelayAttributeName ) |
732 | 0 | { |
733 | 0 | util::Duration aDuration; |
734 | 0 | if (::sax::Converter::convertDuration(aDuration, _rValue)) |
735 | 0 | { |
736 | 0 | PropertyValue aProp; |
737 | 0 | aProp.Name = PROPERTY_REPEAT_DELAY; |
738 | 0 | sal_Int32 const nMS = |
739 | 0 | ((aDuration.Hours * 60 + aDuration.Minutes) * 60 |
740 | 0 | + aDuration.Seconds) * 1000 + aDuration.NanoSeconds/1000000; |
741 | 0 | aProp.Value <<= nMS; |
742 | |
|
743 | 0 | implPushBackPropertyValue(aProp); |
744 | 0 | } |
745 | 0 | return true; |
746 | 0 | } |
747 | | |
748 | 0 | return OElementImport::handleAttribute( nElement, _rValue ); |
749 | 0 | } |
750 | | |
751 | | void OControlImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) |
752 | 0 | { |
753 | 0 | css::uno::Reference< css::xml::sax::XFastAttributeList > xMergedAttributes; |
754 | 0 | if( m_xOuterAttributes.is() ) |
755 | 0 | { |
756 | | // merge the attribute lists, our own one |
757 | 0 | rtl::Reference<sax_fastparser::FastAttributeList> xMerger(new sax_fastparser::FastAttributeList(_rxAttrList)); |
758 | | // and the ones of our enclosing element |
759 | 0 | xMerger->add(m_xOuterAttributes); |
760 | 0 | xMergedAttributes = xMerger.get(); |
761 | 0 | } |
762 | 0 | else |
763 | 0 | { |
764 | 0 | xMergedAttributes = _rxAttrList; |
765 | 0 | } |
766 | | |
767 | | // let the base class handle all the attributes |
768 | 0 | OElementImport::startFastElement(nElement, xMergedAttributes); |
769 | |
|
770 | 0 | if ( m_aValueProperties.empty() || !m_xElement.is()) |
771 | 0 | return; |
772 | | |
773 | | // get the property set info |
774 | 0 | if (!m_xInfo.is()) |
775 | 0 | { |
776 | 0 | OSL_FAIL("OControlImport::StartElement: no PropertySetInfo!"); |
777 | 0 | return; |
778 | 0 | } |
779 | | |
780 | 0 | OUString pValueProperty; |
781 | 0 | OUString pCurrentValueProperty; |
782 | 0 | OUString pMinValueProperty; |
783 | 0 | OUString pMaxValueProperty; |
784 | |
|
785 | 0 | bool bRetrievedValues = false; |
786 | 0 | bool bRetrievedValueLimits = false; |
787 | | |
788 | | // get the class id of our element |
789 | 0 | sal_Int16 nClassId = FormComponentType::CONTROL; |
790 | 0 | m_xElement->getPropertyValue(PROPERTY_CLASSID) >>= nClassId; |
791 | | |
792 | | // translate the value properties we collected in handleAttributes |
793 | 0 | for ( auto& rValueProps : m_aValueProperties ) |
794 | 0 | { |
795 | 0 | bool bSuccess = false; |
796 | 0 | switch (rValueProps.Handle) |
797 | 0 | { |
798 | 0 | case PROPID_VALUE: |
799 | 0 | case PROPID_CURRENT_VALUE: |
800 | 0 | { |
801 | | // get the property names |
802 | 0 | if (!bRetrievedValues) |
803 | 0 | { |
804 | 0 | getValuePropertyNames(m_eElementType, nClassId, pCurrentValueProperty, pValueProperty); |
805 | 0 | if ( pCurrentValueProperty.isEmpty() && pValueProperty.isEmpty() ) |
806 | 0 | { |
807 | 0 | SAL_WARN( "xmloff.forms", "OControlImport::StartElement: illegal value property names!" ); |
808 | 0 | break; |
809 | 0 | } |
810 | | |
811 | 0 | bRetrievedValues = true; |
812 | 0 | } |
813 | 0 | if ( PROPID_VALUE == rValueProps.Handle && pValueProperty.isEmpty() ) |
814 | 0 | { |
815 | 0 | SAL_WARN( "xmloff.forms", "OControlImport::StartElement: the control does not have a value property!"); |
816 | 0 | break; |
817 | 0 | } |
818 | | |
819 | 0 | if ( PROPID_CURRENT_VALUE == rValueProps.Handle && pCurrentValueProperty.isEmpty() ) |
820 | 0 | { |
821 | 0 | SAL_WARN( "xmloff.forms", "OControlImport::StartElement: the control does not have a current-value property!"); |
822 | 0 | break; |
823 | 0 | } |
824 | | |
825 | | // transfer the name |
826 | 0 | if (PROPID_VALUE == rValueProps.Handle) |
827 | 0 | rValueProps.Name = pValueProperty; |
828 | 0 | else |
829 | 0 | rValueProps.Name = pCurrentValueProperty; |
830 | 0 | bSuccess = true; |
831 | 0 | } |
832 | 0 | break; |
833 | 0 | case PROPID_MIN_VALUE: |
834 | 0 | case PROPID_MAX_VALUE: |
835 | 0 | { |
836 | | // get the property names |
837 | 0 | if (!bRetrievedValueLimits) |
838 | 0 | { |
839 | 0 | getValueLimitPropertyNames(nClassId, pMinValueProperty, pMaxValueProperty); |
840 | 0 | if ( pMinValueProperty.isEmpty() || pMaxValueProperty.isEmpty() ) |
841 | 0 | { |
842 | 0 | SAL_WARN( "xmloff.forms", "OControlImport::StartElement: illegal value limit property names!" ); |
843 | 0 | break; |
844 | 0 | } |
845 | | |
846 | 0 | bRetrievedValueLimits = true; |
847 | 0 | } |
848 | 0 | OSL_ENSURE((PROPID_MIN_VALUE != rValueProps.Handle) || !pMinValueProperty.isEmpty(), |
849 | 0 | "OControlImport::StartElement: the control does not have a value property!"); |
850 | 0 | OSL_ENSURE((PROPID_MAX_VALUE != rValueProps.Handle) || !pMaxValueProperty.isEmpty(), |
851 | 0 | "OControlImport::StartElement: the control does not have a current-value property!"); |
852 | | |
853 | | // transfer the name |
854 | 0 | if (PROPID_MIN_VALUE == rValueProps.Handle) |
855 | 0 | rValueProps.Name = pMinValueProperty; |
856 | 0 | else |
857 | 0 | rValueProps.Name = pMaxValueProperty; |
858 | 0 | bSuccess = true; |
859 | 0 | } |
860 | 0 | break; |
861 | 0 | } |
862 | | |
863 | 0 | if ( !bSuccess ) |
864 | 0 | continue; |
865 | | |
866 | | // translate the value |
867 | 0 | implTranslateValueProperty(m_xInfo, rValueProps); |
868 | | // add the property to the base class' array |
869 | 0 | implPushBackPropertyValue(rValueProps); |
870 | 0 | } |
871 | |
|
872 | 0 | } |
873 | | |
874 | | void OControlImport::implTranslateValueProperty(const Reference< XPropertySetInfo >& _rxPropInfo, |
875 | | PropertyValue& _rPropValue) |
876 | 0 | { |
877 | 0 | OSL_ENSURE(_rxPropInfo->hasPropertyByName(_rPropValue.Name), |
878 | 0 | "OControlImport::implTranslateValueProperty: invalid property name!"); |
879 | | |
880 | | // retrieve the type of the property |
881 | 0 | Property aProp = _rxPropInfo->getPropertyByName(_rPropValue.Name); |
882 | | // the untranslated string value as read in handleAttribute |
883 | 0 | OUString sValue; |
884 | 0 | bool bSuccess = _rPropValue.Value >>= sValue; |
885 | 0 | OSL_ENSURE(bSuccess, "OControlImport::implTranslateValueProperty: supposed to be called with non-translated string values!"); |
886 | |
|
887 | 0 | if (TypeClass_ANY == aProp.Type.getTypeClass()) |
888 | 0 | { |
889 | | // we have exactly 2 properties where this type class is allowed: |
890 | 0 | SAL_WARN_IF( |
891 | 0 | _rPropValue.Name != PROPERTY_EFFECTIVE_VALUE |
892 | 0 | && _rPropValue.Name != PROPERTY_EFFECTIVE_DEFAULT, "xmloff", |
893 | 0 | "OControlImport::implTranslateValueProperty: invalid property type/name combination, Any and " << _rPropValue.Name); |
894 | | |
895 | | // Both properties are allowed to have a double or a string value, |
896 | | // so first try to convert the string into a number |
897 | 0 | double nValue; |
898 | 0 | if (::sax::Converter::convertDouble(nValue, sValue)) |
899 | 0 | _rPropValue.Value <<= nValue; |
900 | 0 | else |
901 | 0 | _rPropValue.Value <<= sValue; |
902 | 0 | } |
903 | 0 | else |
904 | 0 | _rPropValue.Value = PropertyConversion::convertString(aProp.Type, sValue); |
905 | 0 | } |
906 | | |
907 | | void OControlImport::endFastElement(sal_Int32 nElement) |
908 | 0 | { |
909 | 0 | OSL_ENSURE(m_xElement.is(), "OControlImport::EndElement: invalid control!"); |
910 | 0 | if ( !m_xElement.is() ) |
911 | 0 | return; |
912 | | |
913 | | // register our control with its id |
914 | 0 | if (!m_sControlId.isEmpty()) |
915 | 0 | m_rFormImport.registerControlId(m_xElement, m_sControlId); |
916 | | // it's allowed to have no control id. In this case we're importing a column |
917 | | |
918 | | // one more pre-work to do: |
919 | | // when we set default values, then by definition the respective value is set |
920 | | // to this default value, too. This means if the sequence contains for example |
921 | | // a DefaultText value, then the Text will be affected by this, too. |
922 | | // In case the Text is not part of the property sequence (or occurs _before_ |
923 | | // the DefaultText, which can happen for other value/default-value property names), |
924 | | // this means that the Text (the value property) is incorrectly imported. |
925 | |
|
926 | 0 | bool bRestoreValuePropertyValue = false; |
927 | 0 | Any aValuePropertyValue; |
928 | |
|
929 | 0 | sal_Int16 nClassId = FormComponentType::CONTROL; |
930 | 0 | try |
931 | 0 | { |
932 | | // get the class id of our element |
933 | 0 | m_xElement->getPropertyValue(PROPERTY_CLASSID) >>= nClassId; |
934 | 0 | } |
935 | 0 | catch( const Exception& ) |
936 | 0 | { |
937 | 0 | TOOLS_WARN_EXCEPTION("xmloff.forms", |
938 | 0 | "caught an exception while retrieving the class id!"); |
939 | 0 | } |
940 | | |
941 | 0 | OUString pValueProperty; |
942 | 0 | OUString pDefaultValueProperty; |
943 | 0 | getRuntimeValuePropertyNames(m_eElementType, nClassId, pValueProperty, pDefaultValueProperty); |
944 | 0 | if ( !pDefaultValueProperty.isEmpty() && !pValueProperty.isEmpty() ) |
945 | 0 | { |
946 | 0 | bool bNonDefaultValuePropertyValue = false; |
947 | | // is the "value property" part of the sequence? |
948 | | |
949 | | // look up this property in our sequence |
950 | 0 | for ( const auto& rCheck : m_aValues ) |
951 | 0 | { |
952 | 0 | if ( rCheck.Name == pDefaultValueProperty ) |
953 | 0 | bRestoreValuePropertyValue = true; |
954 | 0 | else if ( rCheck.Name == pValueProperty ) |
955 | 0 | { |
956 | 0 | bNonDefaultValuePropertyValue = true; |
957 | | // we need to restore the value property we found here, nothing else |
958 | 0 | aValuePropertyValue = rCheck.Value; |
959 | 0 | } |
960 | 0 | } |
961 | |
|
962 | 0 | if ( bRestoreValuePropertyValue && !bNonDefaultValuePropertyValue ) |
963 | 0 | { |
964 | | // found it -> need to remember (and restore) the "value property value", which is not set explicitly |
965 | 0 | try |
966 | 0 | { |
967 | 0 | aValuePropertyValue = m_xElement->getPropertyValue( pValueProperty ); |
968 | 0 | } |
969 | 0 | catch( const Exception& ) |
970 | 0 | { |
971 | 0 | TOOLS_WARN_EXCEPTION( |
972 | 0 | "xmloff.forms", |
973 | 0 | "caught an exception while retrieving the current value property!"); |
974 | 0 | } |
975 | 0 | } |
976 | 0 | } |
977 | | |
978 | | // let the base class set all the values |
979 | 0 | OElementImport::endFastElement(nElement); |
980 | | |
981 | | // restore the "value property value", if necessary |
982 | 0 | if ( bRestoreValuePropertyValue && !pValueProperty.isEmpty() ) |
983 | 0 | { |
984 | 0 | try |
985 | 0 | { |
986 | 0 | m_xElement->setPropertyValue( pValueProperty, aValuePropertyValue ); |
987 | 0 | } |
988 | 0 | catch( const Exception& ) |
989 | 0 | { |
990 | 0 | TOOLS_WARN_EXCEPTION("xmloff.forms", |
991 | 0 | "caught an exception while restoring the value property!"); |
992 | 0 | } |
993 | 0 | } |
994 | | |
995 | | // the external cell binding, if applicable |
996 | 0 | if ( m_xElement.is() && !m_sBoundCellAddress.isEmpty() ) |
997 | 0 | doRegisterCellValueBinding( m_sBoundCellAddress ); |
998 | | |
999 | | // XForms binding, if applicable |
1000 | 0 | if ( m_xElement.is() && !m_sBindingID.isEmpty() ) |
1001 | 0 | doRegisterXFormsValueBinding( m_sBindingID ); |
1002 | | |
1003 | | // XForms list binding, if applicable |
1004 | 0 | if ( m_xElement.is() && !m_sListBindingID.isEmpty() ) |
1005 | 0 | doRegisterXFormsListBinding( m_sListBindingID ); |
1006 | | |
1007 | | // XForms submission, if applicable |
1008 | 0 | if ( m_xElement.is() && !m_sSubmissionID.isEmpty() ) |
1009 | 0 | doRegisterXFormsSubmission( m_sSubmissionID ); |
1010 | 0 | } |
1011 | | |
1012 | | void OControlImport::doRegisterCellValueBinding( const OUString& _rBoundCellAddress ) |
1013 | 0 | { |
1014 | 0 | OSL_PRECOND( m_xElement.is(), "OControlImport::doRegisterCellValueBinding: invalid element!" ); |
1015 | 0 | OSL_PRECOND( !_rBoundCellAddress.isEmpty(), |
1016 | 0 | "OControlImport::doRegisterCellValueBinding: invalid address!" ); |
1017 | |
|
1018 | 0 | m_rContext.registerCellValueBinding( m_xElement, _rBoundCellAddress ); |
1019 | 0 | } |
1020 | | |
1021 | | void OControlImport::doRegisterXFormsValueBinding( const OUString& _rBindingID ) |
1022 | 0 | { |
1023 | 0 | OSL_PRECOND( m_xElement.is(), "need element" ); |
1024 | 0 | OSL_PRECOND( !_rBindingID.isEmpty(), "binding ID is not valid" ); |
1025 | |
|
1026 | 0 | m_rContext.registerXFormsValueBinding( m_xElement, _rBindingID ); |
1027 | 0 | } |
1028 | | |
1029 | | void OControlImport::doRegisterXFormsListBinding( const OUString& _rBindingID ) |
1030 | 0 | { |
1031 | 0 | OSL_PRECOND( m_xElement.is(), "need element" ); |
1032 | 0 | OSL_PRECOND( !_rBindingID.isEmpty(), "binding ID is not valid" ); |
1033 | |
|
1034 | 0 | m_rContext.registerXFormsListBinding( m_xElement, _rBindingID ); |
1035 | 0 | } |
1036 | | |
1037 | | void OControlImport::doRegisterXFormsSubmission( const OUString& _rSubmissionID ) |
1038 | 0 | { |
1039 | 0 | OSL_PRECOND( m_xElement.is(), "need element" ); |
1040 | 0 | OSL_PRECOND( !_rSubmissionID.isEmpty(), "binding ID is not valid" ); |
1041 | |
|
1042 | 0 | m_rContext.registerXFormsSubmission( m_xElement, _rSubmissionID ); |
1043 | 0 | } |
1044 | | |
1045 | | Reference< XPropertySet > OControlImport::createElement() |
1046 | 0 | { |
1047 | 0 | const Reference<XPropertySet> xPropSet = OElementImport::createElement(); |
1048 | 0 | if ( xPropSet.is() ) |
1049 | 0 | { |
1050 | 0 | m_xInfo = xPropSet->getPropertySetInfo(); |
1051 | 0 | if ( m_xInfo.is() && m_xInfo->hasPropertyByName(PROPERTY_ALIGN) ) |
1052 | 0 | { |
1053 | 0 | Any aValue; |
1054 | 0 | xPropSet->setPropertyValue(PROPERTY_ALIGN,aValue); |
1055 | 0 | } |
1056 | 0 | } |
1057 | 0 | return xPropSet; |
1058 | 0 | } |
1059 | | |
1060 | | //= OImagePositionImport |
1061 | | OImagePositionImport::OImagePositionImport( OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1062 | | const Reference< XNameContainer >& _rxParentContainer, |
1063 | | OControlElement::ElementType _eType ) |
1064 | 0 | :OControlImport( _rImport, _rEventManager, _rxParentContainer, _eType ) |
1065 | 0 | ,m_nImagePosition( -1 ) |
1066 | 0 | ,m_nImageAlign( 0 ) |
1067 | 0 | ,m_bHaveImagePosition( false ) |
1068 | 0 | { |
1069 | 0 | } |
1070 | | |
1071 | | bool OImagePositionImport::handleAttribute( sal_Int32 nElement, |
1072 | | const OUString& _rValue ) |
1073 | 0 | { |
1074 | 0 | static const sal_Int32 s_nImageDataAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::ImageData); |
1075 | |
|
1076 | 0 | if ( (nElement & TOKEN_MASK) == s_nImageDataAttributeName) |
1077 | 0 | { |
1078 | 0 | m_xGraphic = m_rContext.getGlobalContext().loadGraphicByURL(_rValue); |
1079 | 0 | return true; |
1080 | 0 | } |
1081 | 0 | else if ( (nElement & TOKEN_MASK) == XML_IMAGE_POSITION ) |
1082 | 0 | { |
1083 | 0 | OSL_VERIFY( PropertyConversion::convertString( |
1084 | 0 | cppu::UnoType<decltype(m_nImagePosition)>::get(), |
1085 | 0 | _rValue, aImagePositionMap |
1086 | 0 | ) >>= m_nImagePosition ); |
1087 | 0 | m_bHaveImagePosition = true; |
1088 | 0 | return true; |
1089 | 0 | } |
1090 | 0 | else if ( (nElement & TOKEN_MASK) == XML_IMAGE_ALIGN ) |
1091 | 0 | { |
1092 | 0 | OSL_VERIFY( PropertyConversion::convertString( |
1093 | 0 | cppu::UnoType<decltype(m_nImageAlign)>::get(), |
1094 | 0 | _rValue, aImageAlignMap |
1095 | 0 | ) >>= m_nImageAlign ); |
1096 | 0 | return true; |
1097 | 0 | } |
1098 | | |
1099 | 0 | return OControlImport::handleAttribute( nElement, _rValue ); |
1100 | 0 | } |
1101 | | |
1102 | | void OImagePositionImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) |
1103 | 0 | { |
1104 | 0 | OControlImport::startFastElement( nElement, _rxAttrList ); |
1105 | |
|
1106 | 0 | if (m_xGraphic.is()) |
1107 | 0 | { |
1108 | 0 | PropertyValue aGraphicProperty; |
1109 | 0 | aGraphicProperty.Name = PROPERTY_GRAPHIC; |
1110 | 0 | aGraphicProperty.Value <<= m_xGraphic; |
1111 | 0 | implPushBackPropertyValue(aGraphicProperty); |
1112 | 0 | } |
1113 | 0 | if ( !m_bHaveImagePosition ) |
1114 | 0 | return; |
1115 | | |
1116 | 0 | sal_Int16 nUnoImagePosition = ImagePosition::Centered; |
1117 | 0 | if ( m_nImagePosition >= 0 ) |
1118 | 0 | { |
1119 | 0 | OSL_ENSURE( ( m_nImagePosition <= 3 ) && ( m_nImageAlign >= 0 ) && ( m_nImageAlign < 3 ), |
1120 | 0 | "OImagePositionImport::StartElement: unknown image align and/or position!" ); |
1121 | 0 | nUnoImagePosition = m_nImagePosition * 3 + m_nImageAlign; |
1122 | 0 | } |
1123 | |
|
1124 | 0 | PropertyValue aImagePosition; |
1125 | 0 | aImagePosition.Name = PROPERTY_IMAGE_POSITION; |
1126 | 0 | aImagePosition.Value <<= nUnoImagePosition; |
1127 | 0 | implPushBackPropertyValue( aImagePosition ); |
1128 | 0 | } |
1129 | | |
1130 | | //= OReferredControlImport |
1131 | | OReferredControlImport::OReferredControlImport( |
1132 | | OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1133 | | const Reference< XNameContainer >& _rxParentContainer ) |
1134 | 0 | :OControlImport(_rImport, _rEventManager, _rxParentContainer) |
1135 | 0 | { |
1136 | 0 | } |
1137 | | |
1138 | | void OReferredControlImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) |
1139 | 0 | { |
1140 | 0 | OControlImport::startFastElement(nElement, _rxAttrList); |
1141 | | |
1142 | | // the base class should have created the control, so we can register it |
1143 | 0 | if ( !m_sReferringControls.isEmpty() ) |
1144 | 0 | m_rFormImport.registerControlReferences(m_xElement, m_sReferringControls); |
1145 | 0 | } |
1146 | | |
1147 | | bool OReferredControlImport::handleAttribute(sal_Int32 nElement, |
1148 | | const OUString& _rValue) |
1149 | 0 | { |
1150 | 0 | static const sal_Int32 s_nReferenceAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::For); |
1151 | 0 | if ((nElement & TOKEN_MASK) == s_nReferenceAttributeName) |
1152 | 0 | { |
1153 | 0 | m_sReferringControls = _rValue; |
1154 | 0 | return true; |
1155 | 0 | } |
1156 | 0 | return OControlImport::handleAttribute(nElement, _rValue); |
1157 | 0 | } |
1158 | | |
1159 | | //= OPasswordImport |
1160 | | OPasswordImport::OPasswordImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1161 | | const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType) |
1162 | 0 | :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType) |
1163 | 0 | { |
1164 | 0 | } |
1165 | | |
1166 | | bool OPasswordImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) |
1167 | 0 | { |
1168 | 0 | static const sal_Int32 s_nEchoCharAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::EchoChar); |
1169 | 0 | if ((nElement & TOKEN_MASK) == s_nEchoCharAttributeName) |
1170 | 0 | { |
1171 | | // need a special handling for the EchoChar property |
1172 | 0 | PropertyValue aEchoChar; |
1173 | 0 | aEchoChar.Name = PROPERTY_ECHOCHAR; |
1174 | 0 | OSL_ENSURE(_rValue.getLength() == 1, "OPasswordImport::handleAttribute: invalid echo char attribute!"); |
1175 | | // we ourself should not have written values other than of length 1 |
1176 | 0 | if (_rValue.getLength() >= 1) |
1177 | 0 | aEchoChar.Value <<= static_cast<sal_Int16>(_rValue[0]); |
1178 | 0 | else |
1179 | 0 | aEchoChar.Value <<= sal_Int16(0); |
1180 | 0 | implPushBackPropertyValue(aEchoChar); |
1181 | 0 | return true; |
1182 | 0 | } |
1183 | 0 | return OControlImport::handleAttribute(nElement, _rValue); |
1184 | 0 | } |
1185 | | |
1186 | | //= ORadioImport |
1187 | | ORadioImport::ORadioImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1188 | | const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType) |
1189 | 0 | :OImagePositionImport( _rImport, _rEventManager, _rxParentContainer, _eType ) |
1190 | 0 | { |
1191 | 0 | } |
1192 | | |
1193 | | bool ORadioImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) |
1194 | 0 | { |
1195 | | // need special handling for the State & CurrentState properties: |
1196 | | // they're stored as booleans, but expected to be int16 properties |
1197 | 0 | static const sal_Int32 nCurrentSelectedAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentSelected); |
1198 | 0 | static const sal_Int32 nSelectedAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Selected); |
1199 | 0 | if ( (nElement & TOKEN_MASK) == nCurrentSelectedAttributeName |
1200 | 0 | || (nElement & TOKEN_MASK) == nSelectedAttributeName |
1201 | 0 | ) |
1202 | 0 | { |
1203 | 0 | const OAttribute2Property::AttributeAssignment* pProperty = m_rContext.getAttributeMap().getAttributeTranslation(nElement & TOKEN_MASK); |
1204 | 0 | assert(pProperty && "ORadioImport::handleAttribute: invalid property map!"); |
1205 | 0 | if (pProperty) |
1206 | 0 | { |
1207 | 0 | const Any aBooleanValue( PropertyConversion::convertString(pProperty->aPropertyType, _rValue, pProperty->pEnumMap) ); |
1208 | | |
1209 | | // create and store a new PropertyValue |
1210 | 0 | PropertyValue aNewValue; |
1211 | 0 | aNewValue.Name = pProperty->sPropertyName; |
1212 | 0 | aNewValue.Value <<= static_cast<sal_Int16>(::cppu::any2bool(aBooleanValue)); |
1213 | |
|
1214 | 0 | implPushBackPropertyValue(aNewValue); |
1215 | 0 | } |
1216 | 0 | return true; |
1217 | 0 | } |
1218 | 0 | return OImagePositionImport::handleAttribute( nElement, _rValue ); |
1219 | 0 | } |
1220 | | |
1221 | | //= OURLReferenceImport |
1222 | | OURLReferenceImport::OURLReferenceImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1223 | | const Reference< XNameContainer >& _rxParentContainer, |
1224 | | OControlElement::ElementType _eType) |
1225 | 0 | :OImagePositionImport(_rImport, _rEventManager, _rxParentContainer, _eType) |
1226 | 0 | { |
1227 | 0 | } |
1228 | | |
1229 | | bool OURLReferenceImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) |
1230 | 0 | { |
1231 | 0 | static const sal_Int32 s_nTargetLocationAttributeName = OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::TargetLocation ); |
1232 | 0 | static const sal_Int32 s_nImageDataAttributeName = OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::ImageData ); |
1233 | | |
1234 | | // need to make the URL absolute if |
1235 | | // * it's the image-data attribute |
1236 | | // * it's the target-location attribute, and we're dealing with an object which has the respective property |
1237 | 0 | bool bMakeAbsolute = |
1238 | 0 | (nElement & TOKEN_MASK) == s_nImageDataAttributeName |
1239 | 0 | || ( (nElement & TOKEN_MASK) == s_nTargetLocationAttributeName |
1240 | 0 | && ( ( OControlElement::BUTTON == m_eElementType ) |
1241 | 0 | || ( OControlElement::IMAGE == m_eElementType ) |
1242 | 0 | ) |
1243 | 0 | ); |
1244 | |
|
1245 | 0 | if (bMakeAbsolute && !_rValue.isEmpty()) |
1246 | 0 | { |
1247 | 0 | OUString sAdjustedValue = _rValue; |
1248 | 0 | if ((nElement & TOKEN_MASK) != s_nImageDataAttributeName) |
1249 | 0 | sAdjustedValue = m_rContext.getGlobalContext().GetAbsoluteReference( _rValue ); |
1250 | 0 | return OImagePositionImport::handleAttribute( nElement, sAdjustedValue ); |
1251 | 0 | } |
1252 | | |
1253 | 0 | return OImagePositionImport::handleAttribute( nElement, _rValue ); |
1254 | 0 | } |
1255 | | |
1256 | | //= OButtonImport |
1257 | | OButtonImport::OButtonImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1258 | | const Reference< XNameContainer >& _rxParentContainer, |
1259 | | OControlElement::ElementType _eType) |
1260 | 0 | :OURLReferenceImport(_rImport, _rEventManager, _rxParentContainer, _eType) |
1261 | 0 | { |
1262 | 0 | enableTrackAttributes(); |
1263 | 0 | } |
1264 | | |
1265 | | void OButtonImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) |
1266 | 0 | { |
1267 | 0 | OURLReferenceImport::startFastElement(nElement, _rxAttrList); |
1268 | | |
1269 | | // handle the target-frame attribute |
1270 | 0 | simulateDefaultedAttribute(OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetFrame), PROPERTY_TARGETFRAME, u"_blank"_ustr); |
1271 | 0 | } |
1272 | | |
1273 | | //= OValueRangeImport |
1274 | | OValueRangeImport::OValueRangeImport( OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1275 | | const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType ) |
1276 | 0 | :OControlImport( _rImport, _rEventManager, _rxParentContainer, _eType ) |
1277 | 0 | ,m_nStepSizeValue( 1 ) |
1278 | 0 | { |
1279 | |
|
1280 | 0 | } |
1281 | | |
1282 | | bool OValueRangeImport::handleAttribute( sal_Int32 nElement, const OUString& _rValue ) |
1283 | 0 | { |
1284 | 0 | if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getSpecialAttributeToken( SCAFlags::StepSize ) ) |
1285 | 0 | { |
1286 | 0 | ::sax::Converter::convertNumber( m_nStepSizeValue, _rValue ); |
1287 | 0 | return true; |
1288 | 0 | } |
1289 | 0 | return OControlImport::handleAttribute( nElement, _rValue ); |
1290 | 0 | } |
1291 | | |
1292 | | void OValueRangeImport::startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList ) |
1293 | 0 | { |
1294 | 0 | OControlImport::startFastElement( nElement, _rxAttrList ); |
1295 | |
|
1296 | 0 | if ( m_xInfo.is() ) |
1297 | 0 | { |
1298 | 0 | if ( m_xInfo->hasPropertyByName( PROPERTY_SPIN_INCREMENT ) ) |
1299 | 0 | m_xElement->setPropertyValue( PROPERTY_SPIN_INCREMENT, Any( m_nStepSizeValue ) ); |
1300 | 0 | else if ( m_xInfo->hasPropertyByName( PROPERTY_LINE_INCREMENT ) ) |
1301 | 0 | m_xElement->setPropertyValue( PROPERTY_LINE_INCREMENT, Any( m_nStepSizeValue ) ); |
1302 | 0 | } |
1303 | 0 | } |
1304 | | |
1305 | | //= OTextLikeImport |
1306 | | OTextLikeImport::OTextLikeImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1307 | | const Reference< XNameContainer >& _rxParentContainer, |
1308 | | OControlElement::ElementType _eType) |
1309 | 0 | :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType) |
1310 | 0 | ,m_bEncounteredTextPara( false ) |
1311 | 0 | { |
1312 | 0 | enableTrackAttributes(); |
1313 | 0 | } |
1314 | | |
1315 | | css::uno::Reference< css::xml::sax::XFastContextHandler > OTextLikeImport::createFastChildContext( |
1316 | | sal_Int32 nElement, |
1317 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) |
1318 | 0 | { |
1319 | 0 | if ( nElement == XML_ELEMENT(TEXT, XML_P) ) |
1320 | 0 | { |
1321 | 0 | OSL_ENSURE( m_eElementType == OControlElement::TEXT_AREA, |
1322 | 0 | "OTextLikeImport::CreateChildContext: text paragraphs in a non-text-area?" ); |
1323 | |
|
1324 | 0 | if ( m_eElementType == OControlElement::TEXT_AREA ) |
1325 | 0 | { |
1326 | 0 | Reference< XText > xTextElement( m_xElement, UNO_QUERY ); |
1327 | 0 | if ( xTextElement.is() ) |
1328 | 0 | { |
1329 | 0 | rtl::Reference < XMLTextImportHelper > xTextImportHelper( m_rContext.getGlobalContext().GetTextImport() ); |
1330 | |
|
1331 | 0 | if ( !m_xCursor.is() ) |
1332 | 0 | { |
1333 | 0 | m_xOldCursor = xTextImportHelper->GetCursor(); |
1334 | 0 | m_xCursor = xTextElement->createTextCursor(); |
1335 | |
|
1336 | 0 | if ( m_xCursor.is() ) |
1337 | 0 | xTextImportHelper->SetCursor( m_xCursor ); |
1338 | 0 | } |
1339 | 0 | if ( m_xCursor.is() ) |
1340 | 0 | { |
1341 | 0 | m_bEncounteredTextPara = true; |
1342 | 0 | return xTextImportHelper->CreateTextChildContext( m_rContext.getGlobalContext(), nElement, xAttrList ); |
1343 | 0 | } |
1344 | 0 | } |
1345 | 0 | else |
1346 | 0 | { |
1347 | | // in theory, we could accumulate all the text portions (without formatting), |
1348 | | // and set it as Text property at the model ... |
1349 | 0 | } |
1350 | 0 | } |
1351 | 0 | } |
1352 | | |
1353 | 0 | return OControlImport::createFastChildContext( nElement, xAttrList ); |
1354 | 0 | } |
1355 | | |
1356 | | void OTextLikeImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) |
1357 | 0 | { |
1358 | 0 | OControlImport::startFastElement(nElement, _rxAttrList); |
1359 | | |
1360 | | // handle the convert-empty-to-null attribute, whose default is different from the property default |
1361 | | // unfortunately, different classes are imported by this class ('cause they're represented by the |
1362 | | // same XML element), though not all of them know this property. |
1363 | | // So we have to do a check ... |
1364 | 0 | if (m_xElement.is() && m_xInfo.is() && m_xInfo->hasPropertyByName(PROPERTY_EMPTY_IS_NULL) ) |
1365 | 0 | simulateDefaultedAttribute(OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ConvertEmpty), PROPERTY_EMPTY_IS_NULL, u"false"_ustr); |
1366 | 0 | } |
1367 | | |
1368 | | namespace { |
1369 | | |
1370 | | struct EqualHandle |
1371 | | { |
1372 | | const sal_Int32 m_nHandle; |
1373 | 0 | explicit EqualHandle( sal_Int32 _nHandle ) : m_nHandle( _nHandle ) { } |
1374 | | |
1375 | | bool operator()( const PropertyValue& _rProp ) |
1376 | 0 | { |
1377 | 0 | return _rProp.Handle == m_nHandle; |
1378 | 0 | } |
1379 | | }; |
1380 | | |
1381 | | } |
1382 | | |
1383 | | void OTextLikeImport::removeRedundantCurrentValue() |
1384 | 0 | { |
1385 | 0 | if ( !m_bEncounteredTextPara ) |
1386 | 0 | return; |
1387 | | |
1388 | | // In case the text is written in the text:p elements, we need to ignore what we read as |
1389 | | // current-value attribute, since it's redundant. |
1390 | | // fortunately, OElementImport tagged the value property with the PROPID_CURRENT_VALUE |
1391 | | // handle, so we do not need to determine the name of our value property here |
1392 | | // (normally, it should be "Text", since no other controls than the edit field should |
1393 | | // have the text:p elements) |
1394 | 0 | PropertyValueArray::iterator aValuePropertyPos = ::std::find_if( |
1395 | 0 | m_aValues.begin(), |
1396 | 0 | m_aValues.end(), |
1397 | 0 | EqualHandle( PROPID_CURRENT_VALUE ) |
1398 | 0 | ); |
1399 | 0 | if ( aValuePropertyPos != m_aValues.end() ) |
1400 | 0 | { |
1401 | 0 | OSL_ENSURE( aValuePropertyPos->Name == PROPERTY_TEXT, "OTextLikeImport::EndElement: text:p was present, but our value property is *not* 'Text'!" ); |
1402 | 0 | if ( aValuePropertyPos->Name == PROPERTY_TEXT ) |
1403 | 0 | { |
1404 | 0 | m_aValues.erase(aValuePropertyPos); |
1405 | 0 | } |
1406 | 0 | } |
1407 | | |
1408 | | // additionally, we need to set the "RichText" property of our element to sal_True |
1409 | | // (the presence of the text:p is used as indicator for the value of the RichText property) |
1410 | 0 | bool bHasRichTextProperty = false; |
1411 | 0 | if ( m_xInfo.is() ) |
1412 | 0 | bHasRichTextProperty = m_xInfo->hasPropertyByName( PROPERTY_RICH_TEXT ); |
1413 | 0 | OSL_ENSURE( bHasRichTextProperty, "OTextLikeImport::EndElement: text:p, but no rich text control?" ); |
1414 | 0 | if ( bHasRichTextProperty ) |
1415 | 0 | m_xElement->setPropertyValue( PROPERTY_RICH_TEXT, Any( true ) ); |
1416 | | // Note that we do *not* set the RichText property (in case our element has one) to sal_False here |
1417 | | // since this is the default of this property, anyway. |
1418 | 0 | } |
1419 | | |
1420 | | namespace { |
1421 | | |
1422 | | struct EqualName |
1423 | | { |
1424 | | const OUString & m_sName; |
1425 | 0 | explicit EqualName( const OUString& _rName ) : m_sName( _rName ) { } |
1426 | | |
1427 | | bool operator()( const PropertyValue& _rProp ) |
1428 | 0 | { |
1429 | 0 | return _rProp.Name == m_sName; |
1430 | 0 | } |
1431 | | }; |
1432 | | |
1433 | | } |
1434 | | |
1435 | | void OTextLikeImport::adjustDefaultControlProperty() |
1436 | 0 | { |
1437 | | // In OpenOffice.org 2.0, we changed the implementation of the css.form.component.TextField (the model of a text field control), |
1438 | | // so that it now uses another default control. So if we encounter a text field where the *old* default |
1439 | | // control property is writing, we are not allowed to use it |
1440 | 0 | PropertyValueArray::iterator aDefaultControlPropertyPos = ::std::find_if( |
1441 | 0 | m_aValues.begin(), |
1442 | 0 | m_aValues.end(), |
1443 | 0 | EqualName( u"DefaultControl"_ustr ) |
1444 | 0 | ); |
1445 | 0 | if ( aDefaultControlPropertyPos != m_aValues.end() ) |
1446 | 0 | { |
1447 | 0 | OUString sDefaultControl; |
1448 | 0 | OSL_VERIFY( aDefaultControlPropertyPos->Value >>= sDefaultControl ); |
1449 | 0 | if ( sDefaultControl == "stardiv.one.form.control.Edit" ) |
1450 | 0 | { |
1451 | | // complete remove this property value from the array. Today's "default value" of the "DefaultControl" |
1452 | | // property is sufficient |
1453 | 0 | m_aValues.erase(aDefaultControlPropertyPos); |
1454 | 0 | } |
1455 | 0 | } |
1456 | 0 | } |
1457 | | |
1458 | | void OTextLikeImport::endFastElement(sal_Int32 nElement) |
1459 | 0 | { |
1460 | 0 | removeRedundantCurrentValue(); |
1461 | 0 | adjustDefaultControlProperty(); |
1462 | | |
1463 | | // let the base class do the stuff |
1464 | 0 | OControlImport::endFastElement(nElement); |
1465 | | |
1466 | | // some cleanups |
1467 | 0 | rtl::Reference < XMLTextImportHelper > xTextImportHelper( m_rContext.getGlobalContext().GetTextImport() ); |
1468 | 0 | if ( m_xCursor.is() ) |
1469 | 0 | { |
1470 | | // delete the newline which has been imported erroneously |
1471 | | // TODO (fs): stole this code somewhere - why don't we fix the text import?? |
1472 | 0 | m_xCursor->gotoEnd( false ); |
1473 | 0 | m_xCursor->goLeft( 1, true ); |
1474 | 0 | m_xCursor->setString( OUString() ); |
1475 | | |
1476 | | // reset cursor |
1477 | 0 | xTextImportHelper->ResetCursor(); |
1478 | 0 | } |
1479 | |
|
1480 | 0 | if ( m_xOldCursor.is() ) |
1481 | 0 | xTextImportHelper->SetCursor( m_xOldCursor ); |
1482 | |
|
1483 | 0 | } |
1484 | | |
1485 | | //= OListAndComboImport |
1486 | | OListAndComboImport::OListAndComboImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1487 | | const Reference< XNameContainer >& _rxParentContainer, |
1488 | | OControlElement::ElementType _eType) |
1489 | 0 | :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType) |
1490 | 0 | ,m_nEmptyListItems( 0 ) |
1491 | 0 | ,m_nEmptyValueItems( 0 ) |
1492 | 0 | ,m_bEncounteredLSAttrib( false ) |
1493 | 0 | ,m_bLinkWithIndexes( false ) |
1494 | 0 | { |
1495 | 0 | if (OControlElement::COMBOBOX == m_eElementType) |
1496 | 0 | enableTrackAttributes(); |
1497 | 0 | } |
1498 | | |
1499 | | css::uno::Reference< css::xml::sax::XFastContextHandler > OListAndComboImport::createFastChildContext( |
1500 | | sal_Int32 nElement, |
1501 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList ) |
1502 | 0 | { |
1503 | | // is it the "option" sub tag of a listbox ? |
1504 | 0 | if ((nElement & TOKEN_MASK) == XML_OPTION) |
1505 | 0 | return new OListOptionImport(GetImport(), this); |
1506 | | |
1507 | | // is it the "item" sub tag of a combobox ? |
1508 | 0 | if ((nElement & TOKEN_MASK) == XML_ITEM) |
1509 | 0 | return new OComboItemImport(GetImport(), this); |
1510 | | |
1511 | | // everything else |
1512 | 0 | return OControlImport::createFastChildContext(nElement, _rxAttrList); |
1513 | 0 | } |
1514 | | |
1515 | | void OListAndComboImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) |
1516 | 0 | { |
1517 | 0 | m_bLinkWithIndexes = false; |
1518 | |
|
1519 | 0 | OControlImport::startFastElement(nElement, _rxAttrList); |
1520 | |
|
1521 | 0 | if (OControlElement::COMBOBOX == m_eElementType) |
1522 | 0 | { |
1523 | | // for the auto-completion |
1524 | | // the attribute default does not equal the property default, so in case we did not read this attribute, |
1525 | | // we have to simulate it |
1526 | 0 | simulateDefaultedAttribute( OAttributeMetaData::getSpecialAttributeToken( SCAFlags::AutoCompletion ), PROPERTY_AUTOCOMPLETE, u"false"_ustr); |
1527 | | |
1528 | | // same for the convert-empty-to-null attribute, which's default is different from the property default |
1529 | 0 | simulateDefaultedAttribute( OAttributeMetaData::getDatabaseAttributeToken( DAFlags::ConvertEmpty ), PROPERTY_EMPTY_IS_NULL, u"false"_ustr); |
1530 | 0 | } |
1531 | 0 | } |
1532 | | |
1533 | | void OListAndComboImport::endFastElement(sal_Int32 nElement) |
1534 | 0 | { |
1535 | | // append the list source property the properties sequence of our importer |
1536 | | // the string item list |
1537 | 0 | PropertyValue aItemList; |
1538 | 0 | aItemList.Name = PROPERTY_STRING_ITEM_LIST; |
1539 | 0 | aItemList.Value <<= comphelper::containerToSequence(m_aListSource); |
1540 | 0 | implPushBackPropertyValue(aItemList); |
1541 | |
|
1542 | 0 | if (OControlElement::LISTBOX == m_eElementType) |
1543 | 0 | { |
1544 | 0 | OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems), |
1545 | 0 | "OListAndComboImport::EndElement: inconsistence between labels and values!"); |
1546 | |
|
1547 | 0 | if ( !m_bEncounteredLSAttrib ) |
1548 | 0 | { |
1549 | | // the value sequence |
1550 | 0 | PropertyValue aValueList; |
1551 | 0 | aValueList.Name = PROPERTY_LISTSOURCE; |
1552 | 0 | aValueList.Value <<= comphelper::containerToSequence(m_aValueList); |
1553 | 0 | implPushBackPropertyValue(aValueList); |
1554 | 0 | } |
1555 | | |
1556 | | // the select sequence |
1557 | 0 | PropertyValue aSelected; |
1558 | 0 | aSelected.Name = PROPERTY_SELECT_SEQ; |
1559 | 0 | aSelected.Value <<= comphelper::containerToSequence(m_aSelectedSeq); |
1560 | 0 | implPushBackPropertyValue(aSelected); |
1561 | | |
1562 | | // the default select sequence |
1563 | 0 | PropertyValue aDefaultSelected; |
1564 | 0 | aDefaultSelected.Name = PROPERTY_DEFAULT_SELECT_SEQ; |
1565 | 0 | aDefaultSelected.Value <<= comphelper::containerToSequence(m_aDefaultSelectedSeq); |
1566 | 0 | implPushBackPropertyValue(aDefaultSelected); |
1567 | 0 | } |
1568 | |
|
1569 | 0 | OControlImport::endFastElement(nElement); |
1570 | | |
1571 | | // the external list source, if applicable |
1572 | 0 | if ( m_xElement.is() && !m_sCellListSource.isEmpty() ) |
1573 | 0 | m_rContext.registerCellRangeListSource( m_xElement, m_sCellListSource ); |
1574 | 0 | } |
1575 | | |
1576 | | void OListAndComboImport::doRegisterCellValueBinding( const OUString& _rBoundCellAddress ) |
1577 | 0 | { |
1578 | 0 | OUString sBoundCellAddress( _rBoundCellAddress ); |
1579 | 0 | if ( m_bLinkWithIndexes ) |
1580 | 0 | { |
1581 | | // This is a HACK. We register a string which is no valid address, but allows |
1582 | | // (somewhere else) to determine that a non-standard binding should be created. |
1583 | | // This hack is acceptable for OOo 1.1.1, since the file format for value |
1584 | | // bindings of form controls is to be changed afterwards, anyway. |
1585 | 0 | sBoundCellAddress += ":index"; |
1586 | 0 | } |
1587 | |
|
1588 | 0 | OControlImport::doRegisterCellValueBinding( sBoundCellAddress ); |
1589 | 0 | } |
1590 | | |
1591 | | bool OListAndComboImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) |
1592 | 0 | { |
1593 | 0 | static const sal_Int32 nListSourceAttributeName = OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ListSource); |
1594 | 0 | if ( (nElement & TOKEN_MASK) == nListSourceAttributeName ) |
1595 | 0 | { |
1596 | 0 | PropertyValue aListSource; |
1597 | 0 | aListSource.Name = PROPERTY_LISTSOURCE; |
1598 | | |
1599 | | // it's the ListSource attribute |
1600 | 0 | m_bEncounteredLSAttrib = true; |
1601 | 0 | if ( OControlElement::COMBOBOX == m_eElementType ) |
1602 | 0 | { |
1603 | 0 | aListSource.Value <<= _rValue; |
1604 | 0 | } |
1605 | 0 | else |
1606 | 0 | { |
1607 | | // a listbox which has a list-source attribute must have a list-source-type of something |
1608 | | // not equal to ValueList. |
1609 | | // In this case, the list-source value is simply the one and only element of the ListSource property. |
1610 | 0 | Sequence<OUString> aListSourcePropValue { _rValue }; |
1611 | 0 | aListSource.Value <<= aListSourcePropValue; |
1612 | 0 | } |
1613 | |
|
1614 | 0 | implPushBackPropertyValue( aListSource ); |
1615 | 0 | return true; |
1616 | 0 | } |
1617 | | |
1618 | 0 | if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getBindingAttributeToken( BAFlags::ListCellRange ) ) |
1619 | 0 | { |
1620 | 0 | m_sCellListSource = _rValue; |
1621 | 0 | return true; |
1622 | 0 | } |
1623 | | |
1624 | 0 | if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getBindingAttributeToken( BAFlags::ListLinkingType ) ) |
1625 | 0 | { |
1626 | 0 | sal_Int16 nLinkageType = 0; |
1627 | 0 | PropertyConversion::convertString( |
1628 | 0 | ::cppu::UnoType<sal_Int16>::get(), |
1629 | 0 | _rValue, |
1630 | 0 | aListLinkageMap |
1631 | 0 | ) >>= nLinkageType; |
1632 | |
|
1633 | 0 | m_bLinkWithIndexes = ( nLinkageType != 0 ); |
1634 | 0 | return true; |
1635 | 0 | } |
1636 | | |
1637 | 0 | return OControlImport::handleAttribute(nElement, _rValue); |
1638 | 0 | } |
1639 | | |
1640 | | void OListAndComboImport::implPushBackLabel(const OUString& _rLabel) |
1641 | 0 | { |
1642 | 0 | OSL_ENSURE(!m_nEmptyListItems, "OListAndComboImport::implPushBackValue: label list is already done!"); |
1643 | 0 | if (!m_nEmptyListItems) |
1644 | 0 | m_aListSource.push_back(_rLabel); |
1645 | 0 | } |
1646 | | |
1647 | | void OListAndComboImport::implPushBackValue(const OUString& _rValue) |
1648 | 0 | { |
1649 | 0 | OSL_ENSURE(!m_nEmptyValueItems, "OListAndComboImport::implPushBackValue: value list is already done!"); |
1650 | 0 | if (!m_nEmptyValueItems) |
1651 | 0 | { |
1652 | 0 | OSL_ENSURE( !m_bEncounteredLSAttrib, "OListAndComboImport::implPushBackValue: invalid structure! Did you save this document with a version prior SRC641 m?" ); |
1653 | | // We already had the list-source attribute, which means that the ListSourceType is |
1654 | | // not ValueList, which means that the ListSource should contain only one string in |
1655 | | // the first element of the sequence |
1656 | | // All other values in the file are invalid |
1657 | |
|
1658 | 0 | m_aValueList.push_back( _rValue ); |
1659 | 0 | } |
1660 | 0 | } |
1661 | | |
1662 | | void OListAndComboImport::implEmptyLabelFound() |
1663 | 0 | { |
1664 | 0 | ++m_nEmptyListItems; |
1665 | 0 | } |
1666 | | |
1667 | | void OListAndComboImport::implEmptyValueFound() |
1668 | 0 | { |
1669 | 0 | ++m_nEmptyValueItems; |
1670 | 0 | } |
1671 | | |
1672 | | void OListAndComboImport::implSelectCurrentItem() |
1673 | 0 | { |
1674 | 0 | OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems), |
1675 | 0 | "OListAndComboImport::implSelectCurrentItem: inconsistence between labels and values!"); |
1676 | |
|
1677 | 0 | sal_Int16 nItemNumber = static_cast<sal_Int16>(m_aListSource.size() - 1 + m_nEmptyListItems); |
1678 | 0 | m_aSelectedSeq.push_back(nItemNumber); |
1679 | 0 | } |
1680 | | |
1681 | | void OListAndComboImport::implDefaultSelectCurrentItem() |
1682 | 0 | { |
1683 | 0 | OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems), |
1684 | 0 | "OListAndComboImport::implDefaultSelectCurrentItem: inconsistence between labels and values!"); |
1685 | |
|
1686 | 0 | sal_Int16 nItemNumber = static_cast<sal_Int16>(m_aListSource.size() - 1 + m_nEmptyListItems); |
1687 | 0 | m_aDefaultSelectedSeq.push_back(nItemNumber); |
1688 | 0 | } |
1689 | | |
1690 | | //= OListOptionImport |
1691 | | OListOptionImport::OListOptionImport(SvXMLImport& _rImport, |
1692 | | OListAndComboImportRef _xListBox) |
1693 | 0 | :SvXMLImportContext(_rImport) |
1694 | 0 | ,m_xListBoxImport(std::move(_xListBox)) |
1695 | 0 | { |
1696 | 0 | } |
1697 | | |
1698 | | void OListOptionImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) |
1699 | 0 | { |
1700 | | // the label and the value |
1701 | 0 | const sal_Int32 nLabelAttribute = (nElement & ~TOKEN_MASK) | XML_LABEL; |
1702 | 0 | const sal_Int32 nValueAttribute = (nElement & ~TOKEN_MASK) | XML_VALUE; |
1703 | | |
1704 | | // the label attribute |
1705 | 0 | OUString sValue = _rxAttrList->getOptionalValue(nLabelAttribute); |
1706 | 0 | bool bNonexistentAttribute = !_rxAttrList->hasAttribute(nLabelAttribute); |
1707 | |
|
1708 | 0 | if (bNonexistentAttribute) |
1709 | 0 | m_xListBoxImport->implEmptyLabelFound(); |
1710 | 0 | else |
1711 | 0 | m_xListBoxImport->implPushBackLabel( sValue ); |
1712 | | |
1713 | | // the value attribute |
1714 | 0 | sValue = _rxAttrList->getOptionalValue(nValueAttribute); |
1715 | 0 | bNonexistentAttribute = !_rxAttrList->hasAttribute(nValueAttribute); |
1716 | |
|
1717 | 0 | if (bNonexistentAttribute) |
1718 | 0 | m_xListBoxImport->implEmptyValueFound(); |
1719 | 0 | else |
1720 | 0 | m_xListBoxImport->implPushBackValue( sValue ); |
1721 | | |
1722 | | // the current-selected and selected |
1723 | 0 | const sal_Int32 nSelectedAttribute = (nElement & ~TOKEN_MASK) | OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentSelected); |
1724 | 0 | const sal_Int32 nDefaultSelectedAttribute = (nElement & ~TOKEN_MASK) | OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Selected); |
1725 | | |
1726 | | // propagate the selected flag |
1727 | 0 | bool bSelected(false); |
1728 | 0 | (void)::sax::Converter::convertBool(bSelected, |
1729 | 0 | _rxAttrList->getOptionalValue(nSelectedAttribute)); |
1730 | 0 | if (bSelected) |
1731 | 0 | m_xListBoxImport->implSelectCurrentItem(); |
1732 | | |
1733 | | // same for the default selected |
1734 | 0 | bool bDefaultSelected(false); |
1735 | 0 | (void)::sax::Converter::convertBool(bDefaultSelected, |
1736 | 0 | _rxAttrList->getOptionalValue(nDefaultSelectedAttribute)); |
1737 | 0 | if (bDefaultSelected) |
1738 | 0 | m_xListBoxImport->implDefaultSelectCurrentItem(); |
1739 | 0 | } |
1740 | | |
1741 | | //= OComboItemImport |
1742 | | OComboItemImport::OComboItemImport(SvXMLImport& _rImport, |
1743 | | OListAndComboImportRef _xListBox) |
1744 | 0 | :SvXMLImportContext(_rImport) |
1745 | 0 | ,m_xListBoxImport(std::move(_xListBox)) |
1746 | 0 | { |
1747 | 0 | } |
1748 | | |
1749 | | void OComboItemImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) |
1750 | 0 | { |
1751 | 0 | const sal_Int32 nLabelAttributeName = (nElement & ~TOKEN_MASK) | |
1752 | 0 | OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Label); |
1753 | 0 | m_xListBoxImport->implPushBackLabel(_rxAttrList->getOptionalValue(nLabelAttributeName)); |
1754 | 0 | } |
1755 | | |
1756 | | //= OColumnWrapperImport |
1757 | | OColumnWrapperImport::OColumnWrapperImport(OFormLayerXMLImport_Impl& _rImport, |
1758 | | IEventAttacherManager& _rEventManager, sal_Int32 /*nElement*/, |
1759 | | const Reference< XNameContainer >& _rxParentContainer) |
1760 | 0 | :SvXMLImportContext(_rImport.getGlobalContext()) |
1761 | 0 | ,m_xParentContainer(_rxParentContainer) |
1762 | 0 | ,m_rFormImport(_rImport) |
1763 | 0 | ,m_rEventManager(_rEventManager) |
1764 | 0 | { |
1765 | 0 | } |
1766 | | css::uno::Reference< css::xml::sax::XFastContextHandler > OColumnWrapperImport::createFastChildContext( |
1767 | | sal_Int32 nElement, |
1768 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) |
1769 | 0 | { |
1770 | 0 | OControlImport* pReturn = implCreateChildContext(nElement, OElementNameMap::getElementType(nElement & TOKEN_MASK)); |
1771 | 0 | if (pReturn) |
1772 | 0 | { |
1773 | 0 | OSL_ENSURE(m_xOwnAttributes.is(), "OColumnWrapperImport::CreateChildContext: had no form:column element!"); |
1774 | 0 | pReturn->addOuterAttributes(m_xOwnAttributes); |
1775 | 0 | } |
1776 | 0 | return pReturn; |
1777 | 0 | } |
1778 | | void OColumnWrapperImport::startFastElement(sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& _rxAttrList) |
1779 | 0 | { |
1780 | 0 | OSL_ENSURE(!m_xOwnAttributes.is(), "OColumnWrapperImport::StartElement: already have the cloned list!"); |
1781 | | |
1782 | | // clone the attributes |
1783 | 0 | Reference< XCloneable > xCloneList(_rxAttrList, UNO_QUERY_THROW); |
1784 | 0 | m_xOwnAttributes.set(xCloneList->createClone(), UNO_QUERY_THROW); |
1785 | 0 | } |
1786 | | |
1787 | | OControlImport* OColumnWrapperImport::implCreateChildContext( |
1788 | | sal_Int32 /*nElement*/, |
1789 | | OControlElement::ElementType _eType) |
1790 | 0 | { |
1791 | 0 | OSL_ENSURE( (OControlElement::TEXT == _eType) |
1792 | 0 | || (OControlElement::TEXT_AREA == _eType) |
1793 | 0 | || (OControlElement::FORMATTED_TEXT == _eType) |
1794 | 0 | || (OControlElement::CHECKBOX == _eType) |
1795 | 0 | || (OControlElement::LISTBOX == _eType) |
1796 | 0 | || (OControlElement::COMBOBOX == _eType) |
1797 | 0 | || (OControlElement::TIME == _eType) |
1798 | 0 | || (OControlElement::DATE == _eType), |
1799 | 0 | "OColumnWrapperImport::implCreateChildContext: invalid or unrecognized sub element!"); |
1800 | |
|
1801 | 0 | switch (_eType) |
1802 | 0 | { |
1803 | 0 | case OControlElement::COMBOBOX: |
1804 | 0 | case OControlElement::LISTBOX: |
1805 | 0 | return new OColumnImport<OListAndComboImport>(m_rFormImport, m_rEventManager, m_xParentContainer, _eType ); |
1806 | | |
1807 | 0 | case OControlElement::PASSWORD: |
1808 | 0 | return new OColumnImport<OPasswordImport>(m_rFormImport, m_rEventManager, m_xParentContainer, _eType ); |
1809 | | |
1810 | 0 | case OControlElement::TEXT: |
1811 | 0 | case OControlElement::TEXT_AREA: |
1812 | 0 | case OControlElement::FORMATTED_TEXT: |
1813 | 0 | return new OColumnImport< OTextLikeImport >( m_rFormImport, m_rEventManager, m_xParentContainer, _eType ); |
1814 | | |
1815 | 0 | default: |
1816 | 0 | return new OColumnImport<OControlImport>(m_rFormImport, m_rEventManager, m_xParentContainer, _eType ); |
1817 | 0 | } |
1818 | 0 | } |
1819 | | |
1820 | | //= OGridImport |
1821 | | OGridImport::OGridImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1822 | | const Reference< XNameContainer >& _rxParentContainer, |
1823 | | OControlElement::ElementType _eType) |
1824 | 0 | :OControlImport(_rImport, _rEventManager, _rxParentContainer) |
1825 | 0 | { |
1826 | 0 | setElementType(_eType); |
1827 | 0 | } |
1828 | | |
1829 | | css::uno::Reference< css::xml::sax::XFastContextHandler > OGridImport::createFastChildContext( |
1830 | | sal_Int32 nElement, |
1831 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) |
1832 | 0 | { |
1833 | | // maybe it's a sub control |
1834 | 0 | if ((nElement & TOKEN_MASK) == XML_COLUMN) |
1835 | 0 | { |
1836 | 0 | if (m_xMeAsContainer.is()) |
1837 | 0 | return new OColumnWrapperImport(m_rFormImport, *this, nElement, m_xMeAsContainer); |
1838 | 0 | else |
1839 | 0 | { |
1840 | 0 | OSL_FAIL("OGridImport::CreateChildContext: don't have an element!"); |
1841 | 0 | return nullptr; |
1842 | 0 | } |
1843 | 0 | } |
1844 | | |
1845 | 0 | return OControlImport::createFastChildContext(nElement, xAttrList); |
1846 | 0 | } |
1847 | | |
1848 | | void OGridImport::endFastElement(sal_Int32 nElement) |
1849 | 0 | { |
1850 | 0 | OControlImport::endFastElement(nElement); |
1851 | | |
1852 | | // now that we have all children, attach the events |
1853 | 0 | css::uno::Reference< css::container::XIndexAccess > xIndexContainer(m_xMeAsContainer, css::uno::UNO_QUERY); |
1854 | 0 | if (xIndexContainer.is()) |
1855 | 0 | ODefaultEventAttacherManager::setEvents(xIndexContainer); |
1856 | 0 | } |
1857 | | |
1858 | | css::uno::Reference< css::beans::XPropertySet > OGridImport::createElement() |
1859 | 0 | { |
1860 | | // let the base class create the object |
1861 | 0 | css::uno::Reference< css::beans::XPropertySet > xReturn = OControlImport::createElement(); |
1862 | 0 | if (!xReturn.is()) |
1863 | 0 | return xReturn; |
1864 | | |
1865 | | // ensure that the object is a XNameContainer (we strongly need this for inserting child elements) |
1866 | 0 | m_xMeAsContainer.set(xReturn, css::uno::UNO_QUERY); |
1867 | 0 | if (!m_xMeAsContainer.is()) |
1868 | 0 | { |
1869 | 0 | OSL_FAIL("OContainerImport::createElement: invalid element (no XNameContainer) created!"); |
1870 | 0 | xReturn.clear(); |
1871 | 0 | } |
1872 | |
|
1873 | 0 | return xReturn; |
1874 | 0 | } |
1875 | | |
1876 | | //= OFormImport |
1877 | | OFormImport::OFormImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, |
1878 | | const Reference< XNameContainer >& _rxParentContainer) |
1879 | 0 | :OElementImport(_rImport, _rEventManager, _rxParentContainer) |
1880 | 0 | { |
1881 | 0 | enableTrackAttributes(); |
1882 | 0 | } |
1883 | | |
1884 | | css::uno::Reference< css::xml::sax::XFastContextHandler > OFormImport::createFastChildContext( |
1885 | | sal_Int32 nElement, |
1886 | | const uno::Reference< xml::sax::XFastAttributeList>& _rxAttrList ) |
1887 | 0 | { |
1888 | 0 | auto nToken = (nElement & TOKEN_MASK); |
1889 | 0 | if( nToken == XML_FORM ) |
1890 | 0 | return new OFormImport( m_rFormImport, *this, m_xMeAsContainer); |
1891 | 0 | else if ( nToken == XML_CONNECTION_RESOURCE ) |
1892 | 0 | return new OXMLDataSourceImport(GetImport(), _rxAttrList, m_xElement); |
1893 | 0 | else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) || |
1894 | 0 | nToken == XML_PROPERTIES ) |
1895 | 0 | return OElementImport::createFastChildContext( nElement, _rxAttrList ); |
1896 | 0 | else |
1897 | 0 | { |
1898 | 0 | OControlElement::ElementType eType = OElementNameMap::getElementType(nToken); |
1899 | 0 | switch (eType) |
1900 | 0 | { |
1901 | 0 | case OControlElement::TEXT: |
1902 | 0 | case OControlElement::TEXT_AREA: |
1903 | 0 | case OControlElement::FORMATTED_TEXT: |
1904 | 0 | return new OTextLikeImport(m_rFormImport, *this, m_xMeAsContainer, eType); |
1905 | 0 | case OControlElement::GRID: |
1906 | 0 | return new OGridImport(m_rFormImport, *this, m_xMeAsContainer, eType); |
1907 | 0 | case OControlElement::COMBOBOX: |
1908 | 0 | case OControlElement::LISTBOX: |
1909 | 0 | return new OListAndComboImport(m_rFormImport, *this, m_xMeAsContainer, eType); |
1910 | 0 | case OControlElement::PASSWORD: |
1911 | 0 | return new OPasswordImport(m_rFormImport, *this, m_xMeAsContainer, eType); |
1912 | 0 | case OControlElement::BUTTON: |
1913 | 0 | case OControlElement::IMAGE: |
1914 | 0 | case OControlElement::IMAGE_FRAME: |
1915 | 0 | return new OButtonImport( m_rFormImport, *this, m_xMeAsContainer, eType ); |
1916 | 0 | case OControlElement::RADIO: |
1917 | 0 | return new ORadioImport(m_rFormImport, *this, m_xMeAsContainer, eType); |
1918 | 0 | case OControlElement::CHECKBOX: |
1919 | 0 | return new OImagePositionImport(m_rFormImport, *this, m_xMeAsContainer, eType); |
1920 | 0 | case OControlElement::FRAME: |
1921 | 0 | case OControlElement::FIXED_TEXT: |
1922 | 0 | return new OReferredControlImport(m_rFormImport, *this, m_xMeAsContainer); |
1923 | 0 | case OControlElement::VALUERANGE: |
1924 | 0 | return new OValueRangeImport( m_rFormImport, *this, m_xMeAsContainer, eType ); |
1925 | 0 | default: |
1926 | 0 | return new OControlImport(m_rFormImport, *this, m_xMeAsContainer, eType); |
1927 | 0 | } |
1928 | 0 | } |
1929 | 0 | } |
1930 | | |
1931 | | void OFormImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) |
1932 | 0 | { |
1933 | 0 | m_rFormImport.enterEventContext(); |
1934 | 0 | OElementImport::startFastElement(nElement, _rxAttrList); |
1935 | | |
1936 | | // handle the target-frame attribute |
1937 | 0 | simulateDefaultedAttribute(OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetFrame), PROPERTY_TARGETFRAME, u"_blank"_ustr); |
1938 | 0 | } |
1939 | | |
1940 | | void OFormImport::endFastElement(sal_Int32 nElement) |
1941 | 0 | { |
1942 | 0 | OElementImport::endFastElement(nElement); |
1943 | | |
1944 | | // now that we have all children, attach the events |
1945 | 0 | css::uno::Reference< css::container::XIndexAccess > xIndexContainer(m_xMeAsContainer, css::uno::UNO_QUERY); |
1946 | 0 | if (xIndexContainer.is()) |
1947 | 0 | ODefaultEventAttacherManager::setEvents(xIndexContainer); |
1948 | |
|
1949 | 0 | m_rFormImport.leaveEventContext(); |
1950 | 0 | } |
1951 | | |
1952 | | css::uno::Reference< css::beans::XPropertySet > OFormImport::createElement() |
1953 | 0 | { |
1954 | | // let the base class create the object |
1955 | 0 | css::uno::Reference< css::beans::XPropertySet > xReturn = OElementImport::createElement(); |
1956 | 0 | if (!xReturn.is()) |
1957 | 0 | return xReturn; |
1958 | | |
1959 | | // ensure that the object is a XNameContainer (we strongly need this for inserting child elements) |
1960 | 0 | m_xMeAsContainer.set(xReturn, css::uno::UNO_QUERY); |
1961 | 0 | if (!m_xMeAsContainer.is()) |
1962 | 0 | { |
1963 | 0 | OSL_FAIL("OContainerImport::createElement: invalid element (no XNameContainer) created!"); |
1964 | 0 | xReturn.clear(); |
1965 | 0 | } |
1966 | |
|
1967 | 0 | return xReturn; |
1968 | 0 | } |
1969 | | |
1970 | | bool OFormImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) |
1971 | 0 | { |
1972 | | // handle the master/details field attributes (they're way too special to let the OPropertyImport handle them) |
1973 | 0 | static const sal_Int32 s_nMasterFieldsAttributeName = OAttributeMetaData::getFormAttributeToken(faMasterFields); |
1974 | 0 | static const sal_Int32 s_nDetailFieldsAttributeName = OAttributeMetaData::getFormAttributeToken(faDetailFields); |
1975 | |
|
1976 | 0 | if ( (nElement & TOKEN_MASK) == s_nMasterFieldsAttributeName) |
1977 | 0 | { |
1978 | 0 | implTranslateStringListProperty(PROPERTY_MASTERFIELDS, _rValue); |
1979 | 0 | return true; |
1980 | 0 | } |
1981 | | |
1982 | 0 | if ( (nElement & TOKEN_MASK) == s_nDetailFieldsAttributeName) |
1983 | 0 | { |
1984 | 0 | implTranslateStringListProperty(PROPERTY_DETAILFIELDS, _rValue); |
1985 | 0 | return true; |
1986 | 0 | } |
1987 | | |
1988 | 0 | return OElementImport::handleAttribute(nElement, _rValue); |
1989 | 0 | } |
1990 | | |
1991 | | void OFormImport::implTranslateStringListProperty(const OUString& _rPropertyName, const OUString& _rValue) |
1992 | 0 | { |
1993 | 0 | PropertyValue aProp; |
1994 | 0 | aProp.Name = _rPropertyName; |
1995 | |
|
1996 | 0 | Sequence< OUString > aList; |
1997 | | |
1998 | | // split up the value string |
1999 | 0 | if (!_rValue.isEmpty()) |
2000 | 0 | { |
2001 | | // For the moment, we build a vector instead of a Sequence. It's easier to handle because of its |
2002 | | // push_back method |
2003 | 0 | ::std::vector< OUString > aElements; |
2004 | | // estimate the number of tokens |
2005 | 0 | sal_Int32 nEstimate = 0, nLength = _rValue.getLength(); |
2006 | 0 | const sal_Unicode* pChars = _rValue.getStr(); |
2007 | 0 | for (sal_Int32 i=0; i<nLength; ++i, ++pChars) |
2008 | 0 | if (*pChars == ',') |
2009 | 0 | ++nEstimate; |
2010 | 0 | aElements.reserve(nEstimate + 1); |
2011 | | // that's the worst case. If the string contains the separator character _quoted_, we reserved too much... |
2012 | |
|
2013 | 0 | sal_Int32 nElementStart = 0; |
2014 | 0 | sal_Int32 nNextSep = 0; |
2015 | 0 | do |
2016 | 0 | { |
2017 | | // extract the current element |
2018 | 0 | nNextSep = ::sax::Converter::indexOfComma( |
2019 | 0 | _rValue, nElementStart); |
2020 | 0 | if (-1 == nNextSep) |
2021 | 0 | nNextSep = nLength; |
2022 | 0 | std::u16string_view sElement = _rValue.subView(nElementStart, nNextSep - nElementStart); |
2023 | |
|
2024 | 0 | size_t nElementLength = sElement.size(); |
2025 | | // when writing the sequence, we quoted the single elements with " characters |
2026 | 0 | OSL_ENSURE( o3tl::starts_with(sElement, u"\"") && o3tl::ends_with(sElement, u"\""), |
2027 | 0 | "OFormImport::implTranslateStringListProperty: invalid quoted element name."); |
2028 | 0 | sElement = sElement.substr(1, nElementLength - 2); |
2029 | |
|
2030 | 0 | aElements.emplace_back(sElement); |
2031 | | |
2032 | | // switch to the next element |
2033 | 0 | nElementStart = 1 + nNextSep; |
2034 | 0 | } |
2035 | 0 | while (nElementStart < nLength); |
2036 | |
|
2037 | 0 | aList = Sequence< OUString >(aElements.data(), aElements.size()); |
2038 | 0 | } |
2039 | 0 | else |
2040 | 0 | { |
2041 | 0 | OSL_FAIL("OFormImport::implTranslateStringListProperty: invalid value (empty)!"); |
2042 | 0 | } |
2043 | |
|
2044 | 0 | aProp.Value <<= aList; |
2045 | | |
2046 | | // add the property to the base class' array |
2047 | 0 | implPushBackPropertyValue(aProp); |
2048 | 0 | } |
2049 | | //= OXMLDataSourceImport |
2050 | | OXMLDataSourceImport::OXMLDataSourceImport( |
2051 | | SvXMLImport& _rImport |
2052 | | ,const Reference< css::xml::sax::XFastAttributeList > & _xAttrList |
2053 | | ,const css::uno::Reference< css::beans::XPropertySet >& _xElement) : |
2054 | 0 | SvXMLImportContext( _rImport) |
2055 | 0 | { |
2056 | 0 | for( auto& aIter : sax_fastparser::castToFastAttributeList(_xAttrList) ) |
2057 | 0 | { |
2058 | 0 | if ( aIter.getToken() == |
2059 | 0 | XML_ELEMENT(XLINK, OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::TargetLocation ) ) ) |
2060 | 0 | { |
2061 | 0 | OUString sValue = aIter.toString(); |
2062 | 0 | sValue = _rImport.GetAbsoluteReference(sValue); |
2063 | 0 | INetURLObject aURL(sValue); |
2064 | 0 | if ( aURL.GetProtocol() == INetProtocol::File ) |
2065 | 0 | _xElement->setPropertyValue(PROPERTY_DATASOURCENAME,Any(sValue)); |
2066 | 0 | else |
2067 | 0 | _xElement->setPropertyValue(PROPERTY_URL,Any(sValue)); // the url is the "sdbc:" string |
2068 | 0 | break; |
2069 | 0 | } |
2070 | 0 | else |
2071 | 0 | SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); |
2072 | 0 | } |
2073 | 0 | } |
2074 | | |
2075 | | OUString OFormImport::determineDefaultServiceName() const |
2076 | 0 | { |
2077 | 0 | return u"com.sun.star.form.component.Form"_ustr; |
2078 | 0 | } |
2079 | | |
2080 | | } // namespace xmloff |
2081 | | |
2082 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |