/src/libreoffice/xmloff/source/transform/StyleOOoTContext.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 <com/sun/star/xml/sax/XDocumentHandler.hpp> |
21 | | |
22 | | #include <sax/tools/converter.hxx> |
23 | | |
24 | | #include <xmloff/namespacemap.hxx> |
25 | | #include <xmloff/xmltoken.hxx> |
26 | | #include <xmloff/xmlnamespace.hxx> |
27 | | #include "PropType.hxx" |
28 | | #include "DeepTContext.hxx" |
29 | | #include "RenameElemTContext.hxx" |
30 | | #include "ActionMapTypesOOo.hxx" |
31 | | #include "MutableAttrList.hxx" |
32 | | #include "TransformerActions.hxx" |
33 | | #include "PropertyActionsOOo.hxx" |
34 | | #include "TransformerBase.hxx" |
35 | | |
36 | | #include "StyleOOoTContext.hxx" |
37 | | #include <xmloff/xmluconv.hxx> |
38 | | #include <rtl/math.hxx> |
39 | | #include <rtl/ustrbuf.hxx> |
40 | | #include <osl/diagnose.h> |
41 | | #include <sal/log.hxx> |
42 | | #include <array> |
43 | | |
44 | | using namespace ::xmloff::token; |
45 | | using namespace ::com::sun::star::uno; |
46 | | using namespace ::com::sun::star::xml::sax; |
47 | | |
48 | | const sal_uInt16 MAX_PROP_TYPES = 4; |
49 | | #define ENTRY4(a,b,c,d) \ |
50 | | { a, b, c, d } |
51 | | #define ENTRY3(a,b,c) \ |
52 | | { a, b, c, XML_PROP_TYPE_END } |
53 | | #define ENTRY2(a,b) \ |
54 | | { a, b, XML_PROP_TYPE_END, XML_PROP_TYPE_END } |
55 | | #define ENTRY1(a) \ |
56 | | { a, XML_PROP_TYPE_END, XML_PROP_TYPE_END, XML_PROP_TYPE_END } |
57 | | |
58 | | const std::array<XMLPropType,MAX_PROP_TYPES> aPropTypes[XML_FAMILY_TYPE_END] = |
59 | | { |
60 | | ENTRY3( XML_PROP_TYPE_GRAPHIC, XML_PROP_TYPE_PARAGRAPH, XML_PROP_TYPE_TEXT ), // XML_FAMILY_TYPE_GRAPHIC, |
61 | | ENTRY3( XML_PROP_TYPE_GRAPHIC, XML_PROP_TYPE_PARAGRAPH, XML_PROP_TYPE_TEXT ), // XML_FAMILY_TYPE_PRESENTATION, |
62 | | ENTRY1( XML_PROP_TYPE_DRAWING_PAGE ), // XML_FAMILY_TYPE_DRAWING_PAGE, |
63 | | ENTRY1( XML_PROP_TYPE_END ), // XML_FAMILY_TYPE_MASTER_PAGE |
64 | | ENTRY1( XML_PROP_TYPE_PAGE_LAYOUT ), // XML_FAMILY_TYPE_PAGE_LAYOUT, |
65 | | ENTRY1( XML_PROP_TYPE_HEADER_FOOTER ), // XML_FAMILY_TYPE_HEADER_FOOTER |
66 | | ENTRY1( XML_PROP_TYPE_TEXT ), // XML_FAMILY_TYPE_TEXT, |
67 | | ENTRY2( XML_PROP_TYPE_PARAGRAPH, XML_PROP_TYPE_TEXT ), // XML_FAMILY_TYPE_PARAGRAPH, |
68 | | ENTRY1( XML_PROP_TYPE_RUBY ), // XML_FAMILY_TYPE_RUBY, |
69 | | ENTRY1( XML_PROP_TYPE_SECTION ), // XML_FAMILY_TYPE_SECTION, |
70 | | ENTRY1( XML_PROP_TYPE_TABLE ), // XML_FAMILY_TYPE_TABLE, |
71 | | ENTRY1( XML_PROP_TYPE_TABLE_COLUMN ), // XML_FAMILY_TYPE_TABLE_COLUMN, |
72 | | ENTRY1( XML_PROP_TYPE_TABLE_ROW ), // XML_FAMILY_TYPE_TABLE_ROW, |
73 | | ENTRY3( XML_PROP_TYPE_TABLE_CELL, XML_PROP_TYPE_PARAGRAPH, XML_PROP_TYPE_TEXT ), // XML_FAMILY_TYPE_TABLE_CELL, |
74 | | ENTRY1( XML_PROP_TYPE_LIST_LEVEL ), // XML_FAMILY_TYPE_LIST, |
75 | | ENTRY4( XML_PROP_TYPE_CHART, XML_PROP_TYPE_GRAPHIC, XML_PROP_TYPE_PARAGRAPH, XML_PROP_TYPE_TEXT ), // XML_FAMILY_TYPE_CHART, |
76 | | ENTRY1( XML_PROP_TYPE_TEXT ), // XML_FAMILY_TYPE_DATA, |
77 | | ENTRY1( XML_PROP_TYPE_END ), // XML_FAMILY_TYPE_GRADIENT, |
78 | | ENTRY1( XML_PROP_TYPE_END ), // XML_FAMILY_TYPE_HATCH, |
79 | | ENTRY1( XML_PROP_TYPE_END ), // XML_FAMILY_TYPE_FILL_IMAGE, |
80 | | ENTRY1( XML_PROP_TYPE_END ), // XML_FAMILY_TYPE_STROKE_DASH, |
81 | | ENTRY1( XML_PROP_TYPE_END ), // XML_FAMILY_TYPE_MARKER, |
82 | | }; |
83 | | |
84 | | const XMLTokenEnum aPropTokens[XML_PROP_TYPE_END] = |
85 | | { |
86 | | XML_GRAPHIC_PROPERTIES, |
87 | | XML_DRAWING_PAGE_PROPERTIES, |
88 | | XML_PAGE_LAYOUT_PROPERTIES, |
89 | | XML_HEADER_FOOTER_PROPERTIES, |
90 | | XML_TEXT_PROPERTIES, |
91 | | XML_PARAGRAPH_PROPERTIES, |
92 | | XML_RUBY_PROPERTIES, |
93 | | XML_SECTION_PROPERTIES, |
94 | | XML_TABLE_PROPERTIES, |
95 | | XML_TABLE_COLUMN_PROPERTIES, |
96 | | XML_TABLE_ROW_PROPERTIES, |
97 | | XML_TABLE_CELL_PROPERTIES, |
98 | | XML_LIST_LEVEL_PROPERTIES, |
99 | | XML_CHART_PROPERTIES |
100 | | }; |
101 | | |
102 | | const sal_uInt16 aAttrActionMaps[XML_PROP_TYPE_END] = |
103 | | { |
104 | | PROP_OOO_GRAPHIC_ATTR_ACTIONS, |
105 | | PROP_OOO_DRAWING_PAGE_ATTR_ACTIONS, // DRAWING_PAGE |
106 | | PROP_OOO_PAGE_LAYOUT_ATTR_ACTIONS, |
107 | | PROP_OOO_HEADER_FOOTER_ATTR_ACTIONS, |
108 | | PROP_OOO_TEXT_ATTR_ACTIONS, |
109 | | PROP_OOO_PARAGRAPH_ATTR_ACTIONS, |
110 | | MAX_OOO_PROP_ACTIONS, // RUBY |
111 | | PROP_OOO_SECTION_ATTR_ACTIONS, |
112 | | PROP_OOO_TABLE_ATTR_ACTIONS, |
113 | | PROP_OOO_TABLE_COLUMN_ATTR_ACTIONS, |
114 | | PROP_OOO_TABLE_ROW_ATTR_ACTIONS, |
115 | | PROP_OOO_TABLE_CELL_ATTR_ACTIONS, |
116 | | PROP_OOO_LIST_LEVEL_ATTR_ACTIONS, |
117 | | PROP_OOO_CHART_ATTR_ACTIONS |
118 | | }; |
119 | | |
120 | | const sal_uInt16 aElemActionMaps[XML_PROP_TYPE_END] = |
121 | | { |
122 | | PROP_OOO_GRAPHIC_ELEM_ACTIONS, |
123 | | MAX_OOO_PROP_ACTIONS, |
124 | | MAX_OOO_PROP_ACTIONS, |
125 | | MAX_OOO_PROP_ACTIONS, |
126 | | PROP_OOO_TEXT_ELEM_ACTIONS, |
127 | | PROP_OOO_PARAGRAPH_ELEM_ACTIONS, |
128 | | MAX_OOO_PROP_ACTIONS, |
129 | | MAX_OOO_PROP_ACTIONS, |
130 | | MAX_OOO_PROP_ACTIONS, |
131 | | MAX_OOO_PROP_ACTIONS, |
132 | | MAX_OOO_PROP_ACTIONS, |
133 | | PROP_OOO_TABLE_CELL_ELEM_ACTIONS, |
134 | | MAX_OOO_PROP_ACTIONS, |
135 | | PROP_OOO_CHART_ELEM_ACTIONS |
136 | | }; |
137 | | |
138 | | namespace { |
139 | | |
140 | | class XMLTypedPropertiesOOoTContext_Impl : public XMLPersElemContentTContext |
141 | | { |
142 | | css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList; |
143 | | |
144 | | public: |
145 | | XMLTypedPropertiesOOoTContext_Impl( XMLTransformerBase& rTransformer, |
146 | | const OUString& rQName ); |
147 | | |
148 | | using XMLPersAttrListTContext::AddAttribute; |
149 | | void AddAttribute( const OUString &sName , |
150 | | const OUString &sValue ); |
151 | | void AddAttribute( sal_uInt16 nPrefix, XMLTokenEnum eToken, |
152 | | const OUString &sValue ); |
153 | | |
154 | | virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& rAttrList ) override; |
155 | | |
156 | | virtual void Export() override; |
157 | | }; |
158 | | |
159 | | } |
160 | | |
161 | | XMLTypedPropertiesOOoTContext_Impl::XMLTypedPropertiesOOoTContext_Impl( |
162 | | XMLTransformerBase& rImp, |
163 | | const OUString& rQName ) : |
164 | 0 | XMLPersElemContentTContext( rImp, rQName ), |
165 | 0 | m_xAttrList( new XMLMutableAttributeList() ) |
166 | 0 | { |
167 | 0 | } |
168 | | |
169 | | void XMLTypedPropertiesOOoTContext_Impl::AddAttribute( |
170 | | const OUString &sName , |
171 | | const OUString &sValue ) |
172 | 0 | { |
173 | 0 | static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) |
174 | 0 | ->AddAttribute( sName, sValue ); |
175 | 0 | } |
176 | | |
177 | | void XMLTypedPropertiesOOoTContext_Impl::AddAttribute( |
178 | | sal_uInt16 nPrefix, XMLTokenEnum eToken, |
179 | | const OUString &sValue ) |
180 | 0 | { |
181 | 0 | OUString sName( |
182 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
183 | 0 | nPrefix, ::xmloff::token::GetXMLToken( eToken ) ) ); |
184 | 0 | static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) |
185 | 0 | ->AddAttribute( sName, sValue ); |
186 | 0 | } |
187 | | |
188 | | void XMLTypedPropertiesOOoTContext_Impl::StartElement( |
189 | | const Reference< XAttributeList >& ) |
190 | 0 | { |
191 | | // empty, ignore even the attribute list |
192 | 0 | } |
193 | | |
194 | | void XMLTypedPropertiesOOoTContext_Impl::Export() |
195 | 0 | { |
196 | 0 | if( m_xAttrList->getLength() || HasElementContent() ) |
197 | 0 | { |
198 | 0 | GetTransformer().GetDocHandler()->startElement( GetQName(), m_xAttrList ); |
199 | 0 | ExportContent(); |
200 | 0 | GetTransformer().GetDocHandler()->endElement( GetQName() ); |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | | namespace { |
205 | | |
206 | | class XMLPropertiesOOoTContext_Impl : public XMLTransformerContext |
207 | | { |
208 | | ::rtl::Reference < XMLTypedPropertiesOOoTContext_Impl > |
209 | | m_aPropContexts[MAX_PROP_TYPES]; |
210 | | |
211 | | using XMLPropTypes = std::array<XMLPropType, MAX_PROP_TYPES>; |
212 | | |
213 | | XMLPropTypes const & m_rPropTypes; |
214 | | |
215 | | bool const m_bPersistent; |
216 | | |
217 | | XMLTypedPropertiesOOoTContext_Impl *GetPropContextAndAction( |
218 | | TransformerAction_Impl& rAction, |
219 | | sal_uInt16 nPrefix, const OUString& rLocalName, |
220 | | bool bElem ); |
221 | | |
222 | | XMLTypedPropertiesOOoTContext_Impl *GetPropContext( |
223 | | XMLPropType eType ); |
224 | | |
225 | | public: |
226 | | XMLPropertiesOOoTContext_Impl( XMLTransformerBase& rTransformer, |
227 | | const OUString& rQName, |
228 | | const XMLPropTypes& rTypes, |
229 | | bool bPersistent ); |
230 | | |
231 | | rtl::Reference<XMLTransformerContext> CreateChildContext( |
232 | | sal_uInt16 nPrefix, |
233 | | const OUString& rLocalName, |
234 | | const OUString& rQName, |
235 | | const Reference< XAttributeList >& rAttrList ) override; |
236 | | |
237 | | virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& rAttrList ) override; |
238 | | |
239 | | virtual void EndElement() override; |
240 | | |
241 | | virtual void Characters( const OUString& rChars ) override; |
242 | | |
243 | | virtual void Export() override; |
244 | | |
245 | | virtual bool IsPersistent() const override; |
246 | | }; |
247 | | |
248 | | } |
249 | | |
250 | | XMLTypedPropertiesOOoTContext_Impl |
251 | | *XMLPropertiesOOoTContext_Impl::GetPropContext( |
252 | | XMLPropType eType ) |
253 | 0 | { |
254 | 0 | sal_uInt16 nIndex = MAX_PROP_TYPES; |
255 | 0 | for( sal_uInt16 i=0; i< MAX_PROP_TYPES; i++ ) |
256 | 0 | { |
257 | 0 | if( m_rPropTypes[i] == eType ) |
258 | 0 | { |
259 | 0 | nIndex = i; |
260 | 0 | break; |
261 | 0 | } |
262 | 0 | } |
263 | 0 | if( MAX_PROP_TYPES == nIndex ) |
264 | 0 | return nullptr; |
265 | | |
266 | 0 | if( !m_aPropContexts[nIndex].is() ) |
267 | 0 | { |
268 | 0 | m_aPropContexts[nIndex] = |
269 | 0 | new XMLTypedPropertiesOOoTContext_Impl( |
270 | 0 | GetTransformer(), |
271 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
272 | 0 | XML_NAMESPACE_STYLE, |
273 | 0 | ::xmloff::token::GetXMLToken( |
274 | 0 | aPropTokens[m_rPropTypes[nIndex]] ) )); |
275 | 0 | } |
276 | |
|
277 | 0 | return m_aPropContexts[nIndex].get(); |
278 | 0 | } |
279 | | |
280 | | XMLTypedPropertiesOOoTContext_Impl |
281 | | *XMLPropertiesOOoTContext_Impl::GetPropContextAndAction( |
282 | | TransformerAction_Impl& rAction, |
283 | | sal_uInt16 nPrefix, const OUString& rLocalName, |
284 | | bool bElem ) |
285 | 0 | { |
286 | 0 | rAction.m_nActionType = XML_ATACTION_COPY; |
287 | 0 | sal_uInt16 nIndex = 0; |
288 | |
|
289 | 0 | XMLTransformerActions::key_type aKey( nPrefix, rLocalName ); |
290 | 0 | sal_uInt16 i=0; |
291 | 0 | while( i < MAX_PROP_TYPES && XML_PROP_TYPE_END!=m_rPropTypes[i]) |
292 | 0 | { |
293 | 0 | sal_uInt16 nActionMap = |
294 | 0 | (bElem ? aElemActionMaps : aAttrActionMaps)[m_rPropTypes[i]]; |
295 | 0 | if( nActionMap < MAX_OOO_PROP_ACTIONS ) |
296 | 0 | { |
297 | 0 | XMLTransformerActions *pActions = |
298 | 0 | GetTransformer().GetUserDefinedActions( nActionMap ); |
299 | 0 | OSL_ENSURE( pActions, "go no actions" ); |
300 | 0 | if( pActions ) |
301 | 0 | { |
302 | 0 | XMLTransformerActions::const_iterator aIter = |
303 | 0 | pActions->find( aKey ); |
304 | |
|
305 | 0 | if( aIter != pActions->end() ) |
306 | 0 | { |
307 | 0 | rAction = (*aIter).second; |
308 | 0 | nIndex = i; |
309 | 0 | break; |
310 | 0 | } |
311 | 0 | } |
312 | 0 | } |
313 | 0 | ++i; |
314 | 0 | } |
315 | |
|
316 | | #ifdef DBG_UTIL |
317 | | if( !( XML_NAMESPACE_NONE == nPrefix || |
318 | | (XML_NAMESPACE_UNKNOWN_FLAG & nPrefix) || |
319 | | XML_PROP_TYPE_END==m_rPropTypes[1] || |
320 | | (i<MAX_PROP_TYPES && XML_PROP_TYPE_END!=m_rPropTypes[i]) ) ) |
321 | | { |
322 | | SAL_WARN("xmloff", "Didn't find property: " |
323 | | << GetTransformer().GetNamespaceMap().GetPrefixByKey( nPrefix ) |
324 | | << ":" |
325 | | << rLocalName |
326 | | << ", assuming <style:" |
327 | | << ::xmloff::token::GetXMLToken( aPropTokens[m_rPropTypes[0]] ) |
328 | | << ">" ); |
329 | | } |
330 | | #endif |
331 | |
|
332 | 0 | if( !m_aPropContexts[nIndex].is() ) |
333 | 0 | { |
334 | 0 | m_aPropContexts[nIndex] = |
335 | 0 | new XMLTypedPropertiesOOoTContext_Impl( |
336 | 0 | GetTransformer(), |
337 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
338 | 0 | XML_NAMESPACE_STYLE, |
339 | 0 | ::xmloff::token::GetXMLToken( |
340 | 0 | aPropTokens[m_rPropTypes[nIndex]] ) )); |
341 | 0 | } |
342 | |
|
343 | 0 | return m_aPropContexts[nIndex].get(); |
344 | 0 | } |
345 | | |
346 | | XMLPropertiesOOoTContext_Impl::XMLPropertiesOOoTContext_Impl( |
347 | | XMLTransformerBase& rImp, |
348 | | const OUString& rQName, |
349 | | const XMLPropTypes& rTypes, |
350 | | bool bPersistent ) : |
351 | 0 | XMLTransformerContext( rImp, rQName ), |
352 | | // remember the types that belong to the attribute and element lists |
353 | 0 | m_rPropTypes(rTypes), |
354 | 0 | m_bPersistent( bPersistent ) |
355 | 0 | { |
356 | 0 | } |
357 | | |
358 | | rtl::Reference<XMLTransformerContext> XMLPropertiesOOoTContext_Impl::CreateChildContext( |
359 | | sal_uInt16 nPrefix, |
360 | | const OUString& rLocalName, |
361 | | const OUString& rQName, |
362 | | const Reference< XAttributeList >& rAttrList ) |
363 | 0 | { |
364 | 0 | TransformerAction_Impl aAction; |
365 | 0 | return GetPropContextAndAction( aAction, nPrefix, rLocalName, true ) |
366 | 0 | ->CreateChildContext( nPrefix, rLocalName, rQName, rAttrList ); |
367 | 0 | } |
368 | | |
369 | | void XMLPropertiesOOoTContext_Impl::StartElement( |
370 | | const Reference< XAttributeList >& rAttrList ) |
371 | 0 | { |
372 | 0 | XMLTypedPropertiesOOoTContext_Impl * pIntervalMinorDivisorContext = nullptr; |
373 | 0 | double fIntervalMajor = 0.0; |
374 | 0 | double fIntervalMinor = 0.0; |
375 | 0 | bool bMoveProtect = false; |
376 | 0 | bool bSizeProtect = false; |
377 | 0 | OUString aProtectAttrValue; |
378 | 0 | XMLTypedPropertiesOOoTContext_Impl * pProtectContext = nullptr; |
379 | | |
380 | | /* Attribute <style:mirror> has to be priority over attribute <style:draw>. |
381 | | The filter from OpenDocument file format to OpenOffice.org file format |
382 | | produces styles with both attributes. (#i49139#) |
383 | | */ |
384 | 0 | bool bExistStyleMirror( false ); |
385 | 0 | OUStringBuffer aStyleMirrorAttrValue; |
386 | 0 | bool bExistDrawMirror( false ); |
387 | 0 | OUString aDrawMirrorAttrValue; |
388 | 0 | XMLTypedPropertiesOOoTContext_Impl* pMirrorContext( nullptr ); |
389 | |
|
390 | 0 | sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; |
391 | 0 | for( sal_Int16 i=0; i < nAttrCount; i++ ) |
392 | 0 | { |
393 | 0 | const OUString sAttrName = rAttrList->getNameByIndex( i ); |
394 | 0 | const OUString sAttrValue = rAttrList->getValueByIndex( i ); |
395 | 0 | OUString aLocalName; |
396 | 0 | sal_uInt16 nPrefix = |
397 | 0 | GetTransformer().GetNamespaceMap().GetKeyByAttrName( sAttrName, |
398 | 0 | &aLocalName ); |
399 | 0 | TransformerAction_Impl aAction; |
400 | 0 | XMLTypedPropertiesOOoTContext_Impl *pContext = |
401 | 0 | GetPropContextAndAction( aAction, nPrefix, aLocalName, false ); |
402 | 0 | switch( aAction.m_nActionType ) |
403 | 0 | { |
404 | 0 | case XML_ATACTION_REMOVE: |
405 | 0 | break; |
406 | 0 | case XML_ATACTION_COPY: |
407 | 0 | pContext->AddAttribute( sAttrName, sAttrValue ); |
408 | 0 | break; |
409 | 0 | case XML_ATACTION_COPY_DUPLICATE: |
410 | 0 | { |
411 | 0 | pContext->AddAttribute( sAttrName, sAttrValue ); |
412 | 0 | XMLTypedPropertiesOOoTContext_Impl *pContext2 = |
413 | 0 | GetPropContext( static_cast<XMLPropType>(aAction.m_nParam1) ); |
414 | 0 | if( pContext2 ) |
415 | 0 | pContext2->AddAttribute( sAttrName, sAttrValue ); |
416 | 0 | } |
417 | 0 | break; |
418 | 0 | case XML_ATACTION_RENAME: |
419 | 0 | { |
420 | 0 | pContext->AddAttribute( aAction.GetQNamePrefixFromParam1(), |
421 | 0 | aAction.GetQNameTokenFromParam1(), |
422 | 0 | sAttrValue ); |
423 | 0 | } |
424 | 0 | break; |
425 | 0 | case XML_ATACTION_ENCODE_STYLE_NAME_REF: |
426 | 0 | { |
427 | 0 | OUString aAttrValue( sAttrValue ); |
428 | 0 | GetTransformer().EncodeStyleName(aAttrValue); |
429 | 0 | pContext->AddAttribute( sAttrName, aAttrValue ); |
430 | 0 | } |
431 | 0 | break; |
432 | 0 | case XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF: |
433 | 0 | { |
434 | 0 | OUString aAttrValue( sAttrValue ); |
435 | 0 | GetTransformer().EncodeStyleName(aAttrValue); |
436 | 0 | pContext->AddAttribute( aAction.GetQNamePrefixFromParam1(), |
437 | 0 | aAction.GetQNameTokenFromParam1(), |
438 | 0 | aAttrValue ); |
439 | 0 | } |
440 | 0 | break; |
441 | 0 | case XML_ATACTION_NEG_PERCENT: |
442 | 0 | { |
443 | 0 | OUString aAttrValue( sAttrValue ); |
444 | 0 | XMLTransformerBase::NegPercent(aAttrValue); |
445 | 0 | pContext->AddAttribute( sAttrName, aAttrValue ); |
446 | 0 | } |
447 | 0 | break; |
448 | 0 | case XML_ATACTION_RENAME_NEG_PERCENT: |
449 | 0 | { |
450 | 0 | OUString aAttrValue( sAttrValue ); |
451 | 0 | XMLTransformerBase::NegPercent(aAttrValue); |
452 | 0 | pContext->AddAttribute( aAction.GetQNamePrefixFromParam1(), |
453 | 0 | aAction.GetQNameTokenFromParam1(), |
454 | 0 | aAttrValue ); |
455 | 0 | } |
456 | 0 | break; |
457 | 0 | case XML_ATACTION_INCH2IN: |
458 | 0 | { |
459 | 0 | OUString aAttrValue( sAttrValue ); |
460 | 0 | XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue ); |
461 | 0 | pContext->AddAttribute( sAttrName, aAttrValue ); |
462 | 0 | } |
463 | 0 | break; |
464 | 0 | case XML_ATACTION_INCH2IN_DUPLICATE: |
465 | 0 | { |
466 | 0 | OUString aAttrValue( sAttrValue ); |
467 | 0 | XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue ); |
468 | 0 | pContext->AddAttribute( sAttrName, aAttrValue ); |
469 | 0 | XMLTypedPropertiesOOoTContext_Impl *pContext2 = |
470 | 0 | GetPropContext( static_cast<XMLPropType>(aAction.m_nParam1) ); |
471 | 0 | if( pContext2 ) |
472 | 0 | pContext2->AddAttribute( sAttrName, aAttrValue ); |
473 | 0 | } |
474 | 0 | break; |
475 | 0 | case XML_ATACTION_INCHS2INS: |
476 | 0 | { |
477 | 0 | OUString aAttrValue( sAttrValue ); |
478 | 0 | XMLTransformerBase::ReplaceInchWithIn( aAttrValue ); |
479 | 0 | pContext->AddAttribute( sAttrName, aAttrValue ); |
480 | 0 | } |
481 | 0 | break; |
482 | 0 | case XML_PTACTION_LINE_MODE: |
483 | 0 | { |
484 | 0 | const OUString& aAttrValue( GetXMLToken( |
485 | 0 | IsXMLToken( sAttrValue, XML_TRUE ) |
486 | 0 | ? XML_CONTINUOUS |
487 | 0 | : XML_SKIP_WHITE_SPACE) ); |
488 | 0 | OUString aAttrQName( |
489 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
490 | 0 | XML_NAMESPACE_STYLE, |
491 | 0 | GetXMLToken( XML_TEXT_UNDERLINE_MODE ) ) ); |
492 | 0 | pContext->AddAttribute( aAttrQName, aAttrValue ); |
493 | |
|
494 | 0 | aAttrQName = |
495 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
496 | 0 | XML_NAMESPACE_STYLE, |
497 | 0 | GetXMLToken( XML_TEXT_LINE_THROUGH_MODE ) ); |
498 | 0 | pContext->AddAttribute( aAttrQName, aAttrValue ); |
499 | 0 | } |
500 | 0 | break; |
501 | 0 | case XML_PTACTION_KEEP_WITH_NEXT: |
502 | 0 | { |
503 | 0 | const OUString& aAttrValue( GetXMLToken( |
504 | 0 | IsXMLToken( sAttrValue, XML_TRUE ) |
505 | 0 | ? XML_ALWAYS |
506 | 0 | : XML_AUTO) ); |
507 | 0 | pContext->AddAttribute( sAttrName, aAttrValue ); |
508 | 0 | } |
509 | 0 | break; |
510 | 0 | case XML_PTACTION_UNDERLINE: |
511 | 0 | { |
512 | 0 | XMLTokenEnum eToken = GetTransformer().GetToken( sAttrValue ); |
513 | 0 | bool bBold = false, bDouble = false; |
514 | 0 | switch( eToken ) |
515 | 0 | { |
516 | 0 | case XML_SINGLE: |
517 | 0 | eToken = XML_SOLID; |
518 | 0 | break; |
519 | 0 | case XML_DOUBLE: |
520 | 0 | eToken = XML_SOLID; |
521 | 0 | bDouble = true; |
522 | 0 | break; |
523 | 0 | case XML_BOLD: |
524 | 0 | eToken = XML_SOLID; |
525 | 0 | bBold = true; |
526 | 0 | break; |
527 | 0 | case XML_BOLD_DOTTED: |
528 | 0 | eToken = XML_DOTTED; |
529 | 0 | bBold = true; |
530 | 0 | break; |
531 | 0 | case XML_BOLD_DASH: |
532 | 0 | eToken = XML_DASH; |
533 | 0 | bBold = true; |
534 | 0 | break; |
535 | 0 | case XML_BOLD_LONG_DASH: |
536 | 0 | eToken = XML_LONG_DASH; |
537 | 0 | bBold = true; |
538 | 0 | break; |
539 | 0 | case XML_BOLD_DOT_DASH: |
540 | 0 | eToken = XML_DOT_DASH; |
541 | 0 | bBold = true; |
542 | 0 | break; |
543 | 0 | case XML_BOLD_DOT_DOT_DASH: |
544 | 0 | eToken = XML_DOT_DOT_DASH; |
545 | 0 | bBold = true; |
546 | 0 | break; |
547 | 0 | case XML_BOLD_WAVE: |
548 | 0 | eToken = XML_WAVE; |
549 | 0 | bBold = true; |
550 | 0 | break; |
551 | 0 | case XML_DOUBLE_WAVE: |
552 | 0 | eToken = XML_WAVE; |
553 | 0 | bDouble = true; |
554 | 0 | break; |
555 | 0 | case XML_NONE: |
556 | 0 | eToken = XML_NONE; |
557 | 0 | bDouble = false; |
558 | 0 | break; |
559 | 0 | default: |
560 | 0 | OSL_FAIL( "xmloff::XMLPropertiesOOoTContext_Impl::StartElement(), unknown underline token!" ); |
561 | 0 | break; |
562 | 0 | } |
563 | 0 | pContext->AddAttribute( |
564 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
565 | 0 | XML_NAMESPACE_STYLE, |
566 | 0 | GetXMLToken( XML_TEXT_UNDERLINE_STYLE ) ), |
567 | 0 | eToken != XML_TOKEN_END ? GetXMLToken( eToken ) |
568 | 0 | : sAttrValue ); |
569 | 0 | if( bDouble ) |
570 | 0 | pContext->AddAttribute( |
571 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
572 | 0 | XML_NAMESPACE_STYLE, |
573 | 0 | GetXMLToken( XML_TEXT_UNDERLINE_TYPE ) ), |
574 | 0 | GetXMLToken( XML_DOUBLE ) ); |
575 | 0 | if( bBold ) |
576 | 0 | pContext->AddAttribute( |
577 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
578 | 0 | XML_NAMESPACE_STYLE, |
579 | 0 | GetXMLToken( XML_TEXT_UNDERLINE_WIDTH ) ), |
580 | 0 | GetXMLToken( XML_BOLD ) ); |
581 | 0 | } |
582 | 0 | break; |
583 | 0 | case XML_PTACTION_LINETHROUGH: |
584 | 0 | { |
585 | 0 | XMLTokenEnum eToken = GetTransformer().GetToken( sAttrValue ); |
586 | 0 | bool bBold = false, bDouble = false; |
587 | 0 | sal_Unicode c = 0; |
588 | 0 | switch( eToken ) |
589 | 0 | { |
590 | 0 | case XML_SINGLE_LINE: |
591 | 0 | eToken = XML_SOLID; |
592 | 0 | break; |
593 | 0 | case XML_DOUBLE_LINE: |
594 | 0 | eToken = XML_SOLID; |
595 | 0 | bDouble = true; |
596 | 0 | break; |
597 | 0 | case XML_THICK_LINE: |
598 | 0 | eToken = XML_SOLID; |
599 | 0 | bBold = true; |
600 | 0 | break; |
601 | 0 | case XML_SLASH: |
602 | 0 | eToken = XML_SOLID; |
603 | 0 | c = '/'; |
604 | 0 | break; |
605 | 0 | case XML_uX: |
606 | 0 | eToken = XML_SOLID; |
607 | 0 | c = 'X'; |
608 | 0 | break; |
609 | 0 | default: |
610 | 0 | break; |
611 | 0 | } |
612 | 0 | pContext->AddAttribute( |
613 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
614 | 0 | XML_NAMESPACE_STYLE, |
615 | 0 | GetXMLToken( XML_TEXT_LINE_THROUGH_STYLE ) ), |
616 | 0 | eToken != XML_TOKEN_END ? GetXMLToken( eToken ) |
617 | 0 | : sAttrValue ); |
618 | 0 | if( bDouble ) |
619 | 0 | pContext->AddAttribute( |
620 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
621 | 0 | XML_NAMESPACE_STYLE, |
622 | 0 | GetXMLToken( XML_TEXT_LINE_THROUGH_TYPE ) ), |
623 | 0 | GetXMLToken( XML_DOUBLE ) ); |
624 | 0 | if( bBold ) |
625 | 0 | pContext->AddAttribute( |
626 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
627 | 0 | XML_NAMESPACE_STYLE, |
628 | 0 | GetXMLToken( XML_TEXT_LINE_THROUGH_WIDTH ) ), |
629 | 0 | GetXMLToken( XML_BOLD ) ); |
630 | 0 | if( c ) |
631 | 0 | pContext->AddAttribute( |
632 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
633 | 0 | XML_NAMESPACE_STYLE, |
634 | 0 | GetXMLToken( XML_TEXT_LINE_THROUGH_TEXT ) ), |
635 | 0 | OUString( c ) ); |
636 | 0 | } |
637 | 0 | break; |
638 | 0 | case XML_PTACTION_SPLINES: |
639 | 0 | { |
640 | 0 | sal_Int32 nSplineType = sAttrValue.toInt32(); |
641 | 0 | OUString aNewAttrName = GetTransformer().GetNamespaceMap().GetQNameByKey( |
642 | 0 | XML_NAMESPACE_CHART, GetXMLToken( XML_INTERPOLATION ) ); |
643 | |
|
644 | 0 | switch( nSplineType ) |
645 | 0 | { |
646 | | // straight lines |
647 | 0 | case 0: |
648 | 0 | pContext->AddAttribute( |
649 | 0 | aNewAttrName, GetXMLToken( XML_NONE )); |
650 | 0 | break; |
651 | | // cubic spline |
652 | 0 | case 1: |
653 | 0 | pContext->AddAttribute( |
654 | 0 | aNewAttrName, GetXMLToken( XML_CUBIC_SPLINE )); |
655 | 0 | break; |
656 | | // B-spline |
657 | 0 | case 2: |
658 | 0 | pContext->AddAttribute( |
659 | 0 | aNewAttrName, GetXMLToken( XML_B_SPLINE )); |
660 | 0 | break; |
661 | | |
662 | 0 | default: |
663 | 0 | OSL_FAIL( "invalid spline type" ); |
664 | 0 | pContext->AddAttribute( |
665 | 0 | aNewAttrName, GetXMLToken( XML_NONE )); |
666 | 0 | break; |
667 | 0 | } |
668 | 0 | } |
669 | 0 | break; |
670 | 0 | case XML_PTACTION_INTERVAL_MAJOR: |
671 | 0 | pContext->AddAttribute( sAttrName, sAttrValue ); |
672 | 0 | ::sax::Converter::convertDouble( fIntervalMajor, sAttrValue ); |
673 | 0 | break; |
674 | 0 | case XML_PTACTION_INTERVAL_MINOR: |
675 | 0 | ::sax::Converter::convertDouble( fIntervalMinor, sAttrValue ); |
676 | 0 | pIntervalMinorDivisorContext = pContext; |
677 | 0 | break; |
678 | 0 | case XML_PTACTION_SYMBOL: |
679 | 0 | { |
680 | 0 | sal_Int32 nSymbolType = sAttrValue.toInt32(); |
681 | 0 | OUString aNewAttrName = GetTransformer().GetNamespaceMap().GetQNameByKey( |
682 | 0 | XML_NAMESPACE_CHART, GetXMLToken( XML_SYMBOL_TYPE ) ); |
683 | |
|
684 | 0 | if( nSymbolType >= 0 ) |
685 | 0 | { |
686 | 0 | pContext->AddAttribute( aNewAttrName, GetXMLToken( XML_NAMED_SYMBOL )); |
687 | 0 | enum XMLTokenEnum eToken = XML_TOKEN_INVALID; |
688 | 0 | switch( nSymbolType ) |
689 | 0 | { |
690 | | // SYMBOL0 |
691 | 0 | case 0: |
692 | | // "square" has an awkward token name |
693 | 0 | eToken = XML_GRADIENTSTYLE_SQUARE; |
694 | 0 | break; |
695 | | // SYMBOL1 |
696 | 0 | case 1: |
697 | 0 | eToken = XML_DIAMOND; |
698 | 0 | break; |
699 | | // SYMBOL2 |
700 | 0 | case 2: |
701 | 0 | eToken = XML_ARROW_DOWN; |
702 | 0 | break; |
703 | | // SYMBOL3 |
704 | 0 | case 3: |
705 | 0 | eToken = XML_ARROW_UP; |
706 | 0 | break; |
707 | | // SYMBOL4 |
708 | 0 | case 4: |
709 | 0 | eToken = XML_ARROW_RIGHT; |
710 | 0 | break; |
711 | | // SYMBOL5 |
712 | 0 | case 5: |
713 | 0 | eToken = XML_ARROW_LEFT; |
714 | 0 | break; |
715 | | // SYMBOL6 |
716 | 0 | case 6: |
717 | 0 | eToken = XML_BOW_TIE; |
718 | 0 | break; |
719 | | // SYMBOL7 |
720 | 0 | case 7: |
721 | 0 | eToken = XML_HOURGLASS; |
722 | 0 | break; |
723 | 0 | case 8: |
724 | 0 | eToken = XML_CIRCLE; |
725 | 0 | break; |
726 | 0 | case 9: |
727 | 0 | eToken = XML_STAR; |
728 | 0 | break; |
729 | 0 | case 10: |
730 | 0 | eToken = XML_X; |
731 | 0 | break; |
732 | 0 | case 11: |
733 | 0 | eToken = XML_PLUS; |
734 | 0 | break; |
735 | 0 | case 12: |
736 | 0 | eToken = XML_ASTERISK; |
737 | 0 | break; |
738 | 0 | case 13: |
739 | 0 | eToken = XML_HORIZONTAL_BAR; |
740 | 0 | break; |
741 | 0 | case 14: |
742 | 0 | eToken = XML_VERTICAL_BAR; |
743 | 0 | break; |
744 | 0 | default: |
745 | 0 | OSL_FAIL( "invalid named symbol" ); |
746 | 0 | break; |
747 | 0 | } |
748 | | |
749 | 0 | if( eToken != XML_TOKEN_INVALID ) |
750 | 0 | { |
751 | 0 | pContext->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey( |
752 | 0 | XML_NAMESPACE_CHART, GetXMLToken( XML_SYMBOL_NAME )), |
753 | 0 | GetXMLToken( eToken )); |
754 | 0 | } |
755 | 0 | } |
756 | 0 | else |
757 | 0 | { |
758 | 0 | switch( nSymbolType ) |
759 | 0 | { |
760 | | // NONE |
761 | 0 | case -3: |
762 | 0 | pContext->AddAttribute( |
763 | 0 | aNewAttrName, GetXMLToken( XML_NONE )); |
764 | 0 | break; |
765 | | // AUTO |
766 | 0 | case -2: |
767 | 0 | pContext->AddAttribute( |
768 | 0 | aNewAttrName, GetXMLToken( XML_AUTOMATIC )); |
769 | 0 | break; |
770 | | // BITMAPURL |
771 | 0 | case -1: |
772 | 0 | pContext->AddAttribute( |
773 | 0 | aNewAttrName, GetXMLToken( XML_IMAGE )); |
774 | 0 | break; |
775 | 0 | default: |
776 | 0 | OSL_FAIL( "invalid symbol type" ); |
777 | 0 | pContext->AddAttribute( |
778 | 0 | aNewAttrName, GetXMLToken( XML_NONE )); |
779 | 0 | break; |
780 | 0 | } |
781 | 0 | } |
782 | 0 | } |
783 | 0 | break; |
784 | 0 | case XML_PTACTION_SYMBOL_IMAGE_NAME: |
785 | 0 | { |
786 | | // create an xlink:href element for URI attribute |
787 | 0 | XMLPersAttrListTContext *pSymbolImageContext = new XMLPersAttrListTContext( |
788 | 0 | GetTransformer(), GetTransformer().GetNamespaceMap().GetQNameByKey( |
789 | 0 | XML_NAMESPACE_CHART, GetXMLToken( XML_SYMBOL_IMAGE ))); |
790 | 0 | rtl::Reference<XMLTransformerContext> xSymbolImageContext(pSymbolImageContext); |
791 | |
|
792 | 0 | OUString aAttrValue( sAttrValue ); |
793 | 0 | if( GetTransformer().ConvertURIToOASIS( aAttrValue, true )) |
794 | 0 | { |
795 | 0 | pSymbolImageContext->AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aAttrValue ); |
796 | 0 | pContext->AddContent(xSymbolImageContext); |
797 | 0 | } |
798 | 0 | } |
799 | 0 | break; |
800 | | |
801 | | // #i25616# |
802 | 0 | case XML_PTACTION_TRANSPARENCY : |
803 | 0 | { |
804 | 0 | OUString aAttrValue( sAttrValue ); |
805 | 0 | XMLTransformerBase::NegPercent(aAttrValue); |
806 | 0 | pContext->AddAttribute( XML_NAMESPACE_DRAW, |
807 | 0 | XML_OPACITY, |
808 | 0 | aAttrValue ); |
809 | 0 | pContext->AddAttribute( XML_NAMESPACE_DRAW, |
810 | 0 | XML_IMAGE_OPACITY, |
811 | 0 | aAttrValue ); |
812 | 0 | } |
813 | 0 | break; |
814 | | |
815 | 0 | case XML_PTACTION_BREAK_INSIDE: |
816 | 0 | { |
817 | 0 | pContext->AddAttribute( |
818 | 0 | XML_NAMESPACE_FO, XML_KEEP_TOGETHER, |
819 | 0 | GetXMLToken( |
820 | 0 | IsXMLToken( sAttrValue, XML_COLUMNSPLIT_AVOID ) |
821 | 0 | ? XML_ALWAYS |
822 | 0 | : XML_AUTO ) ); |
823 | 0 | } |
824 | 0 | break; |
825 | 0 | case XML_ATACTION_CAPTION_ESCAPE_OOO: |
826 | 0 | { |
827 | 0 | OUString aAttrValue( sAttrValue ); |
828 | 0 | if( aAttrValue.indexOf( '%' ) != -1 ) |
829 | 0 | { |
830 | 0 | sal_Int32 nValue = 0; |
831 | 0 | ::sax::Converter::convertPercent( nValue, sAttrValue ); |
832 | 0 | if( nValue ) |
833 | 0 | { |
834 | 0 | nValue /= 100; |
835 | 0 | OUStringBuffer aOut; |
836 | 0 | ::sax::Converter::convertPercent( aOut, nValue ); |
837 | 0 | aAttrValue = aOut.makeStringAndClear(); |
838 | 0 | } |
839 | 0 | } |
840 | 0 | else |
841 | 0 | { |
842 | 0 | XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue ); |
843 | 0 | } |
844 | |
|
845 | 0 | pContext->AddAttribute( sAttrName, aAttrValue ); |
846 | 0 | } |
847 | 0 | break; |
848 | 0 | case XML_ATACTION_MOVE_PROTECT: |
849 | 0 | bMoveProtect = IsXMLToken( sAttrValue, XML_TRUE ); |
850 | 0 | pProtectContext = pContext; |
851 | 0 | break; |
852 | 0 | case XML_ATACTION_SIZE_PROTECT: |
853 | 0 | bSizeProtect = IsXMLToken( sAttrValue, XML_TRUE ); |
854 | 0 | pProtectContext = pContext; |
855 | 0 | break; |
856 | 0 | case XML_ATACTION_PROTECT: |
857 | 0 | aProtectAttrValue = sAttrValue; |
858 | 0 | pProtectContext = pContext; |
859 | 0 | break; |
860 | 0 | case XML_ATACTION_DRAW_MIRROR_OOO: // renames draw:mirror to style:mirror and adapts values |
861 | 0 | { |
862 | | // OpenDocument file format: attribute value of <style:mirror> wrong (#i49139#) |
863 | 0 | aDrawMirrorAttrValue = |
864 | 0 | GetXMLToken( IsXMLToken( sAttrValue, XML_TRUE ) |
865 | 0 | ? XML_HORIZONTAL : XML_NONE ); |
866 | 0 | bExistDrawMirror = true; |
867 | 0 | pMirrorContext = pContext; |
868 | 0 | } |
869 | 0 | break; |
870 | | // OpenDocument file format: attribute value of <style:mirror> wrong (#i49139#) |
871 | 0 | case XML_ATACTION_STYLE_MIRROR_OOO: // adapts style:mirror values |
872 | 0 | { |
873 | 0 | SvXMLTokenEnumerator aTokenEnum( sAttrValue ); |
874 | 0 | std::u16string_view aToken; |
875 | 0 | while( aTokenEnum.getNextToken( aToken ) ) |
876 | 0 | { |
877 | 0 | if ( !aStyleMirrorAttrValue.isEmpty() ) |
878 | 0 | { |
879 | 0 | aStyleMirrorAttrValue.append(" "); |
880 | 0 | } |
881 | |
|
882 | 0 | if ( IsXMLToken( aToken, XML_HORIZONTAL_ON_LEFT_PAGES ) ) |
883 | 0 | { |
884 | 0 | aStyleMirrorAttrValue.append(GetXMLToken( XML_HORIZONTAL_ON_EVEN )); |
885 | 0 | } |
886 | 0 | else if ( IsXMLToken( aToken, XML_HORIZONTAL_ON_RIGHT_PAGES ) ) |
887 | 0 | { |
888 | 0 | aStyleMirrorAttrValue.append(GetXMLToken( XML_HORIZONTAL_ON_ODD )); |
889 | 0 | } |
890 | 0 | else |
891 | 0 | { |
892 | 0 | aStyleMirrorAttrValue.append(aToken); |
893 | 0 | } |
894 | 0 | } |
895 | 0 | bExistStyleMirror = true; |
896 | 0 | pMirrorContext = pContext; |
897 | 0 | } |
898 | 0 | break; |
899 | 0 | case XML_ATACTION_GAMMA_OOO: // converts double value to percentage |
900 | 0 | { |
901 | 0 | double fValue = sAttrValue.toDouble(); |
902 | 0 | sal_Int32 nValue = static_cast<sal_Int32>((fValue * 100.0) + ( fValue > 0 ? 0.5 : - 0.5 ) ); |
903 | |
|
904 | 0 | OUStringBuffer aOut; |
905 | 0 | ::sax::Converter::convertPercent( aOut, nValue ); |
906 | 0 | OUString aAttrValue( aOut.makeStringAndClear() ); |
907 | 0 | pContext->AddAttribute( sAttrName, aAttrValue ); |
908 | 0 | } |
909 | 0 | break; |
910 | 0 | case XML_ATACTION_OPACITY_FIX: |
911 | 0 | { |
912 | 0 | sal_Int32 nValue; |
913 | 0 | if( sAttrValue.indexOf( '%' ) != -1 ) |
914 | 0 | { |
915 | 0 | ::sax::Converter::convertPercent( nValue, sAttrValue ); |
916 | 0 | } |
917 | 0 | else |
918 | 0 | { |
919 | 0 | nValue = sal_Int32( sAttrValue.toDouble() * 100.0 ); |
920 | 0 | } |
921 | 0 | nValue = 100 - nValue; |
922 | |
|
923 | 0 | OUStringBuffer aOut; |
924 | 0 | ::sax::Converter::convertPercent( aOut, nValue ); |
925 | 0 | pContext->AddAttribute( sAttrName, aOut.makeStringAndClear() ); |
926 | 0 | } |
927 | 0 | break; |
928 | 0 | default: |
929 | 0 | OSL_ENSURE( false, "unknown action" ); |
930 | 0 | break; |
931 | 0 | } |
932 | 0 | } |
933 | | |
934 | | // OpenDocument file format: attribute value of <style:mirror> wrong (#i49139#) |
935 | 0 | if ( bExistStyleMirror ) |
936 | 0 | { |
937 | 0 | pMirrorContext->AddAttribute( |
938 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
939 | 0 | XML_NAMESPACE_STYLE, GetXMLToken( XML_MIRROR ) ), |
940 | 0 | aStyleMirrorAttrValue.makeStringAndClear()); |
941 | 0 | } |
942 | 0 | else if ( bExistDrawMirror ) |
943 | 0 | { |
944 | 0 | pMirrorContext->AddAttribute( |
945 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
946 | 0 | XML_NAMESPACE_STYLE, GetXMLToken( XML_MIRROR ) ), |
947 | 0 | aDrawMirrorAttrValue); |
948 | 0 | } |
949 | |
|
950 | 0 | if (bMoveProtect || bSizeProtect || !aProtectAttrValue.isEmpty()) |
951 | 0 | { |
952 | 0 | if( (bMoveProtect ||bSizeProtect) && IsXMLToken( aProtectAttrValue, XML_NONE ) ) |
953 | 0 | aProtectAttrValue.clear(); |
954 | |
|
955 | 0 | const OUString& rPosition = GetXMLToken( XML_POSITION ); |
956 | 0 | if( bMoveProtect && -1 == aProtectAttrValue.indexOf( rPosition ) ) |
957 | 0 | { |
958 | 0 | if( !aProtectAttrValue.isEmpty() ) |
959 | 0 | aProtectAttrValue += " "; |
960 | 0 | aProtectAttrValue += rPosition; |
961 | 0 | } |
962 | |
|
963 | 0 | const OUString& rSize = GetXMLToken( XML_SIZE ); |
964 | 0 | if( bSizeProtect && -1 == aProtectAttrValue.indexOf( rSize ) ) |
965 | 0 | { |
966 | 0 | if( !aProtectAttrValue.isEmpty() ) |
967 | 0 | aProtectAttrValue += " "; |
968 | 0 | aProtectAttrValue += rSize; |
969 | 0 | } |
970 | |
|
971 | 0 | assert(pProtectContext && "pProtectContext should be assigned in a superset of the enclosing if condition entry logic"); |
972 | 0 | pProtectContext->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_STYLE, GetXMLToken( XML_PROTECT ) ), aProtectAttrValue ); |
973 | 0 | } |
974 | |
|
975 | 0 | if( !pIntervalMinorDivisorContext ) |
976 | 0 | return; |
977 | | |
978 | 0 | if( fIntervalMinor != 0.0 ) |
979 | 0 | { |
980 | 0 | sal_Int32 nIntervalMinorDivisor = static_cast< sal_Int32 >( |
981 | 0 | ::rtl::math::round( fIntervalMajor / fIntervalMinor )); |
982 | |
|
983 | 0 | pIntervalMinorDivisorContext->AddAttribute( |
984 | 0 | GetTransformer().GetNamespaceMap().GetQNameByKey( |
985 | 0 | XML_NAMESPACE_CHART, |
986 | 0 | GetXMLToken( XML_INTERVAL_MINOR_DIVISOR )), |
987 | 0 | OUString::number( nIntervalMinorDivisor )); |
988 | 0 | } |
989 | 0 | } |
990 | | |
991 | | void XMLPropertiesOOoTContext_Impl::EndElement() |
992 | 0 | { |
993 | 0 | if( !m_bPersistent ) |
994 | 0 | Export(); |
995 | 0 | } |
996 | | |
997 | | void XMLPropertiesOOoTContext_Impl::Characters( const OUString& ) |
998 | 0 | { |
999 | | // ignore them |
1000 | 0 | } |
1001 | | |
1002 | | void XMLPropertiesOOoTContext_Impl::Export() |
1003 | 0 | { |
1004 | |
|
1005 | 0 | for(rtl::Reference<XMLTypedPropertiesOOoTContext_Impl> & rPropContext : m_aPropContexts) |
1006 | 0 | { |
1007 | 0 | if( rPropContext.is() ) |
1008 | 0 | rPropContext->Export(); |
1009 | 0 | } |
1010 | 0 | } |
1011 | | |
1012 | | bool XMLPropertiesOOoTContext_Impl::IsPersistent() const |
1013 | 0 | { |
1014 | 0 | return m_bPersistent; |
1015 | 0 | } |
1016 | | |
1017 | | XMLStyleOOoTContext::XMLStyleOOoTContext( XMLTransformerBase& rImp, |
1018 | | const OUString& rQName, |
1019 | | XMLFamilyType eT, |
1020 | | bool bPersistent ) : |
1021 | 0 | XMLPersElemContentTContext( rImp, rQName ), |
1022 | 0 | m_eFamily( eT ), |
1023 | 0 | m_bPersistent( bPersistent ) |
1024 | 0 | { |
1025 | 0 | } |
1026 | | |
1027 | | XMLStyleOOoTContext::XMLStyleOOoTContext( |
1028 | | XMLTransformerBase& rImp, |
1029 | | const OUString& rQName, |
1030 | | XMLFamilyType eT, |
1031 | | sal_uInt16 nPrefix, |
1032 | | ::xmloff::token::XMLTokenEnum eToken, |
1033 | | bool bPersistent ) : |
1034 | 0 | XMLPersElemContentTContext( rImp, rQName, nPrefix, eToken ), |
1035 | 0 | m_eFamily( eT ), |
1036 | 0 | m_bPersistent( bPersistent ) |
1037 | 0 | { |
1038 | 0 | } |
1039 | | |
1040 | | XMLStyleOOoTContext::~XMLStyleOOoTContext() |
1041 | 0 | { |
1042 | 0 | } |
1043 | | |
1044 | | rtl::Reference<XMLTransformerContext> XMLStyleOOoTContext::CreateChildContext( |
1045 | | sal_uInt16 nPrefix, |
1046 | | const OUString& rLocalName, |
1047 | | const OUString& rQName, |
1048 | | const Reference< XAttributeList >& rAttrList ) |
1049 | 0 | { |
1050 | 0 | rtl::Reference<XMLTransformerContext> pContext; |
1051 | |
|
1052 | 0 | if( XML_NAMESPACE_STYLE == nPrefix && |
1053 | 0 | IsXMLToken( rLocalName, XML_PROPERTIES ) ) |
1054 | 0 | { |
1055 | 0 | if( aPropTypes[m_eFamily][0] == XML_PROP_TYPE_END ) |
1056 | 0 | { |
1057 | 0 | OSL_ENSURE( false, "unexpected properties element" ); |
1058 | 0 | pContext = m_bPersistent |
1059 | 0 | ? XMLPersElemContentTContext::CreateChildContext( |
1060 | 0 | nPrefix, rLocalName, rQName, rAttrList ) |
1061 | 0 | : XMLTransformerContext::CreateChildContext( |
1062 | 0 | nPrefix, rLocalName, rQName, rAttrList ); |
1063 | 0 | } |
1064 | 0 | else if( aPropTypes[m_eFamily][1] == XML_PROP_TYPE_END ) |
1065 | 0 | { |
1066 | 0 | sal_uInt16 nActionMap = |
1067 | 0 | aAttrActionMaps[aPropTypes[m_eFamily][0]]; |
1068 | 0 | if( nActionMap < MAX_OOO_PROP_ACTIONS ) |
1069 | 0 | { |
1070 | 0 | pContext.set(new XMLPropertiesOOoTContext_Impl( |
1071 | 0 | GetTransformer(), rQName, |
1072 | 0 | aPropTypes[m_eFamily], m_bPersistent )); |
1073 | 0 | } |
1074 | 0 | else |
1075 | 0 | { |
1076 | 0 | if( m_bPersistent ) |
1077 | 0 | pContext.set(new XMLPersElemContentTContext( |
1078 | 0 | GetTransformer(), rQName, |
1079 | 0 | XML_NAMESPACE_STYLE, |
1080 | 0 | aPropTokens[aPropTypes[m_eFamily][0]] )); |
1081 | 0 | else |
1082 | 0 | pContext.set(new XMLRenameElemTransformerContext( |
1083 | 0 | GetTransformer(), rQName, |
1084 | 0 | XML_NAMESPACE_STYLE, |
1085 | 0 | aPropTokens[aPropTypes[m_eFamily][0]] )); |
1086 | 0 | } |
1087 | 0 | } |
1088 | 0 | else |
1089 | 0 | { |
1090 | 0 | pContext.set(new XMLPropertiesOOoTContext_Impl( |
1091 | 0 | GetTransformer(), rQName, |
1092 | 0 | aPropTypes[m_eFamily], m_bPersistent)); |
1093 | 0 | } |
1094 | |
|
1095 | 0 | if( m_bPersistent ) |
1096 | 0 | AddContent( pContext ); |
1097 | 0 | } |
1098 | 0 | else |
1099 | 0 | { |
1100 | 0 | pContext = m_bPersistent |
1101 | 0 | ? XMLPersElemContentTContext::CreateChildContext( |
1102 | 0 | nPrefix, rLocalName, rQName, rAttrList ) |
1103 | 0 | : XMLTransformerContext::CreateChildContext( |
1104 | 0 | nPrefix, rLocalName, rQName, rAttrList ); |
1105 | 0 | } |
1106 | |
|
1107 | 0 | return pContext; |
1108 | 0 | } |
1109 | | |
1110 | | void XMLStyleOOoTContext::StartElement( |
1111 | | const Reference< XAttributeList >& rAttrList ) |
1112 | 0 | { |
1113 | 0 | XMLTransformerActions *pActions = |
1114 | 0 | GetTransformer().GetUserDefinedActions( OOO_STYLE_ACTIONS ); |
1115 | 0 | OSL_ENSURE( pActions, "go no actions" ); |
1116 | |
|
1117 | 0 | Reference< XAttributeList > xAttrList( rAttrList ); |
1118 | 0 | rtl::Reference<XMLMutableAttributeList> pMutableAttrList; |
1119 | 0 | sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; |
1120 | 0 | for( sal_Int16 i=0; i < nAttrCount; i++ ) |
1121 | 0 | { |
1122 | 0 | const OUString sAttrName = xAttrList->getNameByIndex( i ); |
1123 | 0 | OUString aLocalName; |
1124 | 0 | sal_uInt16 nPrefix = |
1125 | 0 | GetTransformer().GetNamespaceMap().GetKeyByAttrName( sAttrName, |
1126 | 0 | &aLocalName ); |
1127 | 0 | XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); |
1128 | 0 | XMLTransformerActions::const_iterator aIter = |
1129 | 0 | pActions->find( aKey ); |
1130 | 0 | if( aIter != pActions->end() ) |
1131 | 0 | { |
1132 | 0 | if( !pMutableAttrList ) |
1133 | 0 | { |
1134 | 0 | pMutableAttrList = |
1135 | 0 | new XMLMutableAttributeList( xAttrList ); |
1136 | 0 | xAttrList = pMutableAttrList; |
1137 | 0 | } |
1138 | 0 | const OUString sAttrValue = xAttrList->getValueByIndex( i ); |
1139 | 0 | switch( (*aIter).second.m_nActionType ) |
1140 | 0 | { |
1141 | 0 | case XML_ATACTION_STYLE_FAMILY: |
1142 | 0 | { |
1143 | 0 | bool bControl = false; |
1144 | 0 | if( XML_FAMILY_TYPE_END == m_eFamily ) |
1145 | 0 | { |
1146 | 0 | if( IsXMLToken( sAttrValue, XML_GRAPHICS ) ) |
1147 | 0 | m_eFamily = XML_FAMILY_TYPE_GRAPHIC; |
1148 | 0 | else if( IsXMLToken( sAttrValue, XML_PRESENTATION ) ) |
1149 | 0 | m_eFamily = XML_FAMILY_TYPE_PRESENTATION; |
1150 | 0 | else if( IsXMLToken( sAttrValue, XML_DRAWING_PAGE ) ) |
1151 | 0 | m_eFamily = XML_FAMILY_TYPE_DRAWING_PAGE; |
1152 | 0 | else if( IsXMLToken( sAttrValue, XML_TEXT) ) |
1153 | 0 | m_eFamily = XML_FAMILY_TYPE_TEXT; |
1154 | 0 | else if( IsXMLToken( sAttrValue, XML_PARAGRAPH) ) |
1155 | 0 | m_eFamily = XML_FAMILY_TYPE_PARAGRAPH; |
1156 | 0 | else if( IsXMLToken( sAttrValue, XML_RUBY) ) |
1157 | 0 | m_eFamily = XML_FAMILY_TYPE_RUBY; |
1158 | 0 | else if( IsXMLToken( sAttrValue, XML_SECTION) ) |
1159 | 0 | m_eFamily = XML_FAMILY_TYPE_SECTION; |
1160 | 0 | else if( IsXMLToken( sAttrValue, XML_TABLE) ) |
1161 | 0 | m_eFamily = XML_FAMILY_TYPE_TABLE; |
1162 | 0 | else if( IsXMLToken( sAttrValue, XML_TABLE_COLUMN) ) |
1163 | 0 | m_eFamily = XML_FAMILY_TYPE_TABLE_COLUMN; |
1164 | 0 | else if( IsXMLToken( sAttrValue, XML_TABLE_ROW) ) |
1165 | 0 | m_eFamily = XML_FAMILY_TYPE_TABLE_ROW; |
1166 | 0 | else if( IsXMLToken( sAttrValue, XML_TABLE_CELL) ) |
1167 | 0 | m_eFamily = XML_FAMILY_TYPE_TABLE_CELL; |
1168 | 0 | else if( IsXMLToken( sAttrValue, XML_CHART) ) |
1169 | 0 | m_eFamily = XML_FAMILY_TYPE_CHART; |
1170 | 0 | else if( IsXMLToken( sAttrValue, XML_CONTROL) ) |
1171 | 0 | { |
1172 | 0 | m_eFamily = XML_FAMILY_TYPE_PARAGRAPH; |
1173 | 0 | bControl = true; |
1174 | 0 | } |
1175 | 0 | } |
1176 | 0 | if( XML_FAMILY_TYPE_GRAPHIC == m_eFamily ) |
1177 | 0 | { |
1178 | 0 | pMutableAttrList->SetValueByIndex( i, |
1179 | 0 | GetXMLToken( XML_GRAPHIC ) ); |
1180 | 0 | } |
1181 | 0 | else if( bControl ) |
1182 | 0 | { |
1183 | 0 | pMutableAttrList->SetValueByIndex( i, |
1184 | 0 | GetXMLToken( XML_PARAGRAPH ) ); |
1185 | 0 | } |
1186 | 0 | } |
1187 | 0 | break; |
1188 | 0 | case XML_ATACTION_INCH2IN: |
1189 | 0 | { |
1190 | 0 | OUString aAttrValue( sAttrValue ); |
1191 | 0 | if( XMLTransformerBase::ReplaceSingleInchWithIn( |
1192 | 0 | aAttrValue ) ) |
1193 | 0 | pMutableAttrList->SetValueByIndex( i, aAttrValue ); |
1194 | 0 | } |
1195 | 0 | break; |
1196 | 0 | case XML_ATACTION_ENCODE_STYLE_NAME: |
1197 | 0 | { |
1198 | 0 | OUString aAttrValue( sAttrValue ); |
1199 | 0 | if( GetTransformer().EncodeStyleName(aAttrValue) ) |
1200 | 0 | { |
1201 | 0 | pMutableAttrList->SetValueByIndex( i, aAttrValue ); |
1202 | 0 | OUString aNewAttrQName( |
1203 | 0 | GetTransformer().GetNamespaceMap(). |
1204 | 0 | GetQNameByKey( |
1205 | 0 | nPrefix, ::xmloff::token::GetXMLToken( |
1206 | 0 | XML_DISPLAY_NAME ) ) ); |
1207 | 0 | pMutableAttrList->AddAttribute( aNewAttrQName, |
1208 | 0 | sAttrValue ); |
1209 | 0 | } |
1210 | 0 | } |
1211 | 0 | break; |
1212 | 0 | case XML_ATACTION_ENCODE_STYLE_NAME_REF: |
1213 | 0 | { |
1214 | 0 | OUString aAttrValue( sAttrValue ); |
1215 | 0 | if( GetTransformer().EncodeStyleName(aAttrValue) ) |
1216 | 0 | pMutableAttrList->SetValueByIndex( i, aAttrValue ); |
1217 | 0 | } |
1218 | 0 | break; |
1219 | 0 | case XML_ATACTION_NEG_PERCENT: |
1220 | 0 | { |
1221 | 0 | OUString aAttrValue( sAttrValue ); |
1222 | 0 | if( XMLTransformerBase::NegPercent(aAttrValue) ) |
1223 | 0 | pMutableAttrList->SetValueByIndex( i, aAttrValue ); |
1224 | 0 | } |
1225 | 0 | break; |
1226 | 0 | case XML_ATACTION_URI_OOO: |
1227 | 0 | { |
1228 | 0 | OUString aAttrValue( sAttrValue ); |
1229 | 0 | if( GetTransformer().ConvertURIToOASIS( aAttrValue, |
1230 | 0 | static_cast< bool >((*aIter).second.m_nParam1))) |
1231 | 0 | pMutableAttrList->SetValueByIndex( i, aAttrValue ); |
1232 | 0 | } |
1233 | 0 | break; |
1234 | 0 | default: |
1235 | 0 | OSL_ENSURE( false, "unknown action" ); |
1236 | 0 | break; |
1237 | 0 | } |
1238 | 0 | } |
1239 | 0 | } |
1240 | 0 | if( XML_FAMILY_TYPE_END == m_eFamily ) |
1241 | 0 | m_eFamily = XML_FAMILY_TYPE_TEXT; |
1242 | 0 | if( m_bPersistent ) |
1243 | 0 | XMLPersElemContentTContext::StartElement( xAttrList ); |
1244 | 0 | else |
1245 | 0 | GetTransformer().GetDocHandler()->startElement( GetExportQName(), xAttrList ); |
1246 | 0 | } |
1247 | | |
1248 | | void XMLStyleOOoTContext::EndElement() |
1249 | 0 | { |
1250 | 0 | if( m_bPersistent ) |
1251 | 0 | XMLPersElemContentTContext::EndElement(); |
1252 | 0 | else |
1253 | 0 | GetTransformer().GetDocHandler()->endElement( GetExportQName() ); |
1254 | 0 | } |
1255 | | |
1256 | | void XMLStyleOOoTContext::Characters( const OUString& ) |
1257 | 0 | { |
1258 | | // element content only: |
1259 | 0 | } |
1260 | | |
1261 | | bool XMLStyleOOoTContext::IsPersistent() const |
1262 | 0 | { |
1263 | 0 | return m_bPersistent; |
1264 | 0 | } |
1265 | | |
1266 | | XMLTransformerActions *XMLStyleOOoTContext::CreateTransformerActions( |
1267 | | sal_uInt16 nType ) |
1268 | 0 | { |
1269 | 0 | XMLTransformerActionInit const *pInit = nullptr; |
1270 | |
|
1271 | 0 | switch( nType ) |
1272 | 0 | { |
1273 | 0 | case PROP_OOO_GRAPHIC_ATTR_ACTIONS: |
1274 | 0 | pInit = aGraphicPropertyOOoAttrActionTable; |
1275 | 0 | break; |
1276 | 0 | case PROP_OOO_GRAPHIC_ELEM_ACTIONS: |
1277 | 0 | pInit = aGraphicPropertyOOoElemActionTable; |
1278 | 0 | break; |
1279 | 0 | case PROP_OOO_DRAWING_PAGE_ATTR_ACTIONS: |
1280 | 0 | pInit = aDrawingPagePropertyOOoAttrActionTable; |
1281 | 0 | break; |
1282 | 0 | case PROP_OOO_PAGE_LAYOUT_ATTR_ACTIONS: |
1283 | 0 | pInit = aPageLayoutPropertyOOoAttrActionTable; |
1284 | 0 | break; |
1285 | 0 | case PROP_OOO_HEADER_FOOTER_ATTR_ACTIONS: |
1286 | 0 | pInit = aHeaderFooterPropertyOOoAttrActionTable; |
1287 | 0 | break; |
1288 | 0 | case PROP_OOO_TEXT_ATTR_ACTIONS: |
1289 | 0 | pInit = aTextPropertyOOoAttrActionTable; |
1290 | 0 | break; |
1291 | 0 | case PROP_OOO_TEXT_ELEM_ACTIONS: |
1292 | 0 | pInit = aTextPropertyOOoElemActionTable; |
1293 | 0 | break; |
1294 | 0 | case PROP_OOO_PARAGRAPH_ATTR_ACTIONS: |
1295 | 0 | pInit = aParagraphPropertyOOoAttrActionTable; |
1296 | 0 | break; |
1297 | 0 | case PROP_OOO_PARAGRAPH_ELEM_ACTIONS: |
1298 | 0 | pInit = aParagraphPropertyOOoElemActionTable; |
1299 | 0 | break; |
1300 | 0 | case PROP_OOO_SECTION_ATTR_ACTIONS: |
1301 | 0 | pInit = aSectionPropertyOOoAttrActionTable; |
1302 | 0 | break; |
1303 | 0 | case PROP_OOO_TABLE_ATTR_ACTIONS: |
1304 | 0 | pInit = aTablePropertyOOoAttrActionTable; |
1305 | 0 | break; |
1306 | 0 | case PROP_OOO_TABLE_COLUMN_ATTR_ACTIONS: |
1307 | 0 | pInit = aTableColumnPropertyOOoAttrActionTable; |
1308 | 0 | break; |
1309 | 0 | case PROP_OOO_TABLE_ROW_ATTR_ACTIONS: |
1310 | 0 | pInit = aTableRowPropertyOOoAttrActionTable; |
1311 | 0 | break; |
1312 | 0 | case PROP_OOO_TABLE_CELL_ATTR_ACTIONS: |
1313 | 0 | pInit = aTableCellPropertyOOoAttrActionTable; |
1314 | 0 | break; |
1315 | 0 | case PROP_OOO_TABLE_CELL_ELEM_ACTIONS: |
1316 | 0 | pInit = aTableCellPropertyOOoElemActionTable; |
1317 | 0 | break; |
1318 | 0 | case PROP_OOO_LIST_LEVEL_ATTR_ACTIONS: |
1319 | 0 | pInit = aListLevelPropertyOOoAttrActionTable; |
1320 | 0 | break; |
1321 | 0 | case PROP_OOO_CHART_ATTR_ACTIONS: |
1322 | 0 | pInit = aChartPropertyOOoAttrActionTable; |
1323 | 0 | break; |
1324 | 0 | case PROP_OOO_CHART_ELEM_ACTIONS: |
1325 | 0 | pInit = aChartPropertyOOoElemActionTable; |
1326 | 0 | break; |
1327 | 0 | } |
1328 | | |
1329 | 0 | XMLTransformerActions *pActions = nullptr; |
1330 | 0 | if( pInit ) |
1331 | 0 | pActions = new XMLTransformerActions( pInit ); |
1332 | |
|
1333 | 0 | return pActions; |
1334 | 0 | } |
1335 | | |
1336 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |