/src/libreoffice/xmloff/source/forms/propertyexport.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 "propertyexport.hxx" |
21 | | |
22 | | #include <memory> |
23 | | |
24 | | #include <xmloff/xmlexp.hxx> |
25 | | #include "strings.hxx" |
26 | | #include <xmloff/xmlnamespace.hxx> |
27 | | #include <xmloff/xmluconv.hxx> |
28 | | #include <xmloff/xmlexppr.hxx> |
29 | | #include <xmloff/xmlprmap.hxx> |
30 | | #include <sax/tools/converter.hxx> |
31 | | #include <sal/log.hxx> |
32 | | #include <comphelper/diagnose_ex.hxx> |
33 | | #include <com/sun/star/beans/PropertyAttribute.hpp> |
34 | | #include <com/sun/star/util/Date.hpp> |
35 | | #include <com/sun/star/graphic/XGraphic.hpp> |
36 | | #include <com/sun/star/util/Time.hpp> |
37 | | #include <com/sun/star/util/DateTime.hpp> |
38 | | #include <comphelper/extract.hxx> |
39 | | #include <comphelper/types.hxx> |
40 | | #include "callbacks.hxx" |
41 | | #include <unotools/datetime.hxx> |
42 | | #include <tools/date.hxx> |
43 | | #include <tools/datetime.hxx> |
44 | | |
45 | | namespace xmloff |
46 | | { |
47 | | |
48 | | using namespace css; |
49 | | using namespace ::com::sun::star::uno; |
50 | | using namespace ::com::sun::star::beans; |
51 | | |
52 | | // NO using namespace ...util !!! |
53 | | // need a tools Date/Time/DateTime below, which would conflict with the uno types then |
54 | | |
55 | | using namespace ::comphelper; |
56 | | |
57 | | //= OPropertyExport |
58 | | OPropertyExport::OPropertyExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxProps) |
59 | 0 | :m_rContext(_rContext) |
60 | 0 | ,m_xProps(_rxProps) |
61 | 0 | ,m_xPropertyInfo( m_xProps->getPropertySetInfo() ) |
62 | 0 | ,m_xPropertyState( _rxProps, UNO_QUERY ) |
63 | 0 | { |
64 | | // caching |
65 | 0 | OUStringBuffer aBuffer; |
66 | 0 | ::sax::Converter::convertBool(aBuffer, true); |
67 | 0 | m_sValueTrue = aBuffer.makeStringAndClear(); |
68 | 0 | ::sax::Converter::convertBool(aBuffer, false); |
69 | 0 | m_sValueFalse = aBuffer.makeStringAndClear(); |
70 | |
|
71 | 0 | OSL_ENSURE(m_xPropertyInfo.is(), "OPropertyExport::OPropertyExport: need an XPropertySetInfo!"); |
72 | | |
73 | | // collect the properties which need to be exported |
74 | 0 | examinePersistence(); |
75 | 0 | } |
76 | | |
77 | | bool OPropertyExport::shouldExportProperty( const OUString& i_propertyName ) const |
78 | 0 | { |
79 | | // if the property state is DEFAULT, it does not need to be written - at least |
80 | | // if it's a built-in property, and not a dynamically-added one. |
81 | 0 | bool bIsDefaultValue = m_xPropertyState.is() |
82 | 0 | && ( PropertyState_DEFAULT_VALUE == m_xPropertyState->getPropertyState( i_propertyName ) ); |
83 | 0 | bool bIsDynamicProperty = m_xPropertyInfo.is() |
84 | 0 | && ( ( m_xPropertyInfo->getPropertyByName( i_propertyName ).Attributes & PropertyAttribute::REMOVABLE ) != 0 ); |
85 | 0 | return ( !bIsDefaultValue || bIsDynamicProperty ); |
86 | 0 | } |
87 | | |
88 | | template< typename T > void |
89 | | OPropertyExport::exportRemainingPropertiesSequence( |
90 | | Any const & value, token::XMLTokenEnum eValueAttName) |
91 | 0 | { |
92 | 0 | css::uno::Sequence<T> anySeq; |
93 | 0 | bool bSuccess = value >>= anySeq; |
94 | 0 | assert(bSuccess); (void)bSuccess; |
95 | 0 | for (T const& i : anySeq) |
96 | 0 | { |
97 | 0 | OUString sValue(implConvertAny(Any(i))); |
98 | 0 | AddAttribute(XML_NAMESPACE_OFFICE, eValueAttName, sValue ); |
99 | 0 | SvXMLElementExport aValueTag( |
100 | 0 | m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, |
101 | 0 | token::XML_LIST_VALUE, true, false); |
102 | 0 | } |
103 | 0 | } Unexecuted instantiation: void xmloff::OPropertyExport::exportRemainingPropertiesSequence<rtl::OUString>(com::sun::star::uno::Any const&, xmloff::token::XMLTokenEnum) Unexecuted instantiation: void xmloff::OPropertyExport::exportRemainingPropertiesSequence<double>(com::sun::star::uno::Any const&, xmloff::token::XMLTokenEnum) Unexecuted instantiation: void xmloff::OPropertyExport::exportRemainingPropertiesSequence<unsigned char>(com::sun::star::uno::Any const&, xmloff::token::XMLTokenEnum) Unexecuted instantiation: void xmloff::OPropertyExport::exportRemainingPropertiesSequence<signed char>(com::sun::star::uno::Any const&, xmloff::token::XMLTokenEnum) Unexecuted instantiation: void xmloff::OPropertyExport::exportRemainingPropertiesSequence<short>(com::sun::star::uno::Any const&, xmloff::token::XMLTokenEnum) Unexecuted instantiation: void xmloff::OPropertyExport::exportRemainingPropertiesSequence<int>(com::sun::star::uno::Any const&, xmloff::token::XMLTokenEnum) Unexecuted instantiation: void xmloff::OPropertyExport::exportRemainingPropertiesSequence<long>(com::sun::star::uno::Any const&, xmloff::token::XMLTokenEnum) |
104 | | |
105 | | void OPropertyExport::exportRemainingProperties() |
106 | 0 | { |
107 | | // the properties tag (will be created if we have at least one no-default property) |
108 | 0 | std::unique_ptr<SvXMLElementExport> pPropertiesTag; |
109 | |
|
110 | 0 | Any aValue; |
111 | 0 | OUString sValue; |
112 | | |
113 | | // loop through all the properties which are yet to be exported |
114 | 0 | for ( const auto& rProperty : m_aRemainingProps ) |
115 | 0 | { |
116 | 0 | DBG_CHECK_PROPERTY_NO_TYPE(rProperty); |
117 | |
|
118 | 0 | if ( !shouldExportProperty( rProperty ) ) |
119 | 0 | continue; |
120 | | |
121 | | // now that we have the first sub-tag we need the form:properties element |
122 | 0 | if (!pPropertiesTag) |
123 | 0 | pPropertiesTag = std::make_unique<SvXMLElementExport>(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, token::XML_PROPERTIES, true, true); |
124 | | |
125 | | // add the name attribute |
126 | 0 | AddAttribute(XML_NAMESPACE_FORM, token::XML_PROPERTY_NAME, rProperty); |
127 | | |
128 | | // get the value |
129 | 0 | aValue = m_xProps->getPropertyValue(rProperty); |
130 | | |
131 | | // the type to export |
132 | 0 | Type aExportType; |
133 | | |
134 | | // is it a sequence |
135 | 0 | bool bIsSequence = TypeClass_SEQUENCE == aValue.getValueTypeClass(); |
136 | | // the type of the property, maybe reduced to the element type of a sequence |
137 | 0 | if (bIsSequence) |
138 | 0 | aExportType = getSequenceElementType( aValue.getValueType() ); |
139 | 0 | else |
140 | 0 | aExportType = aValue.getValueType(); |
141 | | |
142 | | // the type attribute |
143 | |
|
144 | 0 | bool bIsEmptyValue = TypeClass_VOID == aValue.getValueTypeClass(); |
145 | 0 | if ( bIsEmptyValue ) |
146 | 0 | { |
147 | 0 | css::beans::Property aPropDesc = m_xPropertyInfo->getPropertyByName( rProperty ); |
148 | 0 | aExportType = aPropDesc.Type; |
149 | 0 | } |
150 | 0 | token::XMLTokenEnum eValueType = implGetPropertyXMLType( aExportType ); |
151 | |
|
152 | 0 | if ( bIsEmptyValue ) |
153 | 0 | AddAttribute( XML_NAMESPACE_OFFICE, token::XML_VALUE_TYPE, token::XML_VOID ); |
154 | 0 | else |
155 | 0 | AddAttribute( XML_NAMESPACE_OFFICE, token::XML_VALUE_TYPE, eValueType ); |
156 | |
|
157 | 0 | token::XMLTokenEnum eValueAttName( token::XML_VALUE ); |
158 | 0 | switch ( eValueType ) |
159 | 0 | { |
160 | 0 | case token::XML_BOOLEAN: eValueAttName = token::XML_BOOLEAN_VALUE; break; |
161 | 0 | case token::XML_STRING: eValueAttName = token::XML_STRING_VALUE; break; |
162 | 0 | default: break; |
163 | 0 | } |
164 | | |
165 | 0 | if( !bIsSequence && !bIsEmptyValue ) |
166 | 0 | { // the simple case |
167 | |
|
168 | 0 | sValue = implConvertAny(aValue); |
169 | 0 | AddAttribute(XML_NAMESPACE_OFFICE, eValueAttName, sValue ); |
170 | 0 | } |
171 | | |
172 | | // start the property tag |
173 | 0 | SvXMLElementExport aValueTag1(m_rContext.getGlobalContext(), |
174 | 0 | XML_NAMESPACE_FORM, |
175 | 0 | bIsSequence ? token::XML_LIST_PROPERTY |
176 | 0 | : token::XML_PROPERTY, true, true); |
177 | |
|
178 | 0 | if (!bIsSequence) |
179 | 0 | continue; |
180 | | |
181 | | // the not-that-simple case, we need to iterate through the sequence elements |
182 | 0 | switch ( aExportType.getTypeClass() ) |
183 | 0 | { |
184 | 0 | case TypeClass_STRING: |
185 | 0 | exportRemainingPropertiesSequence< OUString >( |
186 | 0 | aValue, eValueAttName); |
187 | 0 | break; |
188 | 0 | case TypeClass_DOUBLE: |
189 | 0 | exportRemainingPropertiesSequence< double >( |
190 | 0 | aValue, eValueAttName); |
191 | 0 | break; |
192 | 0 | case TypeClass_BOOLEAN: |
193 | 0 | exportRemainingPropertiesSequence< sal_Bool >( |
194 | 0 | aValue, eValueAttName); |
195 | 0 | break; |
196 | 0 | case TypeClass_BYTE: |
197 | 0 | exportRemainingPropertiesSequence< sal_Int8 >( |
198 | 0 | aValue, eValueAttName); |
199 | 0 | break; |
200 | 0 | case TypeClass_SHORT: |
201 | 0 | exportRemainingPropertiesSequence< sal_Int16 >( |
202 | 0 | aValue, eValueAttName); |
203 | 0 | break; |
204 | 0 | case TypeClass_LONG: |
205 | 0 | exportRemainingPropertiesSequence< sal_Int32 >( |
206 | 0 | aValue, eValueAttName); |
207 | 0 | break; |
208 | 0 | case TypeClass_HYPER: |
209 | 0 | exportRemainingPropertiesSequence< sal_Int64 >( |
210 | 0 | aValue, eValueAttName); |
211 | 0 | break; |
212 | 0 | default: |
213 | 0 | OSL_FAIL("OPropertyExport::exportRemainingProperties: unsupported sequence type !"); |
214 | 0 | break; |
215 | 0 | } |
216 | 0 | } |
217 | 0 | } |
218 | | |
219 | | void OPropertyExport::examinePersistence() |
220 | 0 | { |
221 | 0 | m_aRemainingProps.clear(); |
222 | 0 | const Sequence< Property > aProperties = m_xPropertyInfo->getProperties(); |
223 | 0 | for (const auto& rProp : aProperties) |
224 | 0 | { |
225 | | // no transient props |
226 | 0 | if ( rProp.Attributes & PropertyAttribute::TRANSIENT ) |
227 | 0 | continue; |
228 | | // no read-only props |
229 | 0 | if ( ( rProp.Attributes & PropertyAttribute::READONLY ) != 0 ) |
230 | | // except they're dynamically added |
231 | 0 | if ( ( rProp.Attributes & PropertyAttribute::REMOVABLE ) == 0 ) |
232 | 0 | continue; |
233 | 0 | m_aRemainingProps.insert(rProp.Name); |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | void OPropertyExport::exportStringPropertyAttribute( const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, |
238 | | const OUString& _rPropertyName ) |
239 | 0 | { |
240 | 0 | DBG_CHECK_PROPERTY( _rPropertyName, OUString ); |
241 | | |
242 | | // no try-catch here, this would be too expensive. The outer scope has to handle exceptions (which should not |
243 | | // happen if we're used correctly :) |
244 | | |
245 | | // this is way simple, as we don't need to convert anything (the property already is a string) |
246 | | |
247 | | // get the string |
248 | 0 | OUString sPropValue; |
249 | 0 | m_xProps->getPropertyValue( _rPropertyName ) >>= sPropValue; |
250 | | |
251 | | // add the attribute |
252 | 0 | if ( !sPropValue.isEmpty() ) |
253 | 0 | AddAttribute( _nNamespaceKey, _pAttributeName, sPropValue ); |
254 | | |
255 | | // the property does not need to be handled anymore |
256 | 0 | exportedProperty( _rPropertyName ); |
257 | 0 | } |
258 | | |
259 | | void OPropertyExport::exportBooleanPropertyAttribute(const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, |
260 | | const OUString& _rPropertyName, const BoolAttrFlags _nBooleanAttributeFlags) |
261 | 0 | { |
262 | 0 | DBG_CHECK_PROPERTY_NO_TYPE( _rPropertyName ); |
263 | | // no check of the property value type: this method is allowed to be called with any integer properties |
264 | | // (e.g. sal_Int32, sal_uInt16 etc) |
265 | |
|
266 | 0 | bool bDefault(BoolAttrFlags::DefaultTrue & _nBooleanAttributeFlags); |
267 | 0 | bool bDefaultVoid(BoolAttrFlags::DefaultVoid & _nBooleanAttributeFlags); |
268 | | |
269 | | // get the value |
270 | 0 | bool bCurrentValue = bDefault; |
271 | 0 | Any aCurrentValue = m_xProps->getPropertyValue( _rPropertyName ); |
272 | 0 | if (aCurrentValue.hasValue()) |
273 | 0 | { |
274 | 0 | bCurrentValue = ::cppu::any2bool(aCurrentValue); |
275 | | // this will extract a boolean value even if the Any contains a int or short or something like that ... |
276 | |
|
277 | 0 | if (_nBooleanAttributeFlags & BoolAttrFlags::InverseSemantics) |
278 | 0 | bCurrentValue = !bCurrentValue; |
279 | | |
280 | | // we have a non-void current value |
281 | 0 | if (bDefaultVoid || (bDefault != bCurrentValue)) |
282 | | // and (the default is void, or the non-void default does not equal the current value) |
283 | | // -> write the attribute |
284 | 0 | AddAttribute(_nNamespaceKey, _pAttributeName, bCurrentValue ? m_sValueTrue : m_sValueFalse); |
285 | 0 | } |
286 | 0 | else |
287 | | // we have a void current value |
288 | 0 | if (!bDefaultVoid) |
289 | | // and we have a non-void default |
290 | | // -> write the attribute |
291 | 0 | AddAttribute(_nNamespaceKey, _pAttributeName, bCurrentValue ? m_sValueTrue : m_sValueFalse); |
292 | | |
293 | | // the property does not need to be handled anymore |
294 | 0 | exportedProperty( _rPropertyName ); |
295 | 0 | } |
296 | | |
297 | | void OPropertyExport::exportInt16PropertyAttribute(const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, |
298 | | const OUString& _rPropertyName, const sal_Int16 _nDefault, bool force) |
299 | 0 | { |
300 | 0 | DBG_CHECK_PROPERTY( _rPropertyName, sal_Int16 ); |
301 | | |
302 | | // get the value |
303 | 0 | sal_Int16 nCurrentValue(_nDefault); |
304 | 0 | m_xProps->getPropertyValue( _rPropertyName ) >>= nCurrentValue; |
305 | | |
306 | | // add the attribute |
307 | 0 | if (force || _nDefault != nCurrentValue) |
308 | 0 | { |
309 | | // let the formatter of the export context build a string |
310 | 0 | AddAttribute(_nNamespaceKey, _pAttributeName, OUString::number(nCurrentValue)); |
311 | 0 | } |
312 | | |
313 | | // the property does not need to be handled anymore |
314 | 0 | exportedProperty( _rPropertyName ); |
315 | 0 | } |
316 | | |
317 | | void OPropertyExport::exportInt32PropertyAttribute( const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, |
318 | | const OUString& _rPropertyName, const sal_Int32 _nDefault ) |
319 | 0 | { |
320 | 0 | DBG_CHECK_PROPERTY( _rPropertyName, sal_Int32 ); |
321 | | |
322 | | // get the value |
323 | 0 | sal_Int32 nCurrentValue( _nDefault ); |
324 | 0 | m_xProps->getPropertyValue( _rPropertyName ) >>= nCurrentValue; |
325 | | |
326 | | // add the attribute |
327 | 0 | if ( _nDefault != nCurrentValue ) |
328 | 0 | { |
329 | | // let the formatter of the export context build a string |
330 | 0 | AddAttribute( _nNamespaceKey, _pAttributeName, OUString::number(nCurrentValue) ); |
331 | 0 | } |
332 | | |
333 | | // the property does not need to be handled anymore |
334 | 0 | exportedProperty( _rPropertyName ); |
335 | 0 | } |
336 | | |
337 | | void OPropertyExport::exportEnumPropertyAttributeImpl( |
338 | | const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, |
339 | | const OUString &rPropertyName, const SvXMLEnumMapEntry<sal_uInt16>* _pValueMap, |
340 | | const sal_uInt16 _nDefault, const bool _bVoidDefault) |
341 | 0 | { |
342 | | // get the value |
343 | 0 | Any aValue = m_xProps->getPropertyValue(rPropertyName); |
344 | |
|
345 | 0 | if (aValue.hasValue()) |
346 | 0 | { // we have a non-void current value |
347 | 0 | sal_Int32 nCurrentValue(_nDefault); |
348 | 0 | ::cppu::enum2int(nCurrentValue, aValue); |
349 | | |
350 | | // add the attribute |
351 | 0 | if ((_nDefault != nCurrentValue) || _bVoidDefault) |
352 | 0 | { // the default does not equal the value, or the default is void and the value isn't |
353 | | |
354 | | // let the formatter of the export context build a string |
355 | 0 | OUStringBuffer sBuffer; |
356 | 0 | SvXMLUnitConverter::convertEnum(sBuffer, static_cast<sal_uInt16>(nCurrentValue), _pValueMap); |
357 | |
|
358 | 0 | AddAttribute(_nNamespaceKey, _pAttributeName, sBuffer.makeStringAndClear()); |
359 | 0 | } |
360 | 0 | } |
361 | 0 | else |
362 | 0 | { |
363 | 0 | if (!_bVoidDefault) |
364 | 0 | AddAttribute(_nNamespaceKey, _pAttributeName, OUString()); |
365 | 0 | } |
366 | | |
367 | | // the property does not need to be handled anymore |
368 | 0 | exportedProperty(rPropertyName); |
369 | 0 | } |
370 | | |
371 | | void OPropertyExport::exportTargetFrameAttribute() |
372 | 0 | { |
373 | 0 | DBG_CHECK_PROPERTY( PROPERTY_TARGETFRAME, OUString ); |
374 | |
|
375 | 0 | OUString sTargetFrame = comphelper::getString(m_xProps->getPropertyValue(PROPERTY_TARGETFRAME)); |
376 | 0 | if( sTargetFrame != "_blank" ) |
377 | 0 | { // an empty string and "_blank" have the same meaning and don't have to be written |
378 | 0 | AddAttribute(OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::TargetFrame) |
379 | 0 | ,OAttributeMetaData::getCommonControlAttributeName(CCAFlags::TargetFrame) |
380 | 0 | ,sTargetFrame); |
381 | 0 | } |
382 | |
|
383 | 0 | exportedProperty(PROPERTY_TARGETFRAME); |
384 | 0 | } |
385 | | |
386 | | void OPropertyExport::exportRelativeTargetLocation(const OUString& _sPropertyName,CCAFlags _nProperty,bool _bAddType) |
387 | 0 | { |
388 | 0 | Any aAny = m_xProps->getPropertyValue(_sPropertyName); |
389 | |
|
390 | 0 | OUString sTargetLocation; |
391 | 0 | if (aAny.has<uno::Reference<graphic::XGraphic>>()) |
392 | 0 | { |
393 | 0 | auto xGraphic = aAny.get<uno::Reference<graphic::XGraphic>>(); |
394 | 0 | OUString sOutMimeType; |
395 | 0 | sTargetLocation = m_rContext.getGlobalContext().AddEmbeddedXGraphic(xGraphic, sOutMimeType); |
396 | 0 | } |
397 | 0 | else if (aAny.has<OUString>()) |
398 | 0 | { |
399 | 0 | auto sURL = aAny.get<OUString>(); |
400 | 0 | sTargetLocation = m_rContext.getGlobalContext().AddEmbeddedObject(sURL); |
401 | 0 | } |
402 | 0 | else |
403 | 0 | { |
404 | 0 | SAL_WARN("xmloff.forms", "OPropertyExport::exportRelativeTargetLocation: " |
405 | 0 | "Value of " << _sPropertyName << " not found!"); |
406 | 0 | } |
407 | | |
408 | 0 | if (!sTargetLocation.isEmpty()) |
409 | 0 | { |
410 | 0 | AddAttribute(OAttributeMetaData::getCommonControlAttributeNamespace(_nProperty) |
411 | 0 | ,OAttributeMetaData::getCommonControlAttributeName(_nProperty) |
412 | 0 | , sTargetLocation); |
413 | | |
414 | | // #i110911# add xlink:type="simple" if required |
415 | 0 | if (_bAddType) |
416 | 0 | AddAttribute(XML_NAMESPACE_XLINK, token::XML_TYPE, token::XML_SIMPLE); |
417 | |
|
418 | 0 | exportedProperty(_sPropertyName); |
419 | 0 | } |
420 | 0 | } |
421 | | void OPropertyExport::flagStyleProperties() |
422 | 0 | { |
423 | | // flag all the properties which are part of the style as "handled" |
424 | 0 | rtl::Reference< XMLPropertySetMapper > xStylePropertiesSupplier = m_rContext.getStylePropertyMapper()->getPropertySetMapper(); |
425 | 0 | for (sal_Int32 i=0; i<xStylePropertiesSupplier->GetEntryCount(); ++i) |
426 | 0 | exportedProperty(xStylePropertiesSupplier->GetEntryAPIName(i)); |
427 | | |
428 | | // the font properties are exported as single properties, but there is a FontDescriptor property which |
429 | | // collects them all-in-one, this has been exported implicitly |
430 | 0 | exportedProperty(PROPERTY_FONT); |
431 | | |
432 | | // for the DateFormat and TimeFormat, there exist wrapper properties which has been exported as |
433 | | // style, too |
434 | 0 | exportedProperty(PROPERTY_DATEFORMAT); |
435 | 0 | exportedProperty(PROPERTY_TIMEFORMAT); |
436 | | |
437 | | // the following properties should have been exported at the shape already: |
438 | 0 | exportedProperty( u"VerticalAlign"_ustr ); |
439 | 0 | exportedProperty( u"WritingMode"_ustr ); |
440 | 0 | exportedProperty( u"ScaleMode"_ustr ); |
441 | | // ditto the TextWritingMode |
442 | 0 | exportedProperty( u"WritingMode"_ustr ); |
443 | 0 | } |
444 | | |
445 | | void OPropertyExport::exportGenericPropertyAttribute( |
446 | | const sal_uInt16 _nAttributeNamespaceKey, const OUString& _pAttributeName, const OUString& sPropertyName) |
447 | 0 | { |
448 | 0 | DBG_CHECK_PROPERTY_NO_TYPE( sPropertyName ); |
449 | |
|
450 | 0 | exportedProperty(sPropertyName); |
451 | |
|
452 | 0 | Any aCurrentValue = m_xProps->getPropertyValue(sPropertyName); |
453 | 0 | if (!aCurrentValue.hasValue()) |
454 | | // nothing to do without a concrete value |
455 | 0 | return; |
456 | | |
457 | 0 | OUString sValue = implConvertAny(aCurrentValue); |
458 | 0 | if (sValue.isEmpty() && (TypeClass_STRING == aCurrentValue.getValueTypeClass())) |
459 | 0 | { |
460 | | // check whether or not the property is allowed to be VOID |
461 | 0 | Property aProperty = m_xPropertyInfo->getPropertyByName(sPropertyName); |
462 | 0 | if ((aProperty.Attributes & PropertyAttribute::MAYBEVOID) == 0) |
463 | | // the string is empty, and the property is not allowed to be void |
464 | | // -> don't need to write the attribute, 'cause missing it is unambiguous |
465 | 0 | return; |
466 | 0 | } |
467 | | |
468 | | // finally add the attribute to the context |
469 | 0 | AddAttribute(_nAttributeNamespaceKey, _pAttributeName, sValue); |
470 | 0 | } |
471 | | |
472 | | void OPropertyExport::exportStringSequenceAttribute(const sal_uInt16 _nAttributeNamespaceKey, const OUString& _pAttributeName, |
473 | | const OUString& _rPropertyName) |
474 | 0 | { |
475 | 0 | const sal_Unicode _aListSeparator = ','; |
476 | 0 | const sal_Unicode _aQuoteCharacter = '"'; |
477 | 0 | DBG_CHECK_PROPERTY( _rPropertyName, Sequence< OUString > ); |
478 | |
|
479 | 0 | Sequence< OUString > aItems; |
480 | 0 | m_xProps->getPropertyValue( _rPropertyName ) >>= aItems; |
481 | |
|
482 | 0 | OUStringBuffer sFinalList; |
483 | | |
484 | | // unfortunately the OUString can't append single sal_Unicode characters ... |
485 | 0 | const OUString sQuote(&_aQuoteCharacter, 1); |
486 | 0 | const OUString sSeparator(&_aListSeparator, 1); |
487 | 0 | const bool bQuote = !sQuote.isEmpty(); |
488 | | |
489 | | // concatenate the string items |
490 | 0 | const OUString* pItems = aItems.getConstArray(); |
491 | 0 | const OUString* pEnd = pItems + aItems.getLength(); |
492 | 0 | const OUString* pLastElement = pEnd - 1; |
493 | 0 | for ( ; |
494 | 0 | pItems != pEnd; |
495 | 0 | ++pItems |
496 | 0 | ) |
497 | 0 | { |
498 | 0 | OSL_ENSURE(-1 == pItems->indexOf(_aQuoteCharacter), |
499 | 0 | "OPropertyExport::exportStringSequenceAttribute: there is an item which contains the quote character!"); |
500 | |
|
501 | 0 | if (bQuote) |
502 | 0 | sFinalList.append(sQuote); |
503 | 0 | sFinalList.append(*pItems); |
504 | 0 | if (bQuote) |
505 | 0 | sFinalList.append(sQuote); |
506 | |
|
507 | 0 | if (pItems != pLastElement) |
508 | 0 | sFinalList.append(sSeparator); |
509 | 0 | } |
510 | |
|
511 | 0 | if (!sFinalList.isEmpty()) |
512 | 0 | AddAttribute(_nAttributeNamespaceKey, _pAttributeName, sFinalList.makeStringAndClear()); |
513 | |
|
514 | 0 | exportedProperty( _rPropertyName ); |
515 | 0 | } |
516 | | |
517 | | OUString OPropertyExport::implConvertAny(const Any& _rValue) |
518 | 0 | { |
519 | 0 | OUStringBuffer aBuffer; |
520 | 0 | switch (_rValue.getValueTypeClass()) |
521 | 0 | { |
522 | 0 | case TypeClass_STRING: |
523 | 0 | { // extract the string |
524 | 0 | OUString sCurrentValue; |
525 | 0 | _rValue >>= sCurrentValue; |
526 | 0 | aBuffer.append(sCurrentValue); |
527 | 0 | } |
528 | 0 | break; |
529 | 0 | case TypeClass_DOUBLE: |
530 | | // let the unit converter format is as string |
531 | 0 | ::sax::Converter::convertDouble(aBuffer, getDouble(_rValue)); |
532 | 0 | break; |
533 | 0 | case TypeClass_BOOLEAN: |
534 | 0 | aBuffer = getBOOL(_rValue) ? m_sValueTrue : m_sValueFalse; |
535 | 0 | break; |
536 | 0 | case TypeClass_BYTE: |
537 | 0 | case TypeClass_UNSIGNED_SHORT: |
538 | 0 | case TypeClass_SHORT: |
539 | 0 | case TypeClass_LONG: |
540 | | // let the unit converter format is as string |
541 | 0 | aBuffer.append(getINT32(_rValue)); |
542 | 0 | break; |
543 | 0 | case TypeClass_UNSIGNED_LONG: |
544 | 0 | case TypeClass_HYPER: |
545 | 0 | aBuffer.append(getINT64(_rValue)); |
546 | 0 | break; |
547 | 0 | case TypeClass_UNSIGNED_HYPER: |
548 | 0 | aBuffer.append(static_cast<sal_Int64>(_rValue.get<sal_uInt64>())); |
549 | 0 | break; |
550 | 0 | case TypeClass_ENUM: |
551 | 0 | { |
552 | | // convert it into an int32 |
553 | 0 | sal_Int32 nValue = 0; |
554 | 0 | ::cppu::enum2int(nValue, _rValue); |
555 | 0 | aBuffer.append(nValue); |
556 | 0 | } |
557 | 0 | break; |
558 | 0 | default: |
559 | 0 | { // hmmm... what else do we know? |
560 | 0 | double fValue = 0; |
561 | 0 | css::util::Date aDate; |
562 | 0 | css::util::Time aTime; |
563 | 0 | css::util::DateTime aDateTime; |
564 | 0 | if (_rValue >>= aDate) |
565 | 0 | { |
566 | 0 | Date aToolsDate( Date::EMPTY ); |
567 | 0 | ::utl::typeConvert(aDate, aToolsDate); |
568 | 0 | fValue = aToolsDate.GetDate(); |
569 | 0 | } |
570 | 0 | else if (_rValue >>= aTime) |
571 | 0 | { |
572 | 0 | fValue = aTime.Hours / static_cast<double>(::tools::Time::hourPerDay) + |
573 | 0 | aTime.Minutes / static_cast<double>(::tools::Time::minutePerDay) + |
574 | 0 | aTime.Seconds / static_cast<double>(::tools::Time::secondPerDay) + |
575 | 0 | aTime.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerDay); |
576 | 0 | } |
577 | 0 | else if (_rValue >>= aDateTime) |
578 | 0 | { |
579 | 0 | DateTime aToolsDateTime( DateTime::EMPTY ); |
580 | 0 | ::utl::typeConvert(aDateTime, aToolsDateTime); |
581 | | // the time part (the digits behind the comma) |
582 | 0 | fValue = aTime.Hours / static_cast<double>(::tools::Time::hourPerDay) + |
583 | 0 | aTime.Minutes / static_cast<double>(::tools::Time::minutePerDay) + |
584 | 0 | aTime.Seconds / static_cast<double>(::tools::Time::secondPerDay) + |
585 | 0 | aTime.NanoSeconds / static_cast<double>(::tools::Time::nanoSecPerDay); |
586 | | // plus the data part (the digits in front of the comma) |
587 | 0 | fValue += aToolsDateTime.GetDate(); |
588 | 0 | } |
589 | 0 | else |
590 | 0 | { |
591 | | // if any other types are added here, please remember to adjust implGetPropertyXMLType accordingly |
592 | | |
593 | | // no more options ... |
594 | 0 | OSL_FAIL("OPropertyExport::implConvertAny: unsupported value type!"); |
595 | 0 | break; |
596 | 0 | } |
597 | | // let the unit converter format is as string |
598 | 0 | ::sax::Converter::convertDouble(aBuffer, fValue); |
599 | 0 | } |
600 | 0 | break; |
601 | 0 | } |
602 | | |
603 | 0 | return aBuffer.makeStringAndClear(); |
604 | 0 | } |
605 | | |
606 | | token::XMLTokenEnum OPropertyExport::implGetPropertyXMLType(const css::uno::Type& _rType) |
607 | 0 | { |
608 | | // handle the type description |
609 | 0 | switch (_rType.getTypeClass()) |
610 | 0 | { |
611 | 0 | case TypeClass_STRING: |
612 | 0 | return token::XML_STRING; |
613 | 0 | case TypeClass_DOUBLE: |
614 | 0 | case TypeClass_BYTE: |
615 | 0 | case TypeClass_SHORT: |
616 | 0 | case TypeClass_LONG: |
617 | 0 | case TypeClass_HYPER: |
618 | 0 | case TypeClass_ENUM: |
619 | 0 | return token::XML_FLOAT; |
620 | 0 | case TypeClass_BOOLEAN: |
621 | 0 | return token::XML_BOOLEAN; |
622 | | |
623 | 0 | default: |
624 | 0 | return token::XML_FLOAT; |
625 | 0 | } |
626 | 0 | } |
627 | | |
628 | | #ifdef DBG_UTIL |
629 | | void OPropertyExport::AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue ) |
630 | | { |
631 | | OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName( _rName ).isEmpty(), |
632 | | "OPropertyExport::AddAttribute: already have such an attribute"); |
633 | | |
634 | | m_rContext.getGlobalContext().AddAttribute( _nPrefix, _rName, _rValue ); |
635 | | } |
636 | | |
637 | | void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue) |
638 | | { |
639 | | OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).isEmpty(), |
640 | | "OPropertyExport::AddAttribute: already have such an attribute"); |
641 | | |
642 | | m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _rValue); |
643 | | } |
644 | | |
645 | | void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue ) |
646 | | { |
647 | | OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).isEmpty(), |
648 | | "OPropertyExport::AddAttribute: already have such an attribute"); |
649 | | |
650 | | m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _eValue); |
651 | | } |
652 | | |
653 | | void OPropertyExport::dbg_implCheckProperty(const OUString& _rPropertyName, const Type* _pType) |
654 | | { |
655 | | try |
656 | | { |
657 | | // the property must exist |
658 | | if (!m_xPropertyInfo->hasPropertyByName(_rPropertyName)) |
659 | | { |
660 | | SAL_WARN("xmloff.forms", "OPropertyExport: " |
661 | | "no property with the name " + _rPropertyName + "!"); |
662 | | return; |
663 | | } |
664 | | |
665 | | if (_pType) |
666 | | { |
667 | | // and it must have the correct type |
668 | | Property aPropertyDescription = m_xPropertyInfo->getPropertyByName(_rPropertyName); |
669 | | OSL_ENSURE(aPropertyDescription.Type.equals(*_pType), "OPropertyExport::dbg_implCheckProperty: invalid property type!"); |
670 | | } |
671 | | } |
672 | | catch(Exception&) |
673 | | { |
674 | | TOOLS_WARN_EXCEPTION("xmloff.forms", "could not check the property!"); |
675 | | } |
676 | | } |
677 | | #endif // DBG_UTIL - dbg_implCheckProperty |
678 | | |
679 | | } // namespace xmloff |
680 | | |
681 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |