bump product version to 4.1.6.2
[LibreOffice.git] / sw / source / filter / ww8 / docxattributeoutput.cxx
blob15e2c558f5199c481f4b991a735437512eb1b489
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "docxattributeoutput.hxx"
21 #include "docxexportfilter.hxx"
22 #include "docxfootnotes.hxx"
23 #include "writerwordglue.hxx"
24 #include "ww8par.hxx"
25 #include "fmtcntnt.hxx"
26 #include "fchrfmt.hxx"
27 #include "tgrditem.hxx"
28 #include "fmtruby.hxx"
29 #include "breakit.hxx"
31 #include <comphelper/string.hxx>
32 #include <oox/token/tokens.hxx>
33 #include <oox/export/utils.hxx>
34 #include <oox/mathml/export.hxx>
36 #include <i18nlangtag/languagetag.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <editeng/tstpitem.hxx>
40 #include <editeng/spltitem.hxx>
41 #include <editeng/widwitem.hxx>
42 #include <editeng/shaditem.hxx>
43 #include <editeng/brushitem.hxx>
44 #include <editeng/postitem.hxx>
45 #include <editeng/wghtitem.hxx>
46 #include <editeng/kernitem.hxx>
47 #include <editeng/crossedoutitem.hxx>
48 #include <editeng/cmapitem.hxx>
49 #include <editeng/udlnitem.hxx>
50 #include <editeng/langitem.hxx>
51 #include <editeng/escapementitem.hxx>
52 #include <editeng/fhgtitem.hxx>
53 #include <editeng/colritem.hxx>
54 #include <editeng/hyphenzoneitem.hxx>
55 #include <editeng/ulspitem.hxx>
56 #include <editeng/boxitem.hxx>
57 #include <editeng/contouritem.hxx>
58 #include <editeng/shdditem.hxx>
59 #include <editeng/emphasismarkitem.hxx>
60 #include <editeng/twolinesitem.hxx>
61 #include <editeng/charscaleitem.hxx>
62 #include <editeng/charrotateitem.hxx>
63 #include <editeng/charreliefitem.hxx>
64 #include <editeng/paravertalignitem.hxx>
65 #include <editeng/pgrditem.hxx>
66 #include <editeng/frmdiritem.hxx>
67 #include <editeng/blinkitem.hxx>
68 #include <editeng/charhiddenitem.hxx>
69 #include <editeng/opaqitem.hxx>
70 #include <editeng/editobj.hxx>
71 #include <svx/svdmodel.hxx>
72 #include <svx/svdobj.hxx>
73 #include <svx/xfillit0.hxx>
74 #include <svx/xflgrit.hxx>
75 #include <sfx2/sfxbasemodel.hxx>
77 #include <anchoredobject.hxx>
78 #include <docufld.hxx>
79 #include <flddropdown.hxx>
80 #include <fmtanchr.hxx>
81 #include <fmtclds.hxx>
82 #include <fmtinfmt.hxx>
83 #include <fmtrowsplt.hxx>
84 #include <fmtline.hxx>
85 #include <frmatr.hxx>
86 #include <ftninfo.hxx>
87 #include <htmltbl.hxx>
88 #include <lineinfo.hxx>
89 #include <ndgrf.hxx>
90 #include <ndole.hxx>
91 #include <ndtxt.hxx>
92 #include <pagedesc.hxx>
93 #include <paratr.hxx>
94 #include <charatr.hxx>
95 #include <swmodule.hxx>
96 #include <swtable.hxx>
97 #include <txtftn.hxx>
98 #include <txtinet.hxx>
100 #include <osl/file.hxx>
101 #include <rtl/tencinfo.h>
102 #include <vcl/embeddedfontshelper.hxx>
104 #include <com/sun/star/i18n/ScriptType.hpp>
105 #include <com/sun/star/chart2/XChartDocument.hpp>
107 #if OSL_DEBUG_LEVEL > 1
108 #include <stdio.h>
109 #endif
111 using ::editeng::SvxBorderLine;
113 using namespace oox;
114 using namespace docx;
115 using namespace sax_fastparser;
116 using namespace nsSwDocInfoSubType;
117 using namespace nsFieldFlags;
118 using namespace sw::util;
119 using namespace ::com::sun::star;
121 class FFDataWriterHelper
123 ::sax_fastparser::FSHelperPtr m_pSerializer;
124 void writeCommonStart( const OUString& rName )
126 m_pSerializer->startElementNS( XML_w, XML_ffData, FSEND );
127 m_pSerializer->singleElementNS( XML_w, XML_name,
128 FSNS( XML_w, XML_val ), OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr(),
129 FSEND );
130 m_pSerializer->singleElementNS( XML_w, XML_enabled, FSEND );
131 m_pSerializer->singleElementNS( XML_w, XML_calcOnExit,
132 FSNS( XML_w, XML_val ),
133 "0", FSEND );
135 void writeFinish()
137 m_pSerializer->endElementNS( XML_w, XML_ffData );
139 public:
140 FFDataWriterHelper( const ::sax_fastparser::FSHelperPtr pSerializer ) : m_pSerializer( pSerializer ){}
141 void WriteFormCheckbox( const OUString& rName, const OUString& rDefault, bool bChecked )
143 writeCommonStart( rName );
144 // Checkbox specific bits
145 m_pSerializer->startElementNS( XML_w, XML_checkBox, FSEND );
146 // currently hardcoding autosize
147 // #TODO check if this defaulted
148 m_pSerializer->startElementNS( XML_w, XML_sizeAuto, FSEND );
149 m_pSerializer->endElementNS( XML_w, XML_sizeAuto );
150 if ( !rDefault.isEmpty() )
152 m_pSerializer->singleElementNS( XML_w, XML_default,
153 FSNS( XML_w, XML_val ),
154 OUStringToOString( rDefault, RTL_TEXTENCODING_UTF8 ).getStr(), FSEND );
156 if ( bChecked )
157 m_pSerializer->singleElementNS( XML_w, XML_checked, FSEND );
158 m_pSerializer->endElementNS( XML_w, XML_checkBox );
159 writeFinish();
161 void WriteFormText( const OUString& rName, const OUString& rDefault )
163 writeCommonStart( rName );
164 if ( !rDefault.isEmpty() )
166 m_pSerializer->startElementNS( XML_w, XML_textInput, FSEND );
167 m_pSerializer->singleElementNS( XML_w, XML_default,
168 FSNS( XML_w, XML_val ),
169 OUStringToOString( rDefault, RTL_TEXTENCODING_UTF8 ).getStr(), FSEND );
170 m_pSerializer->endElementNS( XML_w, XML_textInput );
172 writeFinish();
176 class FieldMarkParamsHelper
178 const sw::mark::IFieldmark& mrFieldmark;
179 public:
180 FieldMarkParamsHelper( const sw::mark::IFieldmark& rFieldmark ) : mrFieldmark( rFieldmark ) {}
181 OUString getName() { return mrFieldmark.GetName(); }
182 template < typename T >
183 bool extractParam( const OUString& rKey, T& rResult )
185 bool bResult = false;
186 if ( mrFieldmark.GetParameters() )
188 sw::mark::IFieldmark::parameter_map_t::const_iterator it = mrFieldmark.GetParameters()->find( rKey );
189 if ( it != mrFieldmark.GetParameters()->end() )
190 bResult = ( it->second >>= rResult );
192 return bResult;
195 void DocxAttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 /*nScript*/ )
197 if (bIsRTL)
198 m_pSerializer->singleElementNS( XML_w, XML_rtl, FSNS( XML_w, XML_val ), "true", FSEND );
201 void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo )
203 if ( m_nColBreakStatus == COLBRK_POSTPONE )
204 m_nColBreakStatus = COLBRK_WRITE;
206 // Output table/table row/table cell starts if needed
207 if ( pTextNodeInfo.get() )
209 sal_uInt32 nRow = pTextNodeInfo->getRow();
210 sal_uInt32 nCell = pTextNodeInfo->getCell();
212 // New cell/row?
213 if ( m_nTableDepth > 0 && !m_bTableCellOpen )
215 ww8::WW8TableNodeInfoInner::Pointer_t pDeepInner( pTextNodeInfo->getInnerForDepth( m_nTableDepth ) );
216 if ( pDeepInner->getCell() == 0 )
217 StartTableRow( pDeepInner );
219 StartTableCell( pDeepInner );
222 if ( nRow == 0 && nCell == 0 )
224 // Do we have to start the table?
225 // [If we are at the rigth depth already, it means that we
226 // continue the table cell]
227 sal_uInt32 nCurrentDepth = pTextNodeInfo->getDepth();
229 if ( nCurrentDepth > m_nTableDepth )
231 // Start all the tables that begin here
232 for ( sal_uInt32 nDepth = m_nTableDepth + 1; nDepth <= pTextNodeInfo->getDepth(); ++nDepth )
234 ww8::WW8TableNodeInfoInner::Pointer_t pInner( pTextNodeInfo->getInnerForDepth( nDepth ) );
236 StartTable( pInner );
237 StartTableRow( pInner );
238 StartTableCell( pInner );
241 m_nTableDepth = nCurrentDepth;
246 m_pSerializer->startElementNS( XML_w, XML_p, FSEND );
248 // postpone the output of the run (we get it before the paragraph
249 // properties, but must write it after them)
250 m_pSerializer->mark();
252 // no section break in this paragraph yet; can be set in SectionBreak()
253 m_pSectionInfo.reset();
255 m_bParagraphOpened = true;
258 void lcl_TextFrameShadow(FSHelperPtr pSerializer, const SwFrmFmt& rFrmFmt)
260 SvxShadowItem aShadowItem = rFrmFmt.GetShadow();
261 if (aShadowItem.GetLocation() == SVX_SHADOW_NONE)
262 return;
264 OString aShadowWidth( OString::valueOf( double( aShadowItem.GetWidth() ) / 20) + "pt");
265 OString aOffset;
266 switch (aShadowItem.GetLocation())
268 case SVX_SHADOW_TOPLEFT: aOffset = "-" + aShadowWidth + ",-" + aShadowWidth; break;
269 case SVX_SHADOW_TOPRIGHT: aOffset = aShadowWidth + ",-" + aShadowWidth; break;
270 case SVX_SHADOW_BOTTOMLEFT: aOffset = "-" + aShadowWidth + "," + aShadowWidth; break;
271 case SVX_SHADOW_BOTTOMRIGHT: aOffset = aShadowWidth + "," + aShadowWidth; break;
272 case SVX_SHADOW_NONE:
273 case SVX_SHADOW_END:
274 break;
276 if (aOffset.isEmpty())
277 return;
279 OString aShadowColor = msfilter::util::ConvertColor(aShadowItem.GetColor());
280 pSerializer->singleElementNS(XML_v, XML_shadow,
281 XML_on, "t",
282 XML_color, "#" + aShadowColor,
283 XML_offset, aOffset,
284 FSEND);
287 void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner )
289 // write the paragraph properties + the run, already in the correct order
290 m_pSerializer->mergeTopMarks();
292 // Write the anchored frame if any
293 // Make a copy and clear the original early, as this method is called
294 // recursively for in-frame paragraphs
295 std::vector<sw::Frame> aParentFrames = m_aParentFrames;
296 m_aParentFrames.clear();
297 for (size_t i = 0; i < aParentFrames.size(); ++i)
299 sw::Frame* pParentFrame = &aParentFrames[i];
301 const SwFrmFmt& rFrmFmt = pParentFrame->GetFrmFmt( );
302 const SwNodeIndex* pNodeIndex = rFrmFmt.GetCntnt().GetCntntIdx();
304 sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex()+1 : 0;
305 sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0;
307 m_rExport.SaveData( nStt, nEnd );
309 m_rExport.mpParentFrame = pParentFrame;
311 // When a frame has some low height, but automatically expanded due
312 // to lots of contents, this size contains the real size.
313 const Size aSize = pParentFrame->GetSize();
314 m_pFlyFrameSize = &aSize;
316 m_bTextFrameSyntax = true;
317 m_pFlyAttrList = m_pSerializer->createAttrList( );
318 m_pTextboxAttrList = m_pSerializer->createAttrList();
319 m_aTextFrameStyle = "position:absolute";
320 m_rExport.OutputFormat( pParentFrame->GetFrmFmt(), false, false, true );
321 m_pFlyAttrList->add(XML_style, m_aTextFrameStyle.makeStringAndClear());
322 XFastAttributeListRef xFlyAttrList( m_pFlyAttrList );
323 m_pFlyAttrList = NULL;
324 XFastAttributeListRef xTextboxAttrList(m_pTextboxAttrList);
325 m_pTextboxAttrList = NULL;
326 m_bTextFrameSyntax = false;
327 m_pFlyFrameSize = 0;
329 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
330 m_pSerializer->startElementNS( XML_w, XML_pict, FSEND );
331 m_pSerializer->startElementNS( XML_v, XML_rect, xFlyAttrList );
332 lcl_TextFrameShadow(m_pSerializer, rFrmFmt);
333 if (m_pFlyFillAttrList)
335 XFastAttributeListRef xFlyFillAttrList(m_pFlyFillAttrList);
336 m_pFlyFillAttrList = NULL;
337 m_pSerializer->singleElementNS(XML_v, XML_fill, xFlyFillAttrList);
339 m_pSerializer->startElementNS( XML_v, XML_textbox, xTextboxAttrList );
340 m_pSerializer->startElementNS( XML_w, XML_txbxContent, FSEND );
341 m_rExport.WriteText( );
342 m_pSerializer->endElementNS( XML_w, XML_txbxContent );
343 m_pSerializer->endElementNS( XML_v, XML_textbox );
345 if (m_pFlyWrapAttrList)
347 XFastAttributeListRef xFlyWrapAttrList(m_pFlyWrapAttrList);
348 m_pFlyWrapAttrList = NULL;
349 m_pSerializer->singleElementNS(XML_w10, XML_wrap, xFlyWrapAttrList);
352 m_pSerializer->endElementNS( XML_v, XML_rect );
353 m_pSerializer->endElementNS( XML_w, XML_pict );
354 m_pSerializer->endElementNS( XML_w, XML_r );
356 m_rExport.RestoreData();
358 m_rExport.mpParentFrame = NULL;
361 m_pSerializer->endElementNS( XML_w, XML_p );
363 // Check for end of cell, rows, tables here
364 FinishTableRowCell( pTextNodeInfoInner );
366 m_bParagraphOpened = false;
370 void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointer_t pInner, bool bForceEmptyParagraph )
372 if ( pInner.get() )
374 // Where are we in the table
375 sal_uInt32 nRow = pInner->getRow( );
377 const SwTable *pTable = pInner->getTable( );
378 const SwTableLines& rLines = pTable->GetTabLines( );
379 sal_uInt16 nLinesCount = rLines.size( );
380 // HACK
381 // msoffice seems to have an internal limitation of 63 columns for tables
382 // and refuses to load .docx with more, even though the spec seems to allow that;
383 // so simply if there are more columns, don't close the last one msoffice will handle
384 // and merge the contents of the remaining ones into it (since we don't close the cell
385 // here, following ones will not be opened)
386 bool limitWorkaround = ( pInner->getCell() >= 62 && !pInner->isEndOfLine());
388 if ( pInner->isEndOfCell() && !limitWorkaround )
390 if ( bForceEmptyParagraph )
391 m_pSerializer->singleElementNS( XML_w, XML_p, FSEND );
393 EndTableCell();
396 // This is a line end
397 if ( pInner->isEndOfLine() )
398 EndTableRow();
400 // This is the end of the table
401 if ( pInner->isEndOfLine( ) && ( nRow + 1 ) == nLinesCount )
402 EndTable();
406 void DocxAttributeOutput::EmptyParagraph()
408 m_pSerializer->singleElementNS( XML_w, XML_p, FSEND );
411 void DocxAttributeOutput::StartParagraphProperties( const SwTxtNode& rNode )
413 // output page/section breaks
414 // Writer can have them at the beginning of a paragraph, or at the end, but
415 // in docx, we have to output them in the paragraph properties of the last
416 // paragraph in a section. To get it right, we have to switch to the next
417 // paragraph, and detect the section breaks there.
418 SwNodeIndex aNextIndex( rNode, 1 );
419 if ( aNextIndex.GetNode().IsTxtNode() )
421 const SwTxtNode* pTxtNode = static_cast< SwTxtNode* >( &aNextIndex.GetNode() );
422 // If next node has no string - it is an empty node, so no need to output the section break
423 if (!pTxtNode->GetTxt().isEmpty())
424 m_rExport.OutputSectionBreaks( pTxtNode->GetpSwAttrSet(), *pTxtNode );
426 else if ( aNextIndex.GetNode().IsTableNode() )
428 const SwTableNode* pTableNode = static_cast< SwTableNode* >( &aNextIndex.GetNode() );
429 const SwFrmFmt *pFmt = pTableNode->GetTable().GetFrmFmt();
430 m_rExport.OutputSectionBreaks( &(pFmt->GetAttrSet()), *pTableNode );
433 m_pSerializer->mark( );
435 m_pSerializer->startElementNS( XML_w, XML_pPr, FSEND );
437 // and output the section break now (if it appeared)
438 if ( m_pSectionInfo )
440 m_rExport.SectionProperties( *m_pSectionInfo );
441 m_pSectionInfo.reset();
444 InitCollectedParagraphProperties();
447 void DocxAttributeOutput::InitCollectedParagraphProperties()
449 m_pParagraphSpacingAttrList = NULL;
451 // Write the elements in the spec order
452 static const sal_Int32 aOrder[] =
454 FSNS( XML_w, XML_pStyle ),
455 FSNS( XML_w, XML_keepNext ),
456 FSNS( XML_w, XML_keepLines ),
457 FSNS( XML_w, XML_pageBreakBefore ),
458 FSNS( XML_w, XML_framePr ),
459 FSNS( XML_w, XML_widowControl ),
460 FSNS( XML_w, XML_numPr ),
461 FSNS( XML_w, XML_suppressLineNumbers ),
462 FSNS( XML_w, XML_pBdr ),
463 FSNS( XML_w, XML_shd ),
464 FSNS( XML_w, XML_tabs ),
465 FSNS( XML_w, XML_suppressAutoHyphens ),
466 FSNS( XML_w, XML_kinsoku ),
467 FSNS( XML_w, XML_wordWrap ),
468 FSNS( XML_w, XML_overflowPunct ),
469 FSNS( XML_w, XML_topLinePunct ),
470 FSNS( XML_w, XML_autoSpaceDE ),
471 FSNS( XML_w, XML_autoSpaceDN ),
472 FSNS( XML_w, XML_bidi ),
473 FSNS( XML_w, XML_adjustRightInd ),
474 FSNS( XML_w, XML_snapToGrid ),
475 FSNS( XML_w, XML_spacing ),
476 FSNS( XML_w, XML_ind ),
477 FSNS( XML_w, XML_contextualSpacing ),
478 FSNS( XML_w, XML_mirrorIndents ),
479 FSNS( XML_w, XML_suppressOverlap ),
480 FSNS( XML_w, XML_jc ),
481 FSNS( XML_w, XML_textDirection ),
482 FSNS( XML_w, XML_textAlignment ),
483 FSNS( XML_w, XML_textboxTightWrap ),
484 FSNS( XML_w, XML_outlineLvl ),
485 FSNS( XML_w, XML_divId ),
486 FSNS( XML_w, XML_cnfStyle ),
487 FSNS( XML_w, XML_rPr ),
488 FSNS( XML_w, XML_sectPr ),
489 FSNS( XML_w, XML_pPrChange )
492 // postpone the output so that we can later [in EndParagraphProperties()]
493 // prepend the properties before the run
494 sal_Int32 len = sizeof ( aOrder ) / sizeof( sal_Int32 );
495 uno::Sequence< sal_Int32 > aSeqOrder( len );
496 for ( sal_Int32 i = 0; i < len; i++ )
497 aSeqOrder[i] = aOrder[i];
499 m_pSerializer->mark( aSeqOrder );
502 void DocxAttributeOutput::WriteCollectedParagraphProperties()
504 if ( m_pFlyAttrList )
506 XFastAttributeListRef xAttrList( m_pFlyAttrList );
507 m_pFlyAttrList = NULL;
509 m_pSerializer->singleElementNS( XML_w, XML_framePr, xAttrList );
512 if ( m_pParagraphSpacingAttrList )
514 XFastAttributeListRef xAttrList( m_pParagraphSpacingAttrList );
515 m_pParagraphSpacingAttrList = NULL;
517 m_pSerializer->singleElementNS( XML_w, XML_spacing, xAttrList );
520 // Merge the marks for the ordered elements
521 m_pSerializer->mergeTopMarks( );
524 void DocxAttributeOutput::EndParagraphProperties()
526 WriteCollectedParagraphProperties();
528 // insert copy of <rPr>
529 m_pSerializer->copyTopMarkPop();
531 m_pSerializer->endElementNS( XML_w, XML_pPr );
533 if ( m_nColBreakStatus == COLBRK_WRITE )
535 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
536 m_pSerializer->singleElementNS( XML_w, XML_br,
537 FSNS( XML_w, XML_type ), "column", FSEND );
538 m_pSerializer->endElementNS( XML_w, XML_r );
540 m_nColBreakStatus = COLBRK_NONE;
543 // merge the properties _before_ the run (strictly speaking, just
544 // after the start of the paragraph)
545 m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND );
548 void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, bool /*bSingleEmptyRun*/ )
550 // Don't start redline data here, possibly there is a hyperlink later, and
551 // that has to be started first.
552 m_pRedlineData = pRedlineData;
554 // postpone the output of the start of a run (there are elements that need
555 // to be written before the start of the run, but we learn which they are
556 // _inside_ of the run)
557 m_pSerializer->mark(); // let's call it "postponed run start"
559 // postpone the output of the text (we get it before the run properties,
560 // but must write it after them)
561 m_pSerializer->mark(); // let's call it "postponed text"
564 void DocxAttributeOutput::EndRun()
566 // Write field starts
567 for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin(); pIt != m_Fields.end(); )
569 // Add the fields starts for all but hyperlinks and TOCs
570 if ( pIt->bOpen && pIt->pField )
572 StartField_Impl( *pIt );
574 // Remove the field from the stack if only the start has to be written
575 // Unknown fields sould be removed too
576 if ( !pIt->bClose || ( pIt->eType == ww::eUNKNOWN ) )
578 if (pIt->pField)
579 delete pIt->pField;
580 pIt = m_Fields.erase( pIt );
581 continue;
584 ++pIt;
587 // write the run properties + the text, already in the correct order
588 m_pSerializer->mergeTopMarks(); // merges with "postponed text", see above
590 // level down, to be able to prepend the actual run start attribute (just
591 // before "postponed run start")
592 m_pSerializer->mark(); // let's call it "actual run start"
594 if ( m_closeHyperlinkInPreviousRun )
596 if ( m_startedHyperlink )
598 m_pSerializer->endElementNS( XML_w, XML_hyperlink );
599 m_startedHyperlink = false;
601 m_closeHyperlinkInPreviousRun = false;
604 // Write the hyperlink and toc fields starts
605 for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin(); pIt != m_Fields.end(); )
607 // Add the fields starts for hyperlinks, TOCs and index marks
608 if ( pIt->bOpen && !pIt->pField )
610 StartField_Impl( *pIt, sal_True );
612 // Remove the field if no end needs to be written
613 if ( !pIt->bClose ) {
614 if (pIt->pField)
615 delete pIt->pField;
616 pIt = m_Fields.erase( pIt );
617 continue;
620 ++pIt;
623 // Start the hyperlink after the fields separators or we would generate invalid file
624 if ( m_pHyperlinkAttrList )
626 XFastAttributeListRef xAttrList ( m_pHyperlinkAttrList );
628 m_pSerializer->startElementNS( XML_w, XML_hyperlink, xAttrList );
629 m_pHyperlinkAttrList = NULL;
630 m_startedHyperlink = true;
633 // if there is some redlining in the document, output it
634 StartRedline();
636 DoWriteBookmarks( );
637 WriteCommentRanges();
639 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
640 m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND ); // merges with "postponed run start", see above
642 // write the run start + the run content
643 m_pSerializer->mergeTopMarks(); // merges the "actual run start"
645 // append the actual run end
646 m_pSerializer->endElementNS( XML_w, XML_r );
648 WritePostponedMath();
649 WritePendingPlaceholder();
651 // if there is some redlining in the document, output it
652 EndRedline();
654 if ( m_closeHyperlinkInThisRun )
656 if ( m_startedHyperlink )
658 m_pSerializer->endElementNS( XML_w, XML_hyperlink );
659 m_startedHyperlink = false;
661 m_closeHyperlinkInThisRun = false;
664 while ( m_Fields.begin() != m_Fields.end() )
666 EndField_Impl( m_Fields.front( ) );
667 if (m_Fields.front().pField)
668 delete m_Fields.front().pField;
669 m_Fields.erase( m_Fields.begin( ) );
673 void DocxAttributeOutput::WriteCommentRanges()
675 if (m_bPostitStart)
677 m_bPostitStart = false;
678 OString idstr = OString::valueOf( sal_Int32( m_postitFieldsMaxId ));
679 m_pSerializer->singleElementNS( XML_w, XML_commentRangeStart, FSNS( XML_w, XML_id ), idstr.getStr(), FSEND );
681 if (m_bPostitEnd)
683 m_bPostitEnd = false;
684 OString idstr = OString::valueOf( sal_Int32( m_postitFieldsMaxId ));
685 m_pSerializer->singleElementNS( XML_w, XML_commentRangeEnd, FSNS( XML_w, XML_id ), idstr.getStr(), FSEND );
689 void DocxAttributeOutput::DoWriteBookmarks()
691 // Write the start bookmarks
692 for ( std::vector< OString >::const_iterator it = m_rMarksStart.begin(), end = m_rMarksStart.end();
693 it != end; ++it )
695 const OString& rName = *it;
697 // Output the bookmark
698 sal_uInt16 nId = m_nNextMarkId++;
699 m_rOpenedMarksIds[rName] = nId;
700 m_pSerializer->singleElementNS( XML_w, XML_bookmarkStart,
701 FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( nId ) ).getStr( ),
702 FSNS( XML_w, XML_name ), rName.getStr(),
703 FSEND );
704 m_sLastOpenedMark = rName;
706 m_rMarksStart.clear();
708 // export the end bookmarks
709 for ( std::vector< OString >::const_iterator it = m_rMarksEnd.begin(), end = m_rMarksEnd.end();
710 it != end; ++it )
712 const OString& rName = *it;
714 // Get the id of the bookmark
715 std::map< OString, sal_uInt16 >::iterator pPos = m_rOpenedMarksIds.find( rName );
716 if ( pPos != m_rOpenedMarksIds.end( ) )
718 sal_uInt16 nId = ( *pPos ).second;
719 m_pSerializer->singleElementNS( XML_w, XML_bookmarkEnd,
720 FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( nId ) ).getStr( ),
721 FSEND );
722 m_rOpenedMarksIds.erase( rName );
725 m_rMarksEnd.clear();
728 void DocxAttributeOutput::WriteFFData( const FieldInfos& rInfos )
730 const ::sw::mark::IFieldmark& rFieldmark = *rInfos.pFieldmark;
731 if ( rInfos.eType == ww::eFORMDROPDOWN )
733 uno::Sequence< OUString> vListEntries;
734 OUString sName, sHelp, sToolTip, sSelected;
736 FieldMarkParamsHelper params( rFieldmark );
737 params.extractParam( ODF_FORMDROPDOWN_LISTENTRY, vListEntries );
738 sName = params.getName();
739 sal_Int32 nSelectedIndex = 0;
741 if ( params.extractParam( ODF_FORMDROPDOWN_RESULT, nSelectedIndex ) )
743 if (nSelectedIndex < vListEntries.getLength() )
744 sSelected = vListEntries[ nSelectedIndex ];
747 GetExport().DoComboBox( sName, sHelp, sToolTip, sSelected, vListEntries );
749 else if ( rInfos.eType == ww::eFORMCHECKBOX )
751 OUString sName;
752 bool bChecked = false;
754 FieldMarkParamsHelper params( rFieldmark );
755 params.extractParam( ODF_FORMCHECKBOX_NAME, sName );
757 const sw::mark::ICheckboxFieldmark* pCheckboxFm = dynamic_cast<const sw::mark::ICheckboxFieldmark*>(&rFieldmark);
758 if ( pCheckboxFm && pCheckboxFm->IsChecked() )
759 bChecked = true;
761 FFDataWriterHelper ffdataOut( m_pSerializer );
762 ffdataOut.WriteFormCheckbox( sName, OUString(), bChecked );
764 else if ( rInfos.eType == ww::eFORMTEXT )
766 FieldMarkParamsHelper params( rFieldmark );
767 FFDataWriterHelper ffdataOut( m_pSerializer );
768 ffdataOut.WriteFormText( params.getName(), OUString() );
772 void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, bool bWriteRun )
774 if ( rInfos.pField && rInfos.eType == ww::eUNKNOWN )
776 // Expand unsupported fields
777 RunText( rInfos.pField->GetFieldName() );
779 else if ( rInfos.eType != ww::eNONE ) // HYPERLINK fields are just commands
781 if ( bWriteRun )
782 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
784 if ( rInfos.eType == ww::eFORMDROPDOWN )
786 m_pSerializer->startElementNS( XML_w, XML_fldChar,
787 FSNS( XML_w, XML_fldCharType ), "begin",
788 FSEND );
789 if ( rInfos.pFieldmark && !rInfos.pField )
790 WriteFFData( rInfos );
791 if ( rInfos.pField )
793 const SwDropDownField& rFld2 = *(SwDropDownField*)rInfos.pField;
794 uno::Sequence<OUString> aItems =
795 rFld2.GetItemSequence();
796 GetExport().DoComboBox(rFld2.GetName(),
797 rFld2.GetHelp(),
798 rFld2.GetToolTip(),
799 rFld2.GetSelectedItem(), aItems);
801 m_pSerializer->endElementNS( XML_w, XML_fldChar );
803 if ( bWriteRun )
804 m_pSerializer->endElementNS( XML_w, XML_r );
805 if ( !rInfos.pField )
806 CmdField_Impl( rInfos );
809 else
811 // Write the field start
812 m_pSerializer->startElementNS( XML_w, XML_fldChar,
813 FSNS( XML_w, XML_fldCharType ), "begin",
814 FSEND );
816 if ( rInfos.pFieldmark )
817 WriteFFData( rInfos );
819 m_pSerializer->endElementNS( XML_w, XML_fldChar );
821 if ( bWriteRun )
822 m_pSerializer->endElementNS( XML_w, XML_r );
824 // The hyperlinks fields can't be expanded: the value is
825 // normally in the text run
826 if ( !rInfos.pField )
827 CmdField_Impl( rInfos );
832 void DocxAttributeOutput::DoWriteCmd( String& rCmd )
834 OUString sCmd = OUString(rCmd).trim();
835 if (sCmd.startsWith("SEQ"))
837 OUString sSeqName = msfilter::util::findQuotedText(sCmd, "SEQ ", '\\').trim();
838 m_aSeqMarksNames[sSeqName].push_back(m_sLastOpenedMark);
840 // Write the Field command
841 m_pSerializer->startElementNS( XML_w, XML_instrText, FSEND );
842 m_pSerializer->writeEscaped( OUString( rCmd ) );
843 m_pSerializer->endElementNS( XML_w, XML_instrText );
847 void DocxAttributeOutput::CmdField_Impl( FieldInfos& rInfos )
849 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
850 xub_StrLen nNbToken = comphelper::string::getTokenCount(rInfos.sCmd, '\t');
852 for ( xub_StrLen i = 0; i < nNbToken; i++ )
854 String sToken = rInfos.sCmd.GetToken( i, '\t' );
855 if ( rInfos.eType == ww::eCREATEDATE
856 || rInfos.eType == ww::eSAVEDATE
857 || rInfos.eType == ww::ePRINTDATE
858 || rInfos.eType == ww::eDATE
859 || rInfos.eType == ww::eTIME )
861 sToken.SearchAndReplaceAll( String( "NNNN" ), String( "dddd" ) );
862 sToken.SearchAndReplaceAll( String( "NN" ), String( "ddd" ) );
864 // Write the Field command
865 DoWriteCmd( sToken );
867 // Replace tabs by </instrText><tab/><instrText>
868 if ( i < ( nNbToken - 1 ) )
869 RunText( OUString( "\t" ) );
872 m_pSerializer->endElementNS( XML_w, XML_r );
874 // Write the Field separator
875 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
876 m_pSerializer->singleElementNS( XML_w, XML_fldChar,
877 FSNS( XML_w, XML_fldCharType ), "separate",
878 FSEND );
879 m_pSerializer->endElementNS( XML_w, XML_r );
882 void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos )
884 // The command has to be written before for the hyperlinks
885 if ( rInfos.pField )
887 CmdField_Impl( rInfos );
890 // Write the bookmark start if any
891 OUString aBkmName( m_sFieldBkm );
892 if ( !aBkmName.isEmpty() )
894 m_pSerializer->singleElementNS( XML_w, XML_bookmarkStart,
895 FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( m_nNextMarkId ) ).getStr( ),
896 FSNS( XML_w, XML_name ), OUStringToOString( aBkmName, RTL_TEXTENCODING_UTF8 ).getStr( ),
897 FSEND );
900 if (rInfos.pField ) // For hyperlinks and TOX
902 // Write the Field latest value
903 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
905 String sExpand( rInfos.pField->ExpandField( true ) );
906 // newlines embedded in fields are 0x0B in MSO and 0x0A for us
907 sExpand.SearchAndReplaceAll( 0x0A, 0x0B );
908 RunText( sExpand );
910 m_pSerializer->endElementNS( XML_w, XML_r );
913 // Write the bookmark end if any
914 if ( !aBkmName.isEmpty() )
916 m_pSerializer->singleElementNS( XML_w, XML_bookmarkEnd,
917 FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( m_nNextMarkId ) ).getStr( ),
918 FSEND );
920 m_nNextMarkId++;
923 // Write the Field end
924 if ( rInfos.bClose )
926 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
927 m_pSerializer->singleElementNS( XML_w, XML_fldChar,
928 FSNS( XML_w, XML_fldCharType ), "end",
929 FSEND );
930 m_pSerializer->endElementNS( XML_w, XML_r );
932 // Write the ref field if a bookmark had to be set and the field
933 // should be visible
934 if ( rInfos.pField )
936 sal_uInt16 nSubType = rInfos.pField->GetSubType( );
937 bool bIsSetField = rInfos.pField->GetTyp( )->Which( ) == RES_SETEXPFLD;
938 bool bShowRef = ( !bIsSetField || ( nSubType & nsSwExtendedSubType::SUB_INVISIBLE ) ) ? false : true;
940 if ( ( m_sFieldBkm.Len( ) > 0 ) && bShowRef )
942 // Write the field beginning
943 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
944 m_pSerializer->singleElementNS( XML_w, XML_fldChar,
945 FSNS( XML_w, XML_fldCharType ), "begin",
946 FSEND );
947 m_pSerializer->endElementNS( XML_w, XML_r );
949 rInfos.sCmd = FieldString( ww::eREF );
950 rInfos.sCmd.AppendAscii( "\"" );
951 rInfos.sCmd += m_sFieldBkm;
952 rInfos.sCmd.AppendAscii( "\" " );
954 // Clean the field bookmark data to avoid infinite loop
955 m_sFieldBkm = String( );
957 // Write the end of the field
958 EndField_Impl( rInfos );
963 void DocxAttributeOutput::StartRunProperties()
965 // postpone the output so that we can later [in EndRunProperties()]
966 // prepend the properties before the text
967 m_pSerializer->mark();
969 m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND );
971 InitCollectedRunProperties();
973 OSL_ASSERT( m_postponedGraphic == NULL );
974 m_postponedGraphic = new std::list< PostponedGraphic >;
977 void DocxAttributeOutput::InitCollectedRunProperties()
979 m_pFontsAttrList = NULL;
980 m_pEastAsianLayoutAttrList = NULL;
981 m_pCharLangAttrList = NULL;
983 // Write the elements in the spec order
984 static const sal_Int32 aOrder[] =
986 FSNS( XML_w, XML_rStyle ),
987 FSNS( XML_w, XML_rFonts ),
988 FSNS( XML_w, XML_b ),
989 FSNS( XML_w, XML_bCs ),
990 FSNS( XML_w, XML_i ),
991 FSNS( XML_w, XML_iCs ),
992 FSNS( XML_w, XML_caps ),
993 FSNS( XML_w, XML_smallCaps ),
994 FSNS( XML_w, XML_strike ),
995 FSNS( XML_w, XML_dstrike ),
996 FSNS( XML_w, XML_outline ),
997 FSNS( XML_w, XML_shadow ),
998 FSNS( XML_w, XML_emboss ),
999 FSNS( XML_w, XML_imprint ),
1000 FSNS( XML_w, XML_noProof ),
1001 FSNS( XML_w, XML_snapToGrid ),
1002 FSNS( XML_w, XML_vanish ),
1003 FSNS( XML_w, XML_webHidden ),
1004 FSNS( XML_w, XML_color ),
1005 FSNS( XML_w, XML_spacing ),
1006 FSNS( XML_w, XML_w ),
1007 FSNS( XML_w, XML_kern ),
1008 FSNS( XML_w, XML_position ),
1009 FSNS( XML_w, XML_sz ),
1010 FSNS( XML_w, XML_szCs ),
1011 FSNS( XML_w, XML_highlight ),
1012 FSNS( XML_w, XML_u ),
1013 FSNS( XML_w, XML_effect ),
1014 FSNS( XML_w, XML_bdr ),
1015 FSNS( XML_w, XML_shd ),
1016 FSNS( XML_w, XML_fitText ),
1017 FSNS( XML_w, XML_vertAlign ),
1018 FSNS( XML_w, XML_rtl ),
1019 FSNS( XML_w, XML_cs ),
1020 FSNS( XML_w, XML_em ),
1021 FSNS( XML_w, XML_lang ),
1022 FSNS( XML_w, XML_eastAsianLayout ),
1023 FSNS( XML_w, XML_specVanish ),
1024 FSNS( XML_w, XML_oMath ),
1025 FSNS( XML_w, XML_rPrChange )
1028 // postpone the output so that we can later [in EndParagraphProperties()]
1029 // prepend the properties before the run
1030 sal_Int32 len = sizeof ( aOrder ) / sizeof( sal_Int32 );
1031 uno::Sequence< sal_Int32 > aSeqOrder( len );
1032 for ( sal_Int32 i = 0; i < len; i++ )
1033 aSeqOrder[i] = aOrder[i];
1035 m_pSerializer->mark( aSeqOrder );
1039 void DocxAttributeOutput::WriteCollectedRunProperties()
1041 // Write all differed properties
1042 if ( m_pFontsAttrList )
1044 XFastAttributeListRef xAttrList( m_pFontsAttrList );
1045 m_pFontsAttrList = NULL;
1047 m_pSerializer->singleElementNS( XML_w, XML_rFonts, xAttrList );
1050 if ( m_pEastAsianLayoutAttrList )
1052 XFastAttributeListRef xAttrList( m_pEastAsianLayoutAttrList );
1053 m_pEastAsianLayoutAttrList = NULL;
1055 m_pSerializer->singleElementNS( XML_w, XML_eastAsianLayout, xAttrList );
1058 if ( m_pCharLangAttrList )
1060 XFastAttributeListRef xAttrList( m_pCharLangAttrList );
1061 m_pCharLangAttrList = NULL;
1063 m_pSerializer->singleElementNS( XML_w, XML_lang, xAttrList );
1066 // Merge the marks for the ordered elements
1067 m_pSerializer->mergeTopMarks();
1070 void DocxAttributeOutput::EndRunProperties( const SwRedlineData* /*pRedlineData*/ )
1072 WriteCollectedRunProperties();
1074 m_pSerializer->endElementNS( XML_w, XML_rPr );
1076 // Clone <rPr>...</rPr> for later re-use, in pPr
1077 m_pSerializer->copyTopMarkPush();
1079 // write footnotes/endnotes if we have any
1080 FootnoteEndnoteReference();
1082 WritePostponedGraphic();
1084 // merge the properties _before_ the run text (strictly speaking, just
1085 // after the start of the run)
1086 m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND );
1089 void DocxAttributeOutput::WritePostponedGraphic()
1091 for( std::list< PostponedGraphic >::const_iterator it = m_postponedGraphic->begin();
1092 it != m_postponedGraphic->end();
1093 ++it )
1094 FlyFrameGraphic( it->grfNode, it->size );
1095 delete m_postponedGraphic;
1096 m_postponedGraphic = NULL;
1099 void DocxAttributeOutput::FootnoteEndnoteRefTag()
1101 if( m_footnoteEndnoteRefTag == 0 )
1102 return;
1103 m_pSerializer->singleElementNS( XML_w, m_footnoteEndnoteRefTag, FSEND );
1104 m_footnoteEndnoteRefTag = 0;
1107 /** Output sal_Unicode* as a run text (<t>the text</t>).
1109 When bMove is true, update rBegin to point _after_ the end of the text +
1110 1, meaning that it skips one character after the text. This is to make
1111 the switch in DocxAttributeOutput::RunText() nicer ;-)
1113 static void impl_WriteRunText( FSHelperPtr pSerializer, sal_Int32 nTextToken,
1114 const sal_Unicode* &rBegin, const sal_Unicode* pEnd, bool bMove = true )
1116 const sal_Unicode *pBegin = rBegin;
1118 // skip one character after the end
1119 if ( bMove )
1120 rBegin = pEnd + 1;
1122 if ( pBegin >= pEnd )
1123 return; // we want to write at least one character
1125 // we have to add 'preserve' when starting/ending with space
1126 if ( *pBegin == sal_Unicode( ' ' ) || *( pEnd - 1 ) == sal_Unicode( ' ' ) )
1128 pSerializer->startElementNS( XML_w, nTextToken, FSNS( XML_xml, XML_space ), "preserve", FSEND );
1130 else
1131 pSerializer->startElementNS( XML_w, nTextToken, FSEND );
1133 pSerializer->writeEscaped( OUString( pBegin, pEnd - pBegin ) );
1135 pSerializer->endElementNS( XML_w, nTextToken );
1138 void DocxAttributeOutput::RunText( const String& rText, rtl_TextEncoding /*eCharSet*/ )
1140 if( m_closeHyperlinkInThisRun )
1142 m_closeHyperlinkInPreviousRun = true;
1143 m_closeHyperlinkInThisRun = false;
1145 OUString aText( rText );
1147 // one text can be split into more <w:t>blah</w:t>'s by line breaks etc.
1148 const sal_Unicode *pBegin = aText.getStr();
1149 const sal_Unicode *pEnd = pBegin + aText.getLength();
1151 // the text run is usually XML_t, with the exception of the deleted text
1152 sal_Int32 nTextToken = XML_t;
1153 if ( m_pRedlineData && m_pRedlineData->GetType() == nsRedlineType_t::REDLINE_DELETE )
1154 nTextToken = XML_delText;
1156 for ( const sal_Unicode *pIt = pBegin; pIt < pEnd; ++pIt )
1158 switch ( *pIt )
1160 case 0x09: // tab
1161 impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pIt );
1162 m_pSerializer->singleElementNS( XML_w, XML_tab, FSEND );
1163 break;
1164 case 0x0b: // line break
1165 impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pIt );
1166 m_pSerializer->singleElementNS( XML_w, XML_br, FSEND );
1167 break;
1168 case 0x1E: //non-breaking hyphen
1169 impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pIt );
1170 m_pSerializer->singleElementNS( XML_w, XML_noBreakHyphen, FSEND );
1171 break;
1172 case 0x1F: //soft (on demand) hyphen
1173 impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pIt );
1174 m_pSerializer->singleElementNS( XML_w, XML_softHyphen, FSEND );
1175 break;
1176 default:
1177 if ( *pIt < 0x0020 ) // filter out the control codes
1179 impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pIt );
1180 OSL_TRACE( "Ignored control code %x in a text run.", *pIt );
1182 break;
1186 impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pEnd, false );
1189 void DocxAttributeOutput::RawText( const String& /*rText*/, bool /*bForceUnicode*/, rtl_TextEncoding /*eCharSet*/ )
1191 OSL_TRACE("TODO DocxAttributeOutput::RawText( const String& rText, bool bForceUnicode, rtl_TextEncoding eCharSet )" );
1194 void DocxAttributeOutput::StartRuby( const SwTxtNode& rNode, xub_StrLen nPos, const SwFmtRuby& rRuby )
1196 OSL_TRACE("TODO DocxAttributeOutput::StartRuby( const SwTxtNode& rNode, const SwFmtRuby& rRuby )" );
1197 m_pSerializer->startElementNS( XML_w, XML_ruby, FSEND );
1198 m_pSerializer->startElementNS( XML_w, XML_rubyPr, FSEND );
1199 // hps
1200 // hpsBaseText
1201 // hpsRaise
1202 // lid
1203 lang::Locale aLocale( SwBreakIt::Get()->GetLocale(
1204 rNode.GetLang( nPos ) ) );
1205 OUString sLang( aLocale.Language );
1206 if ( !aLocale.Country.isEmpty() )
1207 sLang += "-" + aLocale.Country;
1208 m_pSerializer->singleElementNS( XML_w, XML_lid,
1209 FSNS( XML_w, XML_val ),
1210 OUStringToOString( sLang, RTL_TEXTENCODING_UTF8 ).getStr( ), FSEND );
1212 OString sAlign ( "center" );
1213 switch ( rRuby.GetAdjustment( ) )
1215 case 0:
1216 sAlign = OString( "left" );
1217 break;
1218 case 1:
1219 // Defaults to center
1220 break;
1221 case 2:
1222 sAlign = OString( "right" );
1223 break;
1224 case 3:
1225 sAlign = OString( "distributeLetter" );
1226 break;
1227 case 4:
1228 sAlign = OString( "distributeSpace" );
1229 break;
1230 default:
1231 break;
1233 m_pSerializer->singleElementNS( XML_w, XML_rubyAlign,
1234 FSNS( XML_w, XML_val ), sAlign.getStr(), FSEND );
1235 m_pSerializer->endElementNS( XML_w, XML_rubyPr );
1237 m_pSerializer->startElementNS( XML_w, XML_rt, FSEND );
1238 StartRun( NULL );
1239 StartRunProperties( );
1240 SwWW8AttrIter aAttrIt( m_rExport, rNode );
1241 aAttrIt.OutAttr( nPos, true );
1242 sal_uInt16 nStyle = m_rExport.GetId( *rRuby.GetTxtRuby()->GetCharFmt() );
1243 OString aStyleId( "style" );
1244 aStyleId += OString::valueOf( sal_Int32( nStyle ) );
1245 m_pSerializer->singleElementNS( XML_w, XML_rStyle,
1246 FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND );
1247 EndRunProperties( NULL );
1248 RunText( rRuby.GetText( ) );
1249 EndRun( );
1250 m_pSerializer->endElementNS( XML_w, XML_rt );
1252 m_pSerializer->startElementNS( XML_w, XML_rubyBase, FSEND );
1253 StartRun( NULL );
1256 void DocxAttributeOutput::EndRuby()
1258 OSL_TRACE( "TODO DocxAttributeOutput::EndRuby()" );
1259 EndRun( );
1260 m_pSerializer->endElementNS( XML_w, XML_rubyBase );
1261 m_pSerializer->endElementNS( XML_w, XML_ruby );
1264 bool DocxAttributeOutput::AnalyzeURL( const String& rUrl, const String& rTarget, String* pLinkURL, String* pMark )
1266 bool bBookMarkOnly = AttributeOutputBase::AnalyzeURL( rUrl, rTarget, pLinkURL, pMark );
1268 String sURL = *pLinkURL;
1269 String sMark = *pMark;
1271 bool bOutputField = sMark.Len();
1273 if ( bOutputField )
1275 if ( bBookMarkOnly )
1276 sURL = FieldString( ww::eHYPERLINK );
1277 else
1279 String sFld( FieldString( ww::eHYPERLINK ) );
1280 sFld.AppendAscii( "\"" );
1281 sURL.Insert( sFld, 0 );
1282 sURL += '\"';
1285 if ( sMark.Len() )
1286 ( ( sURL.AppendAscii( " \\l \"" ) ) += sMark ) += '\"';
1288 if ( rTarget.Len() )
1289 ( sURL.AppendAscii( " \\n " ) ) += rTarget;
1292 *pLinkURL = sURL;
1293 *pMark = sMark;
1295 return bBookMarkOnly;
1298 bool DocxAttributeOutput::StartURL( const String& rUrl, const String& rTarget )
1300 String sMark;
1301 String sUrl;
1303 bool bBookmarkOnly = AnalyzeURL( rUrl, rTarget, &sUrl, &sMark );
1305 if ( sMark.Len() && !bBookmarkOnly )
1307 m_rExport.OutputField( NULL, ww::eHYPERLINK, sUrl );
1309 else
1311 // Output a hyperlink XML element
1312 m_pHyperlinkAttrList = m_pSerializer->createAttrList();
1314 if ( !bBookmarkOnly )
1316 OUString osUrl( sUrl );
1318 OString sId = OUStringToOString( GetExport().GetFilter().addRelation( m_pSerializer->getOutputStream(),
1319 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
1320 osUrl, true ), RTL_TEXTENCODING_UTF8 );
1322 m_pHyperlinkAttrList->add( FSNS( XML_r, XML_id), sId.getStr());
1324 else
1326 // Is this a link to a sequence? Then try to replace that with a
1327 // normal bookmark, as Word won't understand our special
1328 // <seqname>!<index>|sequence syntax.
1329 OUString aMark(sMark);
1330 if (aMark.endsWith("|sequence"))
1332 sal_Int32 nPos = aMark.indexOf('!');
1333 if (nPos != -1)
1335 // Extract <seqname>, the field instruction text has the name quoted.
1336 OUString aSequenceName = OUString('"') + aMark.copy(0, nPos) + OUString('"');
1337 // Extract <index>.
1338 sal_uInt32 nIndex = aMark.copy(nPos + 1, aMark.getLength() - nPos - sizeof("|sequence")).toInt32();
1339 std::map<OUString, std::vector<OString> >::iterator it = m_aSeqMarksNames.find(aSequenceName);
1340 if (it != m_aSeqMarksNames.end())
1342 std::vector<OString>& rNames = it->second;
1343 if (rNames.size() > nIndex)
1344 // We know the bookmark name for this sequence and this index, do the replacement.
1345 sMark = OStringToOUString(rNames[nIndex], RTL_TEXTENCODING_UTF8);
1349 m_pHyperlinkAttrList->add( FSNS( XML_w, XML_anchor ),
1350 OUStringToOString( OUString( sMark ), RTL_TEXTENCODING_UTF8 ).getStr( ) );
1353 OUString sTarget( rTarget );
1354 if ( !sTarget.isEmpty() )
1356 OString soTarget = OUStringToOString( sTarget, RTL_TEXTENCODING_UTF8 );
1357 m_pHyperlinkAttrList->add(FSNS( XML_w, XML_tgtFrame ), soTarget.getStr());
1361 return true;
1364 bool DocxAttributeOutput::EndURL()
1366 m_closeHyperlinkInThisRun = true;
1367 return true;
1370 void DocxAttributeOutput::FieldVanish( const String& rTxt, ww::eField eType )
1372 WriteField_Impl( NULL, eType, rTxt, WRITEFIELD_ALL );
1375 void DocxAttributeOutput::Redline( const SwRedlineData* /*pRedline*/ )
1377 OSL_TRACE( "TODO DocxAttributeOutput::Redline( const SwRedlineData* pRedline )" );
1380 void DocxAttributeOutput::StartRedline()
1382 if ( !m_pRedlineData )
1383 return;
1384 const SwRedlineData* pRedlineData = m_pRedlineData;
1386 // FIXME check if it's necessary to travel over the Next()'s in pRedlineData
1388 OString aId( OString::valueOf( m_nRedlineId++ ) );
1390 const String &rAuthor( SW_MOD()->GetRedlineAuthor( pRedlineData->GetAuthor() ) );
1391 OString aAuthor( OUStringToOString( rAuthor, RTL_TEXTENCODING_UTF8 ) );
1393 OString aDate( msfilter::util::DateTimeToOString( pRedlineData->GetTimeStamp() ) );
1395 switch ( pRedlineData->GetType() )
1397 case nsRedlineType_t::REDLINE_INSERT:
1398 m_pSerializer->startElementNS( XML_w, XML_ins,
1399 FSNS( XML_w, XML_id ), aId.getStr(),
1400 FSNS( XML_w, XML_author ), aAuthor.getStr(),
1401 FSNS( XML_w, XML_date ), aDate.getStr(),
1402 FSEND );
1403 break;
1405 case nsRedlineType_t::REDLINE_DELETE:
1406 m_pSerializer->startElementNS( XML_w, XML_del,
1407 FSNS( XML_w, XML_id ), aId.getStr(),
1408 FSNS( XML_w, XML_author ), aAuthor.getStr(),
1409 FSNS( XML_w, XML_date ), aDate.getStr(),
1410 FSEND );
1411 break;
1413 case nsRedlineType_t::REDLINE_FORMAT:
1414 OSL_TRACE( "TODO DocxAttributeOutput::StartRedline()" );
1415 default:
1416 break;
1420 void DocxAttributeOutput::EndRedline()
1422 if ( !m_pRedlineData )
1423 return;
1425 switch ( m_pRedlineData->GetType() )
1427 case nsRedlineType_t::REDLINE_INSERT:
1428 m_pSerializer->endElementNS( XML_w, XML_ins );
1429 break;
1431 case nsRedlineType_t::REDLINE_DELETE:
1432 m_pSerializer->endElementNS( XML_w, XML_del );
1433 break;
1435 case nsRedlineType_t::REDLINE_FORMAT:
1436 OSL_TRACE( "TODO DocxAttributeOutput::EndRedline()" );
1437 break;
1438 default:
1439 break;
1442 m_pRedlineData = NULL;
1445 void DocxAttributeOutput::FormatDrop( const SwTxtNode& /*rNode*/, const SwFmtDrop& /*rSwFmtDrop*/, sal_uInt16 /*nStyle*/, ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/, ww8::WW8TableNodeInfoInner::Pointer_t )
1447 OSL_TRACE( "TODO DocxAttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop& rSwFmtDrop, sal_uInt16 nStyle )" );
1450 void DocxAttributeOutput::ParagraphStyle( sal_uInt16 nStyle )
1452 OString aStyleId( "style" );
1453 aStyleId += OString::valueOf( sal_Int32( nStyle ) );
1455 m_pSerializer->singleElementNS( XML_w, XML_pStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND );
1458 static void impl_borderLine( FSHelperPtr pSerializer, sal_Int32 elementToken, const SvxBorderLine* pBorderLine, sal_uInt16 nDist )
1460 FastAttributeList* pAttr = pSerializer->createAttrList();
1463 // Compute val attribute value
1464 // Can be one of:
1465 // single, double,
1466 // basicWideOutline, basicWideInline
1467 // OOXml also supports those types of borders, but we'll try to play with the first ones.
1468 // thickThinMediumGap, thickThinLargeGap, thickThinSmallGap
1469 // thinThickLargeGap, thinThickMediumGap, thinThickSmallGap
1470 const char* pVal = "nil";
1471 if ( pBorderLine && !pBorderLine->isEmpty( ) )
1473 switch (pBorderLine->GetBorderLineStyle())
1475 case table::BorderLineStyle::SOLID:
1476 pVal = ( sal_Char* )"single";
1477 break;
1478 case table::BorderLineStyle::DOTTED:
1479 pVal = ( sal_Char* )"dotted";
1480 break;
1481 case table::BorderLineStyle::DASHED:
1482 pVal = ( sal_Char* )"dashed";
1483 break;
1484 case table::BorderLineStyle::DOUBLE:
1485 pVal = ( sal_Char* )"double";
1486 break;
1487 case table::BorderLineStyle::THINTHICK_SMALLGAP:
1488 pVal = ( sal_Char* )"thinThickSmallGap";
1489 break;
1490 case table::BorderLineStyle::THINTHICK_MEDIUMGAP:
1491 pVal = ( sal_Char* )"thinThickMediumGap";
1492 break;
1493 case table::BorderLineStyle::THINTHICK_LARGEGAP:
1494 pVal = ( sal_Char* )"thinThickLargeGap";
1495 break;
1496 case table::BorderLineStyle::THICKTHIN_SMALLGAP:
1497 pVal = ( sal_Char* )"thickThinSmallGap";
1498 break;
1499 case table::BorderLineStyle::THICKTHIN_MEDIUMGAP:
1500 pVal = ( sal_Char* )"thickThinMediumGap";
1501 break;
1502 case table::BorderLineStyle::THICKTHIN_LARGEGAP:
1503 pVal = ( sal_Char* )"thickThinLargeGap";
1504 break;
1505 case table::BorderLineStyle::EMBOSSED:
1506 pVal = ( sal_Char* )"threeDEmboss";
1507 break;
1508 case table::BorderLineStyle::ENGRAVED:
1509 pVal = ( sal_Char* )"threeDEngrave";
1510 break;
1511 case table::BorderLineStyle::OUTSET:
1512 pVal = ( sal_Char* )"outset";
1513 break;
1514 case table::BorderLineStyle::INSET:
1515 pVal = ( sal_Char* )"inset";
1516 break;
1517 case table::BorderLineStyle::FINE_DASHED:
1518 pVal = ( sal_Char* )"dashSmallGap";
1519 break;
1520 case table::BorderLineStyle::NONE:
1521 default:
1522 break;
1526 pAttr->add( FSNS( XML_w, XML_val ), OString( pVal ) );
1528 if ( pBorderLine && !pBorderLine->isEmpty() )
1530 // Compute the sz attribute
1532 double const fConverted( ::editeng::ConvertBorderWidthToWord(
1533 pBorderLine->GetBorderLineStyle(), pBorderLine->GetWidth()));
1534 // The unit is the 8th of point
1535 sal_Int32 nWidth = sal_Int32( fConverted / 2.5 );
1536 sal_uInt16 nMinWidth = 2;
1537 sal_uInt16 nMaxWidth = 96;
1539 if ( nWidth > nMaxWidth )
1540 nWidth = nMaxWidth;
1541 else if ( nWidth < nMinWidth )
1542 nWidth = nMinWidth;
1544 pAttr->add( FSNS( XML_w, XML_sz ), OString::valueOf( sal_Int32( nWidth ) ) );
1546 // Get the distance (in pt)
1547 pAttr->add( FSNS( XML_w, XML_space ), OString::valueOf( sal_Int32( nDist / 20 ) ) );
1549 // Get the color code as an RRGGBB hex value
1550 OString sColor( msfilter::util::ConvertColor( pBorderLine->GetColor( ) ) );
1551 pAttr->add( FSNS( XML_w, XML_color ), sColor );
1554 XFastAttributeListRef xAttrs( pAttr );
1555 pSerializer->singleElementNS( XML_w, elementToken, xAttrs );
1558 static void impl_pageBorders( FSHelperPtr pSerializer, const SvxBoxItem& rBox, sal_Int32 tag, bool bUseStartEnd = false, bool bWriteTag = true, const SvxBoxItem* pDefaultBorders = 0)
1560 static const sal_uInt16 aBorders[] =
1562 BOX_LINE_TOP, BOX_LINE_LEFT, BOX_LINE_BOTTOM, BOX_LINE_RIGHT
1565 const sal_Int32 aXmlElements[] =
1567 XML_top,
1568 bUseStartEnd ? XML_start : XML_left,
1569 XML_bottom,
1570 bUseStartEnd ? XML_end : XML_right
1572 bool tagWritten = false;
1573 const sal_uInt16* pBrd = aBorders;
1574 for( int i = 0; i < 4; ++i, ++pBrd )
1576 const SvxBorderLine* pLn = rBox.GetLine( *pBrd );
1578 if (!tagWritten && bWriteTag) {
1579 pSerializer->startElementNS( XML_w, tag, FSEND );
1580 tagWritten = true;
1583 impl_borderLine( pSerializer, aXmlElements[i], pLn, 0 );
1585 // When exporting default borders, we need to export these 2 attr
1586 if ( pDefaultBorders == 0 ) {
1587 if ( i == 2 )
1588 impl_borderLine( pSerializer, XML_insideH, pLn, 0 );
1589 else if ( i == 3 )
1590 impl_borderLine( pSerializer, XML_insideV, pLn, 0 );
1593 if (tagWritten && bWriteTag) {
1594 pSerializer->endElementNS( XML_w, tag );
1598 static void impl_cellMargins( FSHelperPtr pSerializer, const SvxBoxItem& rBox, sal_Int32 tag, bool bUseStartEnd = false, const SvxBoxItem* pDefaultMargins = 0)
1600 static const sal_uInt16 aBorders[] =
1602 BOX_LINE_TOP, BOX_LINE_LEFT, BOX_LINE_BOTTOM, BOX_LINE_RIGHT
1605 const sal_Int32 aXmlElements[] =
1607 XML_top,
1608 bUseStartEnd ? XML_start : XML_left,
1609 XML_bottom,
1610 bUseStartEnd ? XML_end : XML_right
1612 bool tagWritten = false;
1613 const sal_uInt16* pBrd = aBorders;
1614 for( int i = 0; i < 4; ++i, ++pBrd )
1616 sal_Int32 nDist = sal_Int32( rBox.GetDistance( *pBrd ) );
1618 if ( aBorders[i] == BOX_LINE_LEFT ) {
1619 // Office's cell margin is measured from the right of the border.
1620 // While LO's cell spacing is measured from the center of the border.
1621 // So we add half left-border width to tblIndent value
1622 const SvxBorderLine* pLn = rBox.GetLine( *pBrd );
1623 if (pLn)
1624 nDist -= pLn->GetWidth() * 0.5;
1627 if (pDefaultMargins)
1629 // Skip output if cell margin == table default margin
1630 if (sal_Int32( pDefaultMargins->GetDistance( *pBrd ) ) == nDist)
1631 continue;
1634 if (!tagWritten) {
1635 pSerializer->startElementNS( XML_w, tag, FSEND );
1636 tagWritten = true;
1638 pSerializer->singleElementNS( XML_w, aXmlElements[i],
1639 FSNS( XML_w, XML_w ), OString::valueOf( nDist ).getStr( ),
1640 FSNS( XML_w, XML_type ), "dxa",
1641 FSEND );
1643 if (tagWritten) {
1644 pSerializer->endElementNS( XML_w, tag );
1648 void DocxAttributeOutput::TableCellProperties( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1650 m_pSerializer->startElementNS( XML_w, XML_tcPr, FSEND );
1652 const SwTableBox *pTblBox = pTableTextNodeInfoInner->getTableBox( );
1654 bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT;
1656 // Cell prefered width
1657 SwTwips nWidth = GetGridCols( pTableTextNodeInfoInner )->at( pTableTextNodeInfoInner->getCell() );
1658 if ( pTableTextNodeInfoInner->getCell() )
1659 nWidth = nWidth - GetGridCols( pTableTextNodeInfoInner )->at( pTableTextNodeInfoInner->getCell() - 1 );
1660 m_pSerializer->singleElementNS( XML_w, XML_tcW,
1661 FSNS( XML_w, XML_w ), OString::valueOf( sal_Int32( nWidth ) ).getStr( ),
1662 FSNS( XML_w, XML_type ), "dxa",
1663 FSEND );
1665 // Horizontal spans
1666 const SwWriteTableRows& aRows = m_pTableWrt->GetRows( );
1667 SwWriteTableRow *pRow = aRows[ pTableTextNodeInfoInner->getRow( ) ];
1668 const SwWriteTableCell *pCell = &pRow->GetCells( )[ pTableTextNodeInfoInner->getCell( ) ];
1670 sal_uInt16 nColSpan = pCell->GetColSpan();
1671 if ( nColSpan > 1 )
1672 m_pSerializer->singleElementNS( XML_w, XML_gridSpan,
1673 FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nColSpan ) ).getStr(),
1674 FSEND );
1676 // Vertical merges
1677 long vSpan = pTblBox->getRowSpan( );
1678 if ( vSpan > 1 )
1680 m_pSerializer->singleElementNS( XML_w, XML_vMerge,
1681 FSNS( XML_w, XML_val ), "restart",
1682 FSEND );
1684 else if ( vSpan < 0 )
1686 m_pSerializer->singleElementNS( XML_w, XML_vMerge,
1687 FSNS( XML_w, XML_val ), "continue",
1688 FSEND );
1691 const SvxBoxItem& rBox = pTblBox->GetFrmFmt( )->GetBox( );
1692 const SvxBoxItem& rDefaultBox = (*tableFirstCells.rbegin())->getTableBox( )->GetFrmFmt( )->GetBox( );
1694 // The cell borders
1695 impl_pageBorders( m_pSerializer, rBox, XML_tcBorders, !bEcma, true, &rDefaultBox );
1698 TableBackgrounds( pTableTextNodeInfoInner );
1701 // Cell margins
1702 impl_cellMargins( m_pSerializer, rBox, XML_tcMar, !bEcma, &rDefaultBox );
1705 TableVerticalCell( pTableTextNodeInfoInner );
1707 m_pSerializer->endElementNS( XML_w, XML_tcPr );
1710 void DocxAttributeOutput::InitTableHelper( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1712 sal_uInt32 nPageSize = 0;
1713 bool bRelBoxSize = false;
1715 // Create the SwWriteTable instance to use col spans (and maybe other infos)
1716 GetTablePageSize( pTableTextNodeInfoInner.get(), nPageSize, bRelBoxSize );
1718 const SwTable* pTable = pTableTextNodeInfoInner->getTable( );
1719 const SwFrmFmt *pFmt = pTable->GetFrmFmt( );
1720 SwTwips nTblSz = pFmt->GetFrmSize( ).GetWidth( );
1722 const SwHTMLTableLayout *pLayout = pTable->GetHTMLTableLayout();
1723 if( pLayout && pLayout->IsExportable() )
1724 m_pTableWrt = new SwWriteTable( pLayout );
1725 else
1726 m_pTableWrt = new SwWriteTable( pTable->GetTabLines(), (sal_uInt16)nPageSize,
1727 (sal_uInt16)nTblSz, false);
1730 void DocxAttributeOutput::StartTable( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1732 m_pSerializer->startElementNS( XML_w, XML_tbl, FSEND );
1734 tableFirstCells.push_back(pTableTextNodeInfoInner);
1736 InitTableHelper( pTableTextNodeInfoInner );
1737 TableDefinition( pTableTextNodeInfoInner );
1740 void DocxAttributeOutput::EndTable()
1742 m_pSerializer->endElementNS( XML_w, XML_tbl );
1744 if ( m_nTableDepth > 0 )
1745 --m_nTableDepth;
1747 tableFirstCells.pop_back();
1749 // We closed the table; if it is a nested table, the cell that contains it
1750 // still continues
1751 m_bTableCellOpen = true;
1753 // Cleans the table helper
1754 delete m_pTableWrt, m_pTableWrt = NULL;
1757 void DocxAttributeOutput::StartTableRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1759 m_pSerializer->startElementNS( XML_w, XML_tr, FSEND );
1761 // Output the row properties
1762 m_pSerializer->startElementNS( XML_w, XML_trPr, FSEND );
1764 // Header row: tblHeader
1765 const SwTable *pTable = pTableTextNodeInfoInner->getTable( );
1766 if ( pTable->GetRowsToRepeat( ) > pTableTextNodeInfoInner->getRow( ) )
1767 m_pSerializer->singleElementNS( XML_w, XML_tblHeader,
1768 FSNS( XML_w, XML_val ), "true",
1769 FSEND );
1771 TableHeight( pTableTextNodeInfoInner );
1772 TableCanSplit( pTableTextNodeInfoInner );
1774 m_pSerializer->endElementNS( XML_w, XML_trPr );
1777 void DocxAttributeOutput::EndTableRow( )
1779 m_pSerializer->endElementNS( XML_w, XML_tr );
1782 void DocxAttributeOutput::StartTableCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1784 if ( !m_pTableWrt )
1785 InitTableHelper( pTableTextNodeInfoInner );
1787 m_pSerializer->startElementNS( XML_w, XML_tc, FSEND );
1789 // Write the cell properties here
1790 TableCellProperties( pTableTextNodeInfoInner );
1792 m_bTableCellOpen = true;
1795 void DocxAttributeOutput::EndTableCell( )
1797 m_pSerializer->endElementNS( XML_w, XML_tc );
1799 m_bBtLr = false;
1800 m_bTableCellOpen = false;
1803 void DocxAttributeOutput::TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ )
1807 void DocxAttributeOutput::TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfo*/ )
1811 void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1813 bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT;
1815 // Write the table properties
1816 m_pSerializer->startElementNS( XML_w, XML_tblPr, FSEND );
1818 static const sal_Int32 aOrder[] =
1820 FSNS( XML_w, XML_tblStyle ),
1821 FSNS( XML_w, XML_tblpPr ),
1822 FSNS( XML_w, XML_tblOverlap ),
1823 FSNS( XML_w, XML_bidiVisual ),
1824 FSNS( XML_w, XML_tblStyleRowBandSize ),
1825 FSNS( XML_w, XML_tblStyleColBandSize ),
1826 FSNS( XML_w, XML_tblW ),
1827 FSNS( XML_w, XML_jc ),
1828 FSNS( XML_w, XML_tblCellSpacing ),
1829 FSNS( XML_w, XML_tblInd ),
1830 FSNS( XML_w, XML_tblBorders ),
1831 FSNS( XML_w, XML_shd ),
1832 FSNS( XML_w, XML_tblLayout ),
1833 FSNS( XML_w, XML_tblCellMar ),
1834 FSNS( XML_w, XML_tblLook ),
1835 FSNS( XML_w, XML_tblPrChange )
1838 // postpone the output so that we can later []
1839 // prepend the properties before the run
1840 sal_Int32 len = sizeof ( aOrder ) / sizeof( sal_Int32 );
1841 uno::Sequence< sal_Int32 > aSeqOrder( len );
1842 for ( sal_Int32 i = 0; i < len; i++ )
1843 aSeqOrder[i] = aOrder[i];
1845 m_pSerializer->mark( aSeqOrder );
1847 sal_uInt32 nPageSize = 0;
1848 bool bRelBoxSize = false;
1850 // Create the SwWriteTable instance to use col spans (and maybe other infos)
1851 GetTablePageSize( pTableTextNodeInfoInner.get(), nPageSize, bRelBoxSize );
1853 // Output the table prefered width
1854 if ( nPageSize != 0 )
1855 m_pSerializer->singleElementNS( XML_w, XML_tblW,
1856 FSNS( XML_w, XML_w ), OString::valueOf( sal_Int32( nPageSize ) ).getStr( ),
1857 FSNS( XML_w, XML_type ), "dxa",
1858 FSEND );
1860 // Output the table alignement
1861 const SwTable *pTable = pTableTextNodeInfoInner->getTable();
1862 SwFrmFmt *pTblFmt = pTable->GetFrmFmt( );
1863 const char* pJcVal;
1864 sal_Int32 nIndent = 0;
1865 switch ( pTblFmt->GetHoriOrient( ).GetHoriOrient( ) )
1867 case text::HoriOrientation::CENTER:
1868 pJcVal = "center";
1869 break;
1870 case text::HoriOrientation::RIGHT:
1871 if ( bEcma )
1872 pJcVal = "right";
1873 else
1874 pJcVal = "end";
1875 break;
1876 default:
1877 case text::HoriOrientation::NONE:
1878 case text::HoriOrientation::LEFT_AND_WIDTH:
1880 if ( bEcma )
1881 pJcVal = "left";
1882 else
1883 pJcVal = "start";
1884 nIndent = sal_Int32( pTblFmt->GetLRSpace( ).GetLeft( ) );
1885 // Table indentation has different meaning in Word, depending if the table is nested or not.
1886 // If nested, tblInd is added to parent table's left spacing and defines left edge position
1887 // If not nested, text position of left-most cell must be at absolute X = tblInd
1888 // so, table_spacing + table_spacing_to_content = tblInd
1889 if (m_nTableDepth == 0)
1891 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
1892 const SwFrmFmt * pFrmFmt = pTabBox->GetFrmFmt();
1893 nIndent += sal_Int32( pFrmFmt->GetBox( ).GetDistance( BOX_LINE_LEFT ) );
1895 break;
1898 m_pSerializer->singleElementNS( XML_w, XML_jc,
1899 FSNS( XML_w, XML_val ), pJcVal,
1900 FSEND );
1902 // Output the table borders
1903 TableDefaultBorders( pTableTextNodeInfoInner );
1905 // Output the default cell margins
1906 TableDefaultCellMargins( pTableTextNodeInfoInner );
1908 TableBidi( pTableTextNodeInfoInner );
1910 // Table indent (need to get written even if == 0)
1911 m_pSerializer->singleElementNS( XML_w, XML_tblInd,
1912 FSNS( XML_w, XML_w ), OString::valueOf( nIndent ).getStr( ),
1913 FSNS( XML_w, XML_type ), "dxa",
1914 FSEND );
1916 // Merge the marks for the ordered elements
1917 m_pSerializer->mergeTopMarks( );
1919 m_pSerializer->endElementNS( XML_w, XML_tblPr );
1921 // Write the table grid infos
1922 m_pSerializer->startElementNS( XML_w, XML_tblGrid, FSEND );
1923 sal_Int32 nPrv = 0;
1924 ww8::GridColsPtr pGridCols = GetGridCols( pTableTextNodeInfoInner );
1925 for ( ww8::GridCols::const_iterator it = pGridCols->begin(); it != pGridCols->end(); ++it )
1927 sal_Int32 nWidth = sal_Int32( *it ) - nPrv;
1928 m_pSerializer->singleElementNS( XML_w, XML_gridCol,
1929 FSNS( XML_w, XML_w ), OString::valueOf( nWidth ).getStr( ),
1930 FSEND );
1931 nPrv = sal_Int32( *it );
1934 m_pSerializer->endElementNS( XML_w, XML_tblGrid );
1937 void DocxAttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1939 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
1940 const SwFrmFmt * pFrmFmt = pTabBox->GetFrmFmt();
1942 bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT;
1944 // the defaults of the table are taken from the top-left cell
1945 impl_pageBorders( m_pSerializer, pFrmFmt->GetBox( ), XML_tblBorders, !bEcma, true );
1948 void DocxAttributeOutput::TableDefaultCellMargins( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1950 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
1951 const SwFrmFmt * pFrmFmt = pTabBox->GetFrmFmt();
1952 const SvxBoxItem& rBox = pFrmFmt->GetBox( );
1953 const bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT;
1955 impl_cellMargins(m_pSerializer, rBox, XML_tblCellMar, !bEcma);
1958 void DocxAttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1960 const SwTableBox *pTblBox = pTableTextNodeInfoInner->getTableBox( );
1961 const SwFrmFmt *pFmt = pTblBox->GetFrmFmt( );
1962 const SfxPoolItem *pI = NULL;
1964 Color aColor;
1965 if ( SFX_ITEM_ON == pFmt->GetAttrSet().GetItemState( RES_BACKGROUND, false, &pI ) )
1966 aColor = dynamic_cast<const SvxBrushItem *>(pI)->GetColor();
1967 else
1968 aColor = COL_AUTO;
1970 OString sColor = msfilter::util::ConvertColor( aColor );
1971 m_pSerializer->singleElementNS( XML_w, XML_shd,
1972 FSNS( XML_w, XML_fill ), sColor.getStr( ),
1973 FSNS( XML_w, XML_val ), "clear",
1974 FSEND );
1977 void DocxAttributeOutput::TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
1979 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
1980 const SwTableLine * pTabLine = pTabBox->GetUpper();
1981 const SwFrmFmt * pLineFmt = pTabLine->GetFrmFmt();
1983 const SwFmtFrmSize& rLSz = pLineFmt->GetFrmSize();
1984 if ( ATT_VAR_SIZE != rLSz.GetHeightSizeType() && rLSz.GetHeight() )
1986 sal_Int32 nHeight = rLSz.GetHeight();
1987 const char *pRule = NULL;
1989 switch ( rLSz.GetHeightSizeType() )
1991 case ATT_FIX_SIZE: pRule = "exact"; break;
1992 case ATT_MIN_SIZE: pRule = "atLeast"; break;
1993 default: break;
1996 if ( pRule )
1997 m_pSerializer->singleElementNS( XML_w, XML_trHeight,
1998 FSNS( XML_w, XML_val ), OString::valueOf( nHeight ).getStr( ),
1999 FSNS( XML_w, XML_hRule ), pRule,
2000 FSEND );
2004 void DocxAttributeOutput::TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2006 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2007 const SwTableLine * pTabLine = pTabBox->GetUpper();
2008 const SwFrmFmt * pLineFmt = pTabLine->GetFrmFmt();
2010 const SwFmtRowSplit& rSplittable = pLineFmt->GetRowSplit( );
2011 const char* pCantSplit = ( !rSplittable.GetValue( ) ) ? "true" : "false";
2013 m_pSerializer->singleElementNS( XML_w, XML_cantSplit,
2014 FSNS( XML_w, XML_val ), pCantSplit,
2015 FSEND );
2018 void DocxAttributeOutput::TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2020 const SwTable * pTable = pTableTextNodeInfoInner->getTable();
2021 const SwFrmFmt * pFrmFmt = pTable->GetFrmFmt();
2023 if ( m_rExport.TrueFrameDirection( *pFrmFmt ) == FRMDIR_HORI_RIGHT_TOP )
2025 m_pSerializer->singleElementNS( XML_w, XML_bidiVisual,
2026 FSNS( XML_w, XML_val ), "true",
2027 FSEND );
2031 void DocxAttributeOutput::TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )
2033 const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox();
2034 const SwFrmFmt *pFrmFmt = pTabBox->GetFrmFmt( );
2036 if ( FRMDIR_VERT_TOP_RIGHT == m_rExport.TrueFrameDirection( *pFrmFmt ) )
2037 m_pSerializer->singleElementNS( XML_w, XML_textDirection,
2038 FSNS( XML_w, XML_val ), "tbRl",
2039 FSEND );
2040 else if ( FRMDIR_HORI_LEFT_TOP == m_rExport.TrueFrameDirection( *pFrmFmt ) )
2042 // Undo the text direction mangling done by the btLr handler in writerfilter::dmapper::DomainMapperTableManager::sprm()
2043 SwPaM aPam(*pTabBox->GetSttNd(), 0);
2044 aPam.GetPoint()->nNode++;
2045 if (aPam.GetPoint()->nNode.GetNode().IsTxtNode())
2047 const SwTxtNode& rTxtNode = (const SwTxtNode&)aPam.GetPoint()->nNode.GetNode();
2048 if( const SwAttrSet* pAttrSet = rTxtNode.GetpSwAttrSet())
2050 const SvxCharRotateItem& rCharRotate = pAttrSet->GetCharRotate();
2051 if (rCharRotate.GetValue() == 900)
2053 m_pSerializer->singleElementNS( XML_w, XML_textDirection, FSNS( XML_w, XML_val ), "btLr", FSEND );
2054 m_bBtLr = true;
2060 const SwWriteTableRows& aRows = m_pTableWrt->GetRows( );
2061 SwWriteTableRow *pRow = aRows[ pTableTextNodeInfoInner->getRow( ) ];
2062 const SwWriteTableCell *pCell = &pRow->GetCells( )[ pTableTextNodeInfoInner->getCell( ) ];
2063 switch( pCell->GetVertOri())
2065 case text::VertOrientation::TOP:
2066 break;
2067 case text::VertOrientation::CENTER:
2068 m_pSerializer->singleElementNS( XML_w, XML_vAlign,
2069 FSNS( XML_w, XML_val ), "center", FSEND );
2070 break;
2071 case text::VertOrientation::BOTTOM:
2072 m_pSerializer->singleElementNS( XML_w, XML_vAlign,
2073 FSNS( XML_w, XML_val ), "bottom", FSEND );
2074 break;
2078 void DocxAttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t /*pNodeInfo*/ )
2080 OSL_TRACE( "TODO: DocxAttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t pNodeInfo )" );
2083 void DocxAttributeOutput::TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner )
2085 // This is called when the nested table ends in a cell, and there's no
2086 // paragraph benhind that; so we must check for the ends of cell, rows,
2087 // tables
2088 // ['true' to write an empty paragraph, MS Word insists on that]
2089 FinishTableRowCell( pNodeInfoInner, true );
2092 void DocxAttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ )
2094 OSL_TRACE( "TODO: DocxAttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )" );
2097 void DocxAttributeOutput::TableSpacing( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ )
2099 #if OSL_DEBUG_LEVEL > 1
2100 fprintf( stderr, "TODO: DocxAttributeOutput::TableSpacing( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )\n" );
2101 #endif
2104 void DocxAttributeOutput::TableRowEnd( sal_uInt32 /*nDepth*/ )
2106 OSL_TRACE( "TODO: DocxAttributeOutput::TableRowEnd( sal_uInt32 nDepth = 1 )" );
2109 void DocxAttributeOutput::StartStyles()
2111 m_pSerializer->startElementNS( XML_w, XML_styles,
2112 FSNS( XML_xmlns, XML_w ), "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
2113 FSEND );
2116 void DocxAttributeOutput::EndStyles( sal_uInt16 /*nNumberOfStyles*/ )
2118 m_pSerializer->endElementNS( XML_w, XML_styles );
2121 void DocxAttributeOutput::DefaultStyle( sal_uInt16 nStyle )
2123 // are these the values of enum ww::sti (see ../inc/wwstyles.hxx)?
2124 #if OSL_DEBUG_LEVEL > 1
2125 OSL_TRACE( "TODO DocxAttributeOutput::DefaultStyle( sal_uInt16 nStyle )- %d", nStyle );
2126 #else
2127 (void) nStyle; // to quiet the warning
2128 #endif
2131 void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size& rSize, const SwFlyFrmFmt* pOLEFrmFmt, SwOLENode* pOLENode )
2133 OSL_TRACE( "TODO DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size& rSize, const SwFlyFrmFmt* pOLEFrmFmt, SwOLENode* pOLENode ) - some stuff still missing" );
2134 // detect mis-use of the API
2135 assert(pGrfNode || (pOLEFrmFmt && pOLENode));
2136 const SwFrmFmt* pFrmFmt = pGrfNode ? pGrfNode->GetFlyFmt() : pOLEFrmFmt;
2137 // create the relation ID
2138 OString aRelId;
2139 sal_Int32 nImageType;
2140 if ( pGrfNode && pGrfNode->IsLinkedFile() )
2142 // linked image, just create the relation
2143 String aFileName;
2144 pGrfNode->GetFileFilterNms( &aFileName, 0 );
2146 // TODO Convert the file name to relative for better interoperability
2148 aRelId = m_rExport.AddRelation(
2149 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
2150 OUString( aFileName ) );
2152 nImageType = XML_link;
2154 else
2156 // inline, we also have to write the image itself
2157 const Graphic* pGraphic = 0;
2158 if (pGrfNode)
2159 pGraphic = &const_cast< Graphic& >( pGrfNode->GetGrf() );
2160 else
2161 pGraphic = pOLENode->GetGraphic();
2163 m_rDrawingML.SetFS( m_pSerializer ); // to be sure that we write to the right stream
2164 OUString aImageId = m_rDrawingML.WriteImage( *pGraphic );
2166 aRelId = OUStringToOString( aImageId, RTL_TEXTENCODING_UTF8 );
2168 nImageType = XML_embed;
2171 if ( aRelId.isEmpty() )
2172 return;
2174 m_pSerializer->startElementNS( XML_w, XML_drawing,
2175 FSEND );
2176 bool isAnchor = pFrmFmt->GetAnchor().GetAnchorId() != FLY_AS_CHAR;
2177 if( isAnchor )
2179 ::sax_fastparser::FastAttributeList* attrList = m_pSerializer->createAttrList();
2180 attrList->add( XML_behindDoc, pFrmFmt->GetOpaque().GetValue() ? "0" : "1" );
2181 attrList->add( XML_distT, "0" );
2182 attrList->add( XML_distB, "0" );
2183 attrList->add( XML_distL, "0" );
2184 attrList->add( XML_distR, "0" );
2185 attrList->add( XML_simplePos, "0" );
2186 attrList->add( XML_locked, "0" );
2187 attrList->add( XML_layoutInCell, "1" );
2188 attrList->add( XML_allowOverlap, "1" ); // TODO
2189 if( const SdrObject* pObj = pFrmFmt->FindRealSdrObject())
2190 attrList->add( XML_relativeHeight, OString::valueOf( sal_Int32( pObj->GetOrdNum())));
2191 m_pSerializer->startElementNS( XML_wp, XML_anchor, XFastAttributeListRef( attrList ));
2192 m_pSerializer->singleElementNS( XML_wp, XML_simplePos, XML_x, "0", XML_y, "0", FSEND ); // required, unused
2193 const char* relativeFromH;
2194 const char* relativeFromV;
2195 switch( pFrmFmt->GetAnchor().GetAnchorId())
2197 case FLY_AT_PAGE:
2198 relativeFromV = relativeFromH = "page";
2199 break;
2200 case FLY_AT_PARA:
2201 relativeFromH = "column";
2202 relativeFromV = "paragraph";
2203 break;
2204 case FLY_AT_CHAR:
2205 default:
2206 // We apply the same conversion that we do in import
2207 // (see writerfilter/source/dmapper/GraphicHelper.cxx)
2208 switch (pFrmFmt->GetVertOrient().GetRelationOrient() )
2210 case text::RelOrientation::PAGE_PRINT_AREA:
2211 relativeFromV = "margin";
2212 break;
2213 case text::RelOrientation::PAGE_FRAME:
2214 relativeFromV = "page";
2215 break;
2216 case text::RelOrientation::FRAME:
2217 relativeFromV = "paragraph";
2218 break;
2219 case text::RelOrientation::TEXT_LINE:
2220 default:
2221 relativeFromV = "line";
2223 switch (pFrmFmt->GetHoriOrient().GetRelationOrient() )
2225 case text::RelOrientation::PAGE_PRINT_AREA:
2226 relativeFromH = "margin";
2227 break;
2228 case text::RelOrientation::PAGE_FRAME:
2229 relativeFromH = "page";
2230 break;
2231 case text::RelOrientation::CHAR:
2232 relativeFromH = "character";
2233 break;
2234 case text::RelOrientation::FRAME:
2235 default:
2236 relativeFromH = "column";
2238 break;
2240 Point pos( 0, 0 );
2241 if( const SwFlyFrmFmt* flyfmt = dynamic_cast<const SwFlyFrmFmt*>(pFrmFmt)) // TODO is always true?
2242 pos = flyfmt->GetAnchoredObj()->GetCurrRelPos();
2243 OString x( OString::valueOf( TwipsToEMU( pos.X())));
2244 OString y( OString::valueOf( TwipsToEMU( pos.Y())));
2245 m_pSerializer->startElementNS( XML_wp, XML_positionH, XML_relativeFrom, relativeFromH, FSEND );
2246 m_pSerializer->startElementNS( XML_wp, XML_posOffset, FSEND );
2247 m_pSerializer->write( x.getStr() );
2248 m_pSerializer->endElementNS( XML_wp, XML_posOffset );
2249 m_pSerializer->endElementNS( XML_wp, XML_positionH );
2250 m_pSerializer->startElementNS( XML_wp, XML_positionV, XML_relativeFrom, relativeFromV, FSEND );
2251 m_pSerializer->startElementNS( XML_wp, XML_posOffset, FSEND );
2252 m_pSerializer->write( y.getStr() );
2253 m_pSerializer->endElementNS( XML_wp, XML_posOffset );
2254 m_pSerializer->endElementNS( XML_wp, XML_positionV );
2256 else
2258 m_pSerializer->startElementNS( XML_wp, XML_inline,
2259 XML_distT, "0", XML_distB, "0", XML_distL, "0", XML_distR, "0",
2260 FSEND );
2262 // now the common parts
2263 // extent of the image
2264 OString aWidth( OString::valueOf( TwipsToEMU( rSize.Width() ) ) );
2265 OString aHeight( OString::valueOf( TwipsToEMU( rSize.Height() ) ) );
2266 m_pSerializer->singleElementNS( XML_wp, XML_extent,
2267 XML_cx, aWidth.getStr(),
2268 XML_cy, aHeight.getStr(),
2269 FSEND );
2271 // effectExtent, extent including the effect (shadow only for now)
2272 SvxShadowItem aShadowItem = pFrmFmt->GetShadow();
2273 OString aLeftExt("0"), aRightExt("0"), aTopExt("0"), aBottomExt("0");
2274 if ( aShadowItem.GetLocation() != SVX_SHADOW_NONE )
2276 OString aShadowWidth( OString::valueOf( TwipsToEMU( aShadowItem.GetWidth() ) ) );
2277 switch ( aShadowItem.GetLocation() )
2279 case SVX_SHADOW_TOPLEFT:
2280 aTopExt = aLeftExt = aShadowWidth;
2281 break;
2282 case SVX_SHADOW_TOPRIGHT:
2283 aTopExt = aRightExt = aShadowWidth;
2284 break;
2285 case SVX_SHADOW_BOTTOMLEFT:
2286 aBottomExt = aLeftExt = aShadowWidth;
2287 break;
2288 case SVX_SHADOW_BOTTOMRIGHT:
2289 aBottomExt = aRightExt = aShadowWidth;
2290 break;
2291 case SVX_SHADOW_NONE:
2292 case SVX_SHADOW_END:
2293 break;
2297 m_pSerializer->singleElementNS( XML_wp, XML_effectExtent,
2298 XML_l, aLeftExt, XML_t, aTopExt, XML_r, aRightExt, XML_b, aBottomExt,
2299 FSEND );
2301 if( isAnchor )
2303 switch( pFrmFmt->GetSurround().GetValue())
2305 case SURROUND_NONE:
2306 m_pSerializer->singleElementNS( XML_wp, XML_wrapTopAndBottom, FSEND );
2307 break;
2308 case SURROUND_THROUGHT:
2309 m_pSerializer->singleElementNS( XML_wp, XML_wrapNone, FSEND );
2310 break;
2311 case SURROUND_PARALLEL:
2312 m_pSerializer->singleElementNS( XML_wp, XML_wrapSquare,
2313 XML_wrapText, "bothSides", FSEND );
2314 break;
2315 case SURROUND_IDEAL:
2316 default:
2317 m_pSerializer->singleElementNS( XML_wp, XML_wrapSquare,
2318 XML_wrapText, "largest", FSEND );
2319 break;
2322 // picture description (used for pic:cNvPr later too)
2323 ::sax_fastparser::FastAttributeList* docPrattrList = m_pSerializer->createAttrList();
2324 docPrattrList->add( XML_id, OString::valueOf( sal_Int32( m_anchorId++ )).getStr());
2325 docPrattrList->add( XML_name, "Picture" );
2326 docPrattrList->add( XML_descr, OUStringToOString( pGrfNode ? pGrfNode->GetDescription() : pOLEFrmFmt->GetObjDescription(), RTL_TEXTENCODING_UTF8 ).getStr());
2327 if( GetExport().GetFilter().getVersion( ) != oox::core::ECMA_DIALECT )
2328 docPrattrList->add( XML_title, OUStringToOString( pGrfNode ? pGrfNode->GetTitle() : pOLEFrmFmt->GetObjTitle(), RTL_TEXTENCODING_UTF8 ).getStr());
2329 XFastAttributeListRef docPrAttrListRef( docPrattrList );
2330 m_pSerializer->startElementNS( XML_wp, XML_docPr, docPrAttrListRef );
2331 // TODO hyperlink
2332 // m_pSerializer->singleElementNS( XML_a, XML_hlinkClick,
2333 // FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main",
2334 // FSNS( XML_r, XML_id ), "rId4",
2335 // FSEND );
2336 m_pSerializer->endElementNS( XML_wp, XML_docPr );
2338 m_pSerializer->startElementNS( XML_wp, XML_cNvGraphicFramePr,
2339 FSEND );
2340 // TODO change aspect?
2341 m_pSerializer->singleElementNS( XML_a, XML_graphicFrameLocks,
2342 FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main",
2343 XML_noChangeAspect, "1",
2344 FSEND );
2345 m_pSerializer->endElementNS( XML_wp, XML_cNvGraphicFramePr );
2347 m_pSerializer->startElementNS( XML_a, XML_graphic,
2348 FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main",
2349 FSEND );
2350 m_pSerializer->startElementNS( XML_a, XML_graphicData,
2351 XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/picture",
2352 FSEND );
2354 m_pSerializer->startElementNS( XML_pic, XML_pic,
2355 FSNS( XML_xmlns, XML_pic ), "http://schemas.openxmlformats.org/drawingml/2006/picture",
2356 FSEND );
2358 m_pSerializer->startElementNS( XML_pic, XML_nvPicPr,
2359 FSEND );
2360 // It seems pic:cNvpr and wp:docPr are pretty much the same thing with the same attributes
2361 m_pSerializer->startElementNS( XML_pic, XML_cNvPr, docPrAttrListRef );
2363 // TODO hyperlink
2364 // m_pSerializer->singleElementNS( XML_a, XML_hlinkClick,
2365 // FSNS( XML_r, XML_id ), "rId4",
2366 // FSEND );
2367 m_pSerializer->endElementNS( XML_pic, XML_cNvPr );
2369 m_pSerializer->startElementNS( XML_pic, XML_cNvPicPr,
2370 FSEND );
2371 // TODO change aspect?
2372 m_pSerializer->singleElementNS( XML_a, XML_picLocks,
2373 XML_noChangeAspect, "1", XML_noChangeArrowheads, "1",
2374 FSEND );
2375 m_pSerializer->endElementNS( XML_pic, XML_cNvPicPr );
2376 m_pSerializer->endElementNS( XML_pic, XML_nvPicPr );
2378 // the actual picture
2379 m_pSerializer->startElementNS( XML_pic, XML_blipFill,
2380 FSEND );
2381 m_pSerializer->singleElementNS( XML_a, XML_blip,
2382 FSNS( XML_r, nImageType ), aRelId.getStr(),
2383 FSEND );
2384 m_pSerializer->singleElementNS( XML_a, XML_srcRect,
2385 FSEND );
2386 m_pSerializer->startElementNS( XML_a, XML_stretch,
2387 FSEND );
2388 m_pSerializer->singleElementNS( XML_a, XML_fillRect,
2389 FSEND );
2390 m_pSerializer->endElementNS( XML_a, XML_stretch );
2391 m_pSerializer->endElementNS( XML_pic, XML_blipFill );
2393 // TODO setup the right values below
2394 m_pSerializer->startElementNS( XML_pic, XML_spPr,
2395 XML_bwMode, "auto",
2396 FSEND );
2397 m_pSerializer->startElementNS( XML_a, XML_xfrm,
2398 FSEND );
2399 m_pSerializer->singleElementNS( XML_a, XML_off,
2400 XML_x, "0", XML_y, "0",
2401 FSEND );
2402 m_pSerializer->singleElementNS( XML_a, XML_ext,
2403 XML_cx, aWidth.getStr(),
2404 XML_cy, aHeight.getStr(),
2405 FSEND );
2406 m_pSerializer->endElementNS( XML_a, XML_xfrm );
2407 m_pSerializer->startElementNS( XML_a, XML_prstGeom,
2408 XML_prst, "rect",
2409 FSEND );
2410 m_pSerializer->singleElementNS( XML_a, XML_avLst,
2411 FSEND );
2412 m_pSerializer->endElementNS( XML_a, XML_prstGeom );
2413 m_pSerializer->singleElementNS( XML_a, XML_noFill,
2414 FSEND );
2415 m_pSerializer->startElementNS( XML_a, XML_ln,
2416 XML_w, "9525",
2417 FSEND );
2418 m_pSerializer->singleElementNS( XML_a, XML_noFill,
2419 FSEND );
2420 m_pSerializer->singleElementNS( XML_a, XML_miter,
2421 XML_lim, "800000",
2422 FSEND );
2423 m_pSerializer->singleElementNS( XML_a, XML_headEnd,
2424 FSEND );
2425 m_pSerializer->singleElementNS( XML_a, XML_tailEnd,
2426 FSEND );
2427 m_pSerializer->endElementNS( XML_a, XML_ln );
2429 // Output effects
2430 if ( aShadowItem.GetLocation() != SVX_SHADOW_NONE )
2432 // Distance is measured diagonally from corner
2433 double nShadowDist = sqrt((aShadowItem.GetWidth()*aShadowItem.GetWidth())*2.0);
2434 OString aShadowDist( OString::valueOf( TwipsToEMU( nShadowDist ) ) );
2435 OString aShadowColor = msfilter::util::ConvertColor( aShadowItem.GetColor() );
2436 sal_uInt32 nShadowDir = 0;
2437 switch ( aShadowItem.GetLocation() )
2439 case SVX_SHADOW_TOPLEFT: nShadowDir = 13500000; break;
2440 case SVX_SHADOW_TOPRIGHT: nShadowDir = 18900000; break;
2441 case SVX_SHADOW_BOTTOMLEFT: nShadowDir = 8100000; break;
2442 case SVX_SHADOW_BOTTOMRIGHT: nShadowDir = 2700000; break;
2443 case SVX_SHADOW_NONE:
2444 case SVX_SHADOW_END:
2445 break;
2447 OString aShadowDir( OString::valueOf( long(nShadowDir) ) );
2449 m_pSerializer->startElementNS( XML_a, XML_effectLst, FSEND );
2450 m_pSerializer->startElementNS( XML_a, XML_outerShdw,
2451 XML_dist, aShadowDist.getStr(),
2452 XML_dir, aShadowDir.getStr(), FSEND );
2453 m_pSerializer->singleElementNS( XML_a, XML_srgbClr,
2454 XML_val, aShadowColor.getStr(), FSEND );
2455 m_pSerializer->endElementNS( XML_a, XML_outerShdw );
2456 m_pSerializer->endElementNS( XML_a, XML_effectLst );
2459 m_pSerializer->endElementNS( XML_pic, XML_spPr );
2461 m_pSerializer->endElementNS( XML_pic, XML_pic );
2463 m_pSerializer->endElementNS( XML_a, XML_graphicData );
2464 m_pSerializer->endElementNS( XML_a, XML_graphic );
2465 m_pSerializer->endElementNS( XML_wp, isAnchor ? XML_anchor : XML_inline );
2467 m_pSerializer->endElementNS( XML_w, XML_drawing );
2470 void DocxAttributeOutput::WriteOLE2Obj( const SdrObject* pSdrObj, SwOLENode& rOLENode, const Size& rSize, const SwFlyFrmFmt* pFlyFrmFmt )
2472 if( WriteOLEChart( pSdrObj, rSize ))
2473 return;
2474 if( WriteOLEMath( pSdrObj, rOLENode, rSize ))
2475 return;
2476 // Then we fall back to just export the object as a graphic.
2477 FlyFrameGraphic( 0, rSize, pFlyFrmFmt, &rOLENode );
2480 bool DocxAttributeOutput::WriteOLEChart( const SdrObject* pSdrObj, const Size& rSize )
2482 uno::Reference< chart2::XChartDocument > xChartDoc;
2483 uno::Reference< drawing::XShape > xShape( ((SdrObject*)pSdrObj)->getUnoShape(), uno::UNO_QUERY );
2484 if( xShape.is() )
2486 uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
2487 if( xPropSet.is() )
2488 xChartDoc.set( xPropSet->getPropertyValue( "Model" ), uno::UNO_QUERY );
2491 if( xChartDoc.is() )
2493 OSL_TRACE("DocxAttributeOutput::WriteOLE2Obj: export chart ");
2494 m_pSerializer->startElementNS( XML_w, XML_drawing,
2495 FSEND );
2496 m_pSerializer->startElementNS( XML_wp, XML_inline,
2497 XML_distT, "0", XML_distB, "0", XML_distL, "0", XML_distR, "0",
2498 FSEND );
2500 OString aWidth( OString::valueOf( TwipsToEMU( rSize.Width() ) ) );
2501 OString aHeight( OString::valueOf( TwipsToEMU( rSize.Height() ) ) );
2502 m_pSerializer->singleElementNS( XML_wp, XML_extent,
2503 XML_cx, aWidth.getStr(),
2504 XML_cy, aHeight.getStr(),
2505 FSEND );
2506 // TODO - the right effectExtent, extent including the effect
2507 m_pSerializer->singleElementNS( XML_wp, XML_effectExtent,
2508 XML_l, "0", XML_t, "0", XML_r, "0", XML_b, "0",
2509 FSEND );
2511 // should get the unique id
2512 sal_Int32 nID = 1;
2513 OUString sName("Object 1");
2514 uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY );
2515 if( xNamed.is() )
2516 sName = xNamed->getName();
2518 m_pSerializer->singleElementNS( XML_wp, XML_docPr,
2519 XML_id, I32S( nID ),
2520 XML_name, USS( sName ),
2521 FSEND );
2523 m_pSerializer->singleElementNS( XML_wp, XML_cNvGraphicFramePr,
2524 FSEND );
2526 m_pSerializer->startElementNS( XML_a, XML_graphic,
2527 FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main",
2528 FSEND );
2530 m_pSerializer->startElementNS( XML_a, XML_graphicData,
2531 XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/chart",
2532 FSEND );
2534 OString aRelId;
2535 static sal_Int32 nChartCount = 0;
2536 nChartCount++;
2537 uno::Reference< frame::XModel > xModel( xChartDoc, uno::UNO_QUERY );
2538 aRelId = m_rExport.OutputChart( xModel, nChartCount );
2540 m_pSerializer->singleElementNS( XML_c, XML_chart,
2541 FSNS( XML_xmlns, XML_c ), "http://schemas.openxmlformats.org/drawingml/2006/chart",
2542 FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
2543 FSNS( XML_r, XML_id ), aRelId.getStr(),
2544 FSEND );
2546 m_pSerializer->endElementNS( XML_a, XML_graphicData );
2547 m_pSerializer->endElementNS( XML_a, XML_graphic );
2548 m_pSerializer->endElementNS( XML_wp, XML_inline );
2549 m_pSerializer->endElementNS( XML_w, XML_drawing );
2551 return true;
2553 return false;
2556 bool DocxAttributeOutput::WriteOLEMath( const SdrObject*, const SwOLENode& rOLENode, const Size& )
2558 uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
2559 sal_Int64 nAspect = rOLENode.GetAspect();
2560 svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
2561 SvGlobalName aObjName(aObjRef->getClassID());
2563 if( !SotExchange::IsMath(aObjName) )
2564 return false;
2565 assert( m_postponedMath == NULL ); // make it a list if there can be more inside one run
2566 m_postponedMath = &rOLENode;
2567 return true;
2570 void DocxAttributeOutput::WritePostponedMath()
2572 if( m_postponedMath == NULL )
2573 return;
2574 uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode*>(m_postponedMath)->GetOLEObj().GetOleRef());
2575 uno::Reference< uno::XInterface > xInterface( xObj->getComponent(), uno::UNO_QUERY );
2576 // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
2577 // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
2578 // to RTLD_GLOBAL, so most probably a gcc bug.
2579 oox::FormulaExportBase* formulaexport = dynamic_cast<oox::FormulaExportBase*>(dynamic_cast<SfxBaseModel*>(xInterface.get()));
2580 assert( formulaexport != NULL );
2581 formulaexport->writeFormulaOoxml( m_pSerializer, GetExport().GetFilter().getVersion());
2582 m_postponedMath = NULL;
2585 void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Point& /*rNdTopLeft*/ )
2587 m_pSerializer->mark();
2589 switch ( rFrame.GetWriterType() )
2591 case sw::Frame::eGraphic:
2593 const SwNode *pNode = rFrame.GetContent();
2594 const SwGrfNode *pGrfNode = pNode ? pNode->GetGrfNode() : 0;
2595 if ( pGrfNode )
2597 if( m_postponedGraphic == NULL )
2598 FlyFrameGraphic( pGrfNode, rFrame.GetLayoutSize() );
2599 else // we are writing out attributes, but w:drawing should not be inside w:rPr,
2600 { // so write it out later
2601 m_postponedGraphic->push_back( PostponedGraphic( pGrfNode, rFrame.GetLayoutSize()));
2605 break;
2606 case sw::Frame::eDrawing:
2608 const SdrObject* pSdrObj = rFrame.GetFrmFmt().FindRealSdrObject();
2609 if ( pSdrObj )
2611 bool bSwapInPage = false;
2612 if ( !pSdrObj->GetPage() )
2614 if ( SdrModel* pModel = m_rExport.pDoc->GetDrawModel() )
2616 if ( SdrPage *pPage = pModel->GetPage( 0 ) )
2618 bSwapInPage = true;
2619 const_cast< SdrObject* >( pSdrObj )->SetPage( pPage );
2624 m_pSerializer->startElementNS( XML_w, XML_pict,
2625 FSEND );
2627 m_rExport.VMLExporter().AddSdrObject( *pSdrObj );
2629 m_pSerializer->endElementNS( XML_w, XML_pict );
2631 if ( bSwapInPage )
2632 const_cast< SdrObject* >( pSdrObj )->SetPage( 0 );
2635 break;
2636 case sw::Frame::eTxtBox:
2638 // The frame output is postponed to the end of the anchor paragraph
2639 m_aParentFrames.push_back(sw::Frame(rFrame));
2641 break;
2642 case sw::Frame::eOle:
2644 const SwFrmFmt &rFrmFmt = rFrame.GetFrmFmt();
2645 const SdrObject *pSdrObj = rFrmFmt.FindRealSdrObject();
2646 if ( pSdrObj )
2648 SwNodeIndex aIdx(*rFrmFmt.GetCntnt().GetCntntIdx(), 1);
2649 SwOLENode& rOLENd = *aIdx.GetNode().GetOLENode();
2650 WriteOLE2Obj( pSdrObj, rOLENd, rFrame.GetLayoutSize(), dynamic_cast<const SwFlyFrmFmt*>( &rFrmFmt ));
2653 break;
2654 default:
2655 OSL_TRACE( "TODO DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame& rFrame, const Point& rNdTopLeft ) - frame type '%s'\n",
2656 rFrame.GetWriterType() == sw::Frame::eTxtBox? "eTxtBox":
2657 ( rFrame.GetWriterType() == sw::Frame::eOle? "eOle":
2658 ( rFrame.GetWriterType() == sw::Frame::eFormControl? "eFormControl": "???" ) ) );
2659 break;
2662 m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE );
2665 void DocxAttributeOutput::WriteOutliner(const OutlinerParaObject& rParaObj)
2667 const EditTextObject& rEditObj = rParaObj.GetTextObject();
2668 MSWord_SdrAttrIter aAttrIter( m_rExport, rEditObj, TXT_HFTXTBOX );
2670 sal_Int32 nPara = rEditObj.GetParagraphCount();
2672 m_pSerializer->startElementNS( XML_v, XML_textbox, FSEND );
2673 m_pSerializer->startElementNS( XML_w, XML_txbxContent, FSEND );
2674 for (sal_Int32 n = 0; n < nPara; ++n)
2676 if( n )
2677 aAttrIter.NextPara( n );
2679 String aStr( rEditObj.GetText( n ));
2680 xub_StrLen nAktPos = 0;
2681 xub_StrLen nEnd = aStr.Len();
2683 m_pSerializer->startElementNS( XML_w, XML_p, FSEND );
2685 // Write paragraph properties.
2686 m_pSerializer->startElementNS(XML_w, XML_pPr, FSEND);
2687 aAttrIter.OutParaAttr(false);
2688 m_pSerializer->endElementNS(XML_w, XML_pPr);
2690 do {
2691 xub_StrLen nNextAttr = aAttrIter.WhereNext();
2692 if( nNextAttr > nEnd )
2693 nNextAttr = nEnd;
2695 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
2697 // Write run properties.
2698 m_pSerializer->startElementNS(XML_w, XML_rPr, FSEND);
2699 aAttrIter.OutAttr(nAktPos);
2700 m_pSerializer->endElementNS(XML_w, XML_rPr);
2702 bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos );
2703 if( !bTxtAtr )
2705 String aOut( aStr.Copy( nAktPos, nNextAttr - nAktPos ) );
2706 RunText(aOut);
2709 m_pSerializer->endElementNS( XML_w, XML_r );
2711 nAktPos = nNextAttr;
2712 aAttrIter.NextPos();
2714 while( nAktPos < nEnd );
2715 m_pSerializer->endElementNS( XML_w, XML_p );
2717 m_pSerializer->endElementNS( XML_w, XML_txbxContent );
2718 m_pSerializer->endElementNS( XML_v, XML_textbox );
2721 oox::drawingml::DrawingML& DocxAttributeOutput::GetDrawingML()
2723 return m_rDrawingML;
2726 void DocxAttributeOutput::StartStyle( const String& rName, bool bPapFmt,
2727 sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 /*nWwId*/, sal_uInt16 nId, bool bAutoUpdate )
2729 OString aStyle( "style" );
2731 m_pSerializer->startElementNS( XML_w, XML_style,
2732 FSNS( XML_w, XML_type ), bPapFmt? "paragraph": "character", // FIXME is this correct?
2733 FSNS( XML_w, XML_styleId ), OString( aStyle + OString::valueOf( sal_Int32( nId ) ) ).getStr(),
2734 FSEND );
2736 m_pSerializer->singleElementNS( XML_w, XML_name,
2737 FSNS( XML_w, XML_val ), OUStringToOString( OUString( rName ), RTL_TEXTENCODING_UTF8 ).getStr(),
2738 FSEND );
2740 if ( nBase != 0x0FFF )
2742 m_pSerializer->singleElementNS( XML_w, XML_basedOn,
2743 FSNS( XML_w, XML_val ), OString( aStyle + OString::valueOf( sal_Int32( nBase ) ) ).getStr(),
2744 FSEND );
2747 m_pSerializer->singleElementNS( XML_w, XML_next,
2748 FSNS( XML_w, XML_val ), OString( aStyle + OString::valueOf( sal_Int32( nNext ) ) ).getStr(),
2749 FSEND );
2751 if ( bAutoUpdate )
2752 m_pSerializer->singleElementNS( XML_w, XML_autoRedefine, FSEND );
2755 void DocxAttributeOutput::EndStyle()
2757 m_pSerializer->endElementNS( XML_w, XML_style );
2760 void DocxAttributeOutput::StartStyleProperties( bool bParProp, sal_uInt16 /*nStyle*/ )
2762 if ( bParProp )
2764 m_pSerializer->startElementNS( XML_w, XML_pPr, FSEND );
2765 InitCollectedParagraphProperties();
2767 else
2769 m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND );
2770 InitCollectedRunProperties();
2774 void DocxAttributeOutput::EndStyleProperties( bool bParProp )
2776 if ( bParProp )
2778 WriteCollectedParagraphProperties();
2779 m_pSerializer->endElementNS( XML_w, XML_pPr );
2781 else
2783 WriteCollectedRunProperties();
2784 m_pSerializer->endElementNS( XML_w, XML_rPr );
2788 void DocxAttributeOutput::OutlineNumbering( sal_uInt8 nLvl, const SwNumFmt& /*rNFmt*/, const SwFmt& /*rFmt*/ )
2790 if ( nLvl >= WW8ListManager::nMaxLevel )
2791 nLvl = WW8ListManager::nMaxLevel - 1;
2793 m_pSerializer->singleElementNS( XML_w, XML_outlineLvl,
2794 FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nLvl ) ).getStr( ),
2795 FSEND );
2798 void DocxAttributeOutput::PageBreakBefore( bool bBreak )
2800 if ( bBreak )
2801 m_pSerializer->singleElementNS( XML_w, XML_pageBreakBefore, FSEND );
2802 else
2803 m_pSerializer->singleElementNS( XML_w, XML_pageBreakBefore,
2804 FSNS( XML_w, XML_val ), "false",
2805 FSEND );
2808 void DocxAttributeOutput::SectionBreak( sal_uInt8 nC, const WW8_SepInfo* pSectionInfo )
2810 switch ( nC )
2812 case msword::ColumnBreak:
2813 // The column break should be output in the next paragraph...
2814 m_nColBreakStatus = COLBRK_POSTPONE;
2815 break;
2816 case msword::PageBreak:
2817 if ( pSectionInfo )
2819 if ( !m_bParagraphOpened )
2821 // Create a dummy paragraph if needed
2822 m_pSerializer->startElementNS( XML_w, XML_p, FSEND );
2823 m_pSerializer->startElementNS( XML_w, XML_pPr, FSEND );
2825 m_rExport.SectionProperties( *pSectionInfo );
2827 m_pSerializer->endElementNS( XML_w, XML_pPr );
2828 m_pSerializer->endElementNS( XML_w, XML_p );
2830 else
2832 // postpone the output of this; it has to be done inside the
2833 // paragraph properties, so remember it until then
2834 m_pSectionInfo.reset( new WW8_SepInfo( *pSectionInfo ));
2837 else
2839 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
2840 m_pSerializer->singleElementNS( XML_w, XML_br,
2841 FSNS( XML_w, XML_type ), "page", FSEND );
2842 m_pSerializer->endElementNS( XML_w, XML_r );
2844 break;
2845 default:
2846 OSL_TRACE( "Unknown section break to write: %d", nC );
2847 break;
2851 void DocxAttributeOutput::StartSection()
2853 m_pSerializer->startElementNS( XML_w, XML_sectPr, FSEND );
2854 m_bOpenedSectPr = true;
2856 // Write the elements in the spec order
2857 static const sal_Int32 aOrder[] =
2859 FSNS( XML_w, XML_headerReference ),
2860 FSNS( XML_w, XML_footerReference ),
2861 FSNS( XML_w, XML_footnotePr ),
2862 FSNS( XML_w, XML_endnotePr ),
2863 FSNS( XML_w, XML_type ),
2864 FSNS( XML_w, XML_pgSz ),
2865 FSNS( XML_w, XML_pgMar ),
2866 FSNS( XML_w, XML_paperSrc ),
2867 FSNS( XML_w, XML_pgBorders ),
2868 FSNS( XML_w, XML_lnNumType ),
2869 FSNS( XML_w, XML_pgNumType ),
2870 FSNS( XML_w, XML_cols ),
2871 FSNS( XML_w, XML_formProt ),
2872 FSNS( XML_w, XML_vAlign ),
2873 FSNS( XML_w, XML_noEndnote ),
2874 FSNS( XML_w, XML_titlePg ),
2875 FSNS( XML_w, XML_textDirection ),
2876 FSNS( XML_w, XML_bidi ),
2877 FSNS( XML_w, XML_rtlGutter ),
2878 FSNS( XML_w, XML_docGrid ),
2879 FSNS( XML_w, XML_printerSettings ),
2880 FSNS( XML_w, XML_sectPrChange )
2883 // postpone the output so that we can later [in EndParagraphProperties()]
2884 // prepend the properties before the run
2885 sal_Int32 len = sizeof ( aOrder ) / sizeof( sal_Int32 );
2886 uno::Sequence< sal_Int32 > aSeqOrder( len );
2887 for ( sal_Int32 i = 0; i < len; i++ )
2888 aSeqOrder[i] = aOrder[i];
2890 m_pSerializer->mark( aSeqOrder );
2893 void DocxAttributeOutput::EndSection()
2895 // Write the section properties
2896 if ( m_pSectionSpacingAttrList )
2898 XFastAttributeListRef xAttrList( m_pSectionSpacingAttrList );
2899 m_pSectionSpacingAttrList = NULL;
2901 m_pSerializer->singleElementNS( XML_w, XML_pgMar, xAttrList );
2904 // Order the elements
2905 m_pSerializer->mergeTopMarks( );
2907 m_pSerializer->endElementNS( XML_w, XML_sectPr );
2908 m_bOpenedSectPr = false;
2911 void DocxAttributeOutput::SectionFormProtection( bool bProtected )
2913 if ( bProtected )
2914 m_pSerializer->singleElementNS( XML_w, XML_formProt, FSEND );
2915 else
2916 m_pSerializer->singleElementNS( XML_w, XML_formProt,
2917 FSNS( XML_w, XML_val ), "false", FSEND );
2920 void DocxAttributeOutput::SectionLineNumbering( sal_uLong nRestartNo, const SwLineNumberInfo& rLnNumInfo )
2922 FastAttributeList* pAttr = m_pSerializer->createAttrList();
2923 pAttr->add( FSNS( XML_w, XML_countBy ), OString::number(rLnNumInfo.GetCountBy()).getStr());
2924 pAttr->add( FSNS( XML_w, XML_restart ), rLnNumInfo.IsRestartEachPage() ? "newPage" : "continuous" );
2925 if( rLnNumInfo.GetPosFromLeft())
2926 pAttr->add( FSNS( XML_w, XML_distance ), OString::number(rLnNumInfo.GetPosFromLeft()).getStr());
2927 if( nRestartNo )
2928 pAttr->add( FSNS( XML_w, XML_start ), OString::valueOf( long( nRestartNo )).getStr());
2929 XFastAttributeListRef xAttrs( pAttr );
2930 m_pSerializer->singleElementNS( XML_w, XML_lnNumType, xAttrs );
2933 void DocxAttributeOutput::SectionTitlePage()
2935 m_pSerializer->singleElementNS( XML_w, XML_titlePg, FSEND );
2938 void DocxAttributeOutput::SectionPageBorders( const SwFrmFmt* pFmt, const SwFrmFmt* /*pFirstPageFmt*/ )
2940 // Output the margins
2942 const SvxBoxItem& rBox = pFmt->GetBox( );
2944 const SvxBorderLine* pBottom = rBox.GetBottom( );
2945 const SvxBorderLine* pTop = rBox.GetTop( );
2946 const SvxBorderLine* pLeft = rBox.GetLeft( );
2947 const SvxBorderLine* pRight = rBox.GetRight( );
2949 if ( pBottom || pTop || pLeft || pRight )
2951 // All distances are relative to the text margins
2952 m_pSerializer->startElementNS( XML_w, XML_pgBorders,
2953 FSNS( XML_w, XML_display ), "allPages",
2954 FSNS( XML_w, XML_offsetFrom ), "text",
2955 FSEND );
2957 m_pSerializer->mark();
2959 m_pSerializer->endElementNS( XML_w, XML_pgBorders );
2960 m_pSerializer->mark();
2964 void DocxAttributeOutput::SectionBiDi( bool bBiDi )
2966 if ( bBiDi )
2967 m_pSerializer->singleElementNS( XML_w, XML_bidi, FSEND );
2970 static OString impl_NumberingType( sal_uInt16 nNumberingType )
2972 OString aType;
2974 switch ( nNumberingType )
2976 case SVX_NUM_CHARS_UPPER_LETTER:
2977 case SVX_NUM_CHARS_UPPER_LETTER_N: aType = "upperLetter"; break;
2978 case SVX_NUM_CHARS_LOWER_LETTER:
2979 case SVX_NUM_CHARS_LOWER_LETTER_N: aType = "lowerLetter"; break;
2980 case SVX_NUM_ROMAN_UPPER: aType = "upperRoman"; break;
2981 case SVX_NUM_ROMAN_LOWER: aType = "lowerRoman"; break;
2983 case SVX_NUM_ARABIC: aType = "decimal"; break;
2985 case SVX_NUM_BITMAP:
2986 case SVX_NUM_CHAR_SPECIAL: aType = "bullet"; break;
2988 default: aType = "none"; break;
2991 return aType;
2994 void DocxAttributeOutput::SectionPageNumbering( sal_uInt16 nNumType, sal_uInt16 nPageRestartNumber )
2996 // FIXME Not called properly with page styles like "First Page"
2998 FastAttributeList* pAttr = m_pSerializer->createAttrList();
3000 // 0 means no restart: then don't output that attribute if 0
3001 if ( nPageRestartNumber > 0 )
3002 pAttr->add( FSNS( XML_w, XML_start ), OString::valueOf( sal_Int32( nPageRestartNumber ) ) );
3004 // nNumType corresponds to w:fmt. See WW8Export::GetNumId() for more precisions
3005 OString aFmt( impl_NumberingType( nNumType ) );
3006 if ( !aFmt.isEmpty() )
3007 pAttr->add( FSNS( XML_w, XML_fmt ), aFmt.getStr() );
3009 XFastAttributeListRef xAttrs( pAttr );
3010 m_pSerializer->singleElementNS( XML_w, XML_pgNumType, xAttrs );
3012 // see 2.6.12 pgNumType (Page Numbering Settings)
3013 OSL_TRACE( "TODO DocxAttributeOutput::SectionPageNumbering()" );
3016 void DocxAttributeOutput::SectionType( sal_uInt8 nBreakCode )
3018 /* break code: 0 No break, 1 New column
3019 2 New page, 3 Even page, 4 Odd page
3021 const char* pType = NULL;
3022 switch ( nBreakCode )
3024 case 1: pType = "nextColumn"; break;
3025 case 2: pType = "nextPage"; break;
3026 case 3: pType = "evenPage"; break;
3027 case 4: pType = "oddPage"; break;
3028 default: pType = "continuous"; break;
3031 if ( pType )
3032 m_pSerializer->singleElementNS( XML_w, XML_type,
3033 FSNS( XML_w, XML_val ), pType,
3034 FSEND );
3037 void DocxAttributeOutput::StartFont( const String& rFamilyName ) const
3039 m_pSerializer->startElementNS( XML_w, XML_font,
3040 FSNS( XML_w, XML_name ), OUStringToOString( OUString( rFamilyName ), RTL_TEXTENCODING_UTF8 ).getStr(),
3041 FSEND );
3044 void DocxAttributeOutput::EndFont() const
3046 m_pSerializer->endElementNS( XML_w, XML_font );
3049 void DocxAttributeOutput::FontAlternateName( const String& rName ) const
3051 m_pSerializer->singleElementNS( XML_w, XML_altName,
3052 FSNS( XML_w, XML_val ), OUStringToOString( OUString( rName ), RTL_TEXTENCODING_UTF8 ).getStr(),
3053 FSEND );
3056 void DocxAttributeOutput::FontCharset( sal_uInt8 nCharSet, rtl_TextEncoding nEncoding ) const
3058 FastAttributeList* pAttr = m_pSerializer->createAttrList();
3060 OString aCharSet( OString::valueOf( sal_Int32( nCharSet ), 16 ) );
3061 if ( aCharSet.getLength() == 1 )
3062 aCharSet = OString( "0" ) + aCharSet;
3063 pAttr->add( FSNS( XML_w, XML_val ), aCharSet.getStr());
3065 if( GetExport().GetFilter().getVersion( ) != oox::core::ECMA_DIALECT )
3067 if( const char* charset = rtl_getMimeCharsetFromTextEncoding( nEncoding ))
3068 pAttr->add( FSNS( XML_w, XML_characterSet ), charset );
3071 m_pSerializer->singleElementNS( XML_w, XML_charset, XFastAttributeListRef( pAttr ));
3074 void DocxAttributeOutput::FontFamilyType( FontFamily eFamily ) const
3076 const char *pFamily = NULL;
3077 switch ( eFamily )
3079 case FAMILY_ROMAN: pFamily = "roman"; break;
3080 case FAMILY_SWISS: pFamily = "swiss"; break;
3081 case FAMILY_MODERN: pFamily = "modern"; break;
3082 case FAMILY_SCRIPT: pFamily = "script"; break;
3083 case FAMILY_DECORATIVE: pFamily = "decorative"; break;
3084 default: pFamily = "auto"; break; // no font family
3087 if ( pFamily )
3088 m_pSerializer->singleElementNS( XML_w, XML_family,
3089 FSNS( XML_w, XML_val ), pFamily,
3090 FSEND );
3093 void DocxAttributeOutput::FontPitchType( FontPitch ePitch ) const
3095 const char *pPitch = NULL;
3096 switch ( ePitch )
3098 case PITCH_VARIABLE: pPitch = "variable"; break;
3099 case PITCH_FIXED: pPitch = "fixed"; break;
3100 default: pPitch = "default"; break; // no info about the pitch
3103 if ( pPitch )
3104 m_pSerializer->singleElementNS( XML_w, XML_pitch,
3105 FSNS( XML_w, XML_val ), pPitch,
3106 FSEND );
3109 void DocxAttributeOutput::EmbedFont( const OUString& name, FontFamily family, FontPitch pitch, rtl_TextEncoding encoding )
3111 if( !m_rExport.pDoc->get( IDocumentSettingAccess::EMBED_FONTS ))
3112 return; // no font embedding with this document
3113 EmbedFontStyle( name, XML_embedRegular, family, ITALIC_NONE, WEIGHT_NORMAL, pitch, encoding );
3114 EmbedFontStyle( name, XML_embedBold, family, ITALIC_NONE, WEIGHT_BOLD, pitch, encoding );
3115 EmbedFontStyle( name, XML_embedItalic, family, ITALIC_NORMAL, WEIGHT_NORMAL, pitch, encoding );
3116 EmbedFontStyle( name, XML_embedBoldItalic, family, ITALIC_NORMAL, WEIGHT_BOLD, pitch, encoding );
3119 static inline char toHexChar( int value )
3121 return value >= 10 ? value + 'A' - 10 : value + '0';
3124 void DocxAttributeOutput::EmbedFontStyle( const OUString& name, int tag, FontFamily family, FontItalic italic,
3125 FontWeight weight, FontPitch pitch, rtl_TextEncoding encoding )
3127 // Embed font if at least viewing is allowed (in which case the opening app must check
3128 // the font license rights too and open either read-only or not use the font for editing).
3129 OUString fontUrl = EmbeddedFontsHelper::fontFileUrl( name, family, italic, weight, pitch, encoding,
3130 EmbeddedFontsHelper::ViewingAllowed );
3131 if( fontUrl.isEmpty())
3132 return;
3133 // TODO IDocumentSettingAccess::EMBED_SYSTEM_FONTS
3134 if( !fontFilesMap.count( fontUrl ))
3136 osl::File file( fontUrl );
3137 if( file.open( osl_File_OpenFlag_Read ) != osl::File::E_None )
3138 return;
3139 uno::Reference< com::sun::star::io::XOutputStream > xOutStream = m_rExport.GetFilter().openFragmentStream(
3140 OUString( "word/fonts/font" ) + OUString::number(m_nextFontId) + ".odttf",
3141 "application/vnd.openxmlformats-officedocument.obfuscatedFont" );
3142 // Not much point in trying hard with the obfuscation key, whoever reads the spec can read the font anyway,
3143 // so just alter the first and last part of the key.
3144 char fontKeyStr[] = "{00014A78-CABC-4EF0-12AC-5CD89AEFDE00}";
3145 sal_uInt8 fontKey[ 16 ] = { 0, 0xDE, 0xEF, 0x9A, 0xD8, 0x5C, 0xAC, 0x12, 0xF0, 0x4E,
3146 0xBC, 0xCA, 0x78, 0x4A, 0x01, 0 };
3147 fontKey[ 0 ] = fontKey[ 15 ] = m_nextFontId % 256;
3148 fontKeyStr[ 1 ] = fontKeyStr[ 35 ] = toHexChar(( m_nextFontId % 256 ) / 16 );
3149 fontKeyStr[ 2 ] = fontKeyStr[ 36 ] = toHexChar(( m_nextFontId % 256 ) % 16 );
3150 char buffer[ 4096 ];
3151 sal_uInt64 readSize;
3152 file.read( buffer, 32, readSize );
3153 if( readSize < 32 )
3155 SAL_WARN( "sw.ww8", "Font file size too small (" << fontUrl << ")" );
3156 xOutStream->closeOutput();
3157 return;
3159 for( int i = 0;
3160 i < 16;
3161 ++i )
3163 buffer[ i ] ^= fontKey[ i ];
3164 buffer[ i + 16 ] ^= fontKey[ i ];
3166 xOutStream->writeBytes( uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( buffer ), 32 ));
3167 for(;;)
3169 sal_Bool eof;
3170 if( file.isEndOfFile( &eof ) != osl::File::E_None )
3172 SAL_WARN( "sw.ww8", "Error reading font file " << fontUrl );
3173 xOutStream->closeOutput();
3174 return;
3176 if( eof )
3177 break;
3178 if( file.read( buffer, 4096, readSize ) != osl::File::E_None )
3180 SAL_WARN( "sw.ww8", "Error reading font file " << fontUrl );
3181 xOutStream->closeOutput();
3182 return;
3184 if( readSize == 0 )
3185 break;
3186 xOutStream->writeBytes( uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( buffer ), readSize ));
3188 xOutStream->closeOutput();
3189 OString relId = OUStringToOString( GetExport().GetFilter().addRelation( m_pSerializer->getOutputStream(),
3190 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/font",
3191 OUString( "fonts/font" ) + OUString::number( m_nextFontId ) + ".odttf" ), RTL_TEXTENCODING_UTF8 );
3192 EmbeddedFontRef ref;
3193 ref.relId = relId;
3194 ref.fontKey = fontKeyStr;
3195 fontFilesMap[ fontUrl ] = ref;
3196 ++m_nextFontId;
3198 m_pSerializer->singleElementNS( XML_w, tag,
3199 FSNS( XML_r, XML_id ), fontFilesMap[ fontUrl ].relId,
3200 FSNS( XML_w, XML_fontKey ), fontFilesMap[ fontUrl ].fontKey,
3201 FSEND );
3204 void DocxAttributeOutput::NumberingDefinition( sal_uInt16 nId, const SwNumRule &rRule )
3206 // nId is the same both for abstract numbering definition as well as the
3207 // numbering definition itself
3208 // TODO check that this is actually true & fix if not ;-)
3209 OString aId( OString::valueOf( sal_Int32( nId ) ) );
3211 m_pSerializer->startElementNS( XML_w, XML_num,
3212 FSNS( XML_w, XML_numId ), aId.getStr(),
3213 FSEND );
3215 m_pSerializer->singleElementNS( XML_w, XML_abstractNumId,
3216 FSNS( XML_w, XML_val ), aId.getStr(),
3217 FSEND );
3219 #if OSL_DEBUG_LEVEL > 1
3220 // TODO ww8 version writes this, anything to do about it here?
3221 if ( rRule.IsContinusNum() )
3222 OSL_TRACE( "TODO DocxAttributeOutput::NumberingDefinition()" );
3223 #else
3224 (void) rRule; // to quiet the warning...
3225 #endif
3227 m_pSerializer->endElementNS( XML_w, XML_num );
3230 void DocxAttributeOutput::StartAbstractNumbering( sal_uInt16 nId )
3232 m_pSerializer->startElementNS( XML_w, XML_abstractNum,
3233 FSNS( XML_w, XML_abstractNumId ), OString::valueOf( sal_Int32( nId ) ).getStr(),
3234 FSEND );
3237 void DocxAttributeOutput::EndAbstractNumbering()
3239 m_pSerializer->endElementNS( XML_w, XML_abstractNum );
3242 void DocxAttributeOutput::NumberingLevel( sal_uInt8 nLevel,
3243 sal_uInt16 nStart,
3244 sal_uInt16 nNumberingType,
3245 SvxAdjust eAdjust,
3246 const sal_uInt8 * /*pNumLvlPos*/,
3247 sal_uInt8 nFollow,
3248 const wwFont *pFont,
3249 const SfxItemSet *pOutSet,
3250 sal_Int16 nIndentAt,
3251 sal_Int16 nFirstLineIndex,
3252 sal_Int16 nListTabPos,
3253 const String &rNumberingString,
3254 const SvxBrushItem* pBrush)
3256 m_pSerializer->startElementNS( XML_w, XML_lvl,
3257 FSNS( XML_w, XML_ilvl ), OString::valueOf( sal_Int32( nLevel ) ).getStr(),
3258 FSEND );
3260 // start with the nStart value
3261 m_pSerializer->singleElementNS( XML_w, XML_start,
3262 FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nStart ) ).getStr(),
3263 FSEND );
3265 // format
3266 OString aFmt( impl_NumberingType( nNumberingType ) );
3268 if ( !aFmt.isEmpty() )
3269 m_pSerializer->singleElementNS( XML_w, XML_numFmt,
3270 FSNS( XML_w, XML_val ), aFmt.getStr(),
3271 FSEND );
3273 // suffix
3274 const char *pSuffix = NULL;
3275 switch ( nFollow )
3277 case 1: pSuffix = "space"; break;
3278 case 2: pSuffix = "nothing"; break;
3279 default: /*pSuffix = "tab";*/ break;
3281 if ( pSuffix )
3282 m_pSerializer->singleElementNS( XML_w, XML_suff,
3283 FSNS( XML_w, XML_val ), pSuffix,
3284 FSEND );
3286 // text
3287 OUString aText( rNumberingString );
3288 OUStringBuffer aBuffer( aText.getLength() + WW8ListManager::nMaxLevel );
3290 const sal_Unicode *pPrev = aText.getStr();
3291 const sal_Unicode *pIt = aText.getStr();
3292 while ( pIt < aText.getStr() + aText.getLength() )
3294 // convert the level values to %NUMBER form
3295 // (we don't use pNumLvlPos at all)
3296 // FIXME so far we support the ww8 limit of levels only
3297 if ( *pIt < sal_Unicode( WW8ListManager::nMaxLevel ) )
3299 aBuffer.append( pPrev, pIt - pPrev );
3300 aBuffer.append( '%' );
3301 aBuffer.append( OUString::valueOf( sal_Int32( *pIt ) + 1 ) );
3303 pPrev = pIt + 1;
3305 ++pIt;
3307 if ( pPrev < pIt )
3308 aBuffer.append( pPrev, pIt - pPrev );
3310 m_pSerializer->singleElementNS( XML_w, XML_lvlText,
3311 FSNS( XML_w, XML_val ), OUStringToOString( aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ).getStr(),
3312 FSEND );
3314 // bullet
3315 if (nNumberingType == SVX_NUM_BITMAP && pBrush)
3317 int nIndex = m_rExport.GetGrfIndex(*pBrush);
3318 if (nIndex != -1)
3320 m_pSerializer->singleElementNS(XML_w, XML_lvlPicBulletId,
3321 FSNS(XML_w, XML_val), OString::number(nIndex).getStr(),
3322 FSEND);
3326 // justification
3327 const char *pJc;
3328 bool ecmaDialect = ( m_rExport.GetFilter().getVersion() == oox::core::ECMA_DIALECT );
3329 switch ( eAdjust )
3331 case SVX_ADJUST_CENTER: pJc = "center"; break;
3332 case SVX_ADJUST_RIGHT: pJc = !ecmaDialect ? "end" : "right"; break;
3333 default: pJc = !ecmaDialect ? "start" : "left"; break;
3335 m_pSerializer->singleElementNS( XML_w, XML_lvlJc,
3336 FSNS( XML_w, XML_val ), pJc,
3337 FSEND );
3339 // indentation
3340 m_pSerializer->startElementNS( XML_w, XML_pPr, FSEND );
3341 if( nListTabPos != 0 )
3343 m_pSerializer->startElementNS( XML_w, XML_tabs, FSEND );
3344 m_pSerializer->singleElementNS( XML_w, XML_tab,
3345 FSNS( XML_w, XML_val ), "num",
3346 FSNS( XML_w, XML_pos ), OString::number( nListTabPos ).getStr(),
3347 FSEND );
3348 m_pSerializer->endElementNS( XML_w, XML_tabs );
3351 sal_Int32 nToken = ecmaDialect ? XML_left : XML_start;
3352 m_pSerializer->singleElementNS( XML_w, XML_ind,
3353 FSNS( XML_w, nToken ), OString::valueOf( sal_Int32( nIndentAt ) ).getStr(),
3354 FSNS( XML_w, XML_hanging ), OString::valueOf( sal_Int32( -nFirstLineIndex ) ).getStr(),
3355 FSEND );
3356 m_pSerializer->endElementNS( XML_w, XML_pPr );
3358 // font
3359 if ( pOutSet )
3361 m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND );
3363 if ( pFont )
3365 GetExport().GetId( *pFont ); // ensure font info is written to fontTable.xml
3366 OString aFamilyName( OUStringToOString( OUString( pFont->GetFamilyName() ), RTL_TEXTENCODING_UTF8 ) );
3367 m_pSerializer->singleElementNS( XML_w, XML_rFonts,
3368 FSNS( XML_w, XML_ascii ), aFamilyName.getStr(),
3369 FSNS( XML_w, XML_hAnsi ), aFamilyName.getStr(),
3370 FSNS( XML_w, XML_cs ), aFamilyName.getStr(),
3371 FSNS( XML_w, XML_hint ), "default",
3372 FSEND );
3374 m_rExport.OutputItemSet( *pOutSet, false, true, i18n::ScriptType::LATIN, m_rExport.mbExportModeRTF );
3376 m_pSerializer->endElementNS( XML_w, XML_rPr );
3379 // TODO anything to do about nListTabPos?
3381 m_pSerializer->endElementNS( XML_w, XML_lvl );
3384 void DocxAttributeOutput::CharCaseMap( const SvxCaseMapItem& rCaseMap )
3386 switch ( rCaseMap.GetValue() )
3388 case SVX_CASEMAP_KAPITAELCHEN:
3389 m_pSerializer->singleElementNS( XML_w, XML_smallCaps, FSEND );
3390 break;
3391 case SVX_CASEMAP_VERSALIEN:
3392 m_pSerializer->singleElementNS( XML_w, XML_caps, FSEND );
3393 break;
3394 default: // Something that ooxml does not support
3395 m_pSerializer->singleElementNS( XML_w, XML_smallCaps, FSNS( XML_w, XML_val ), "false", FSEND );
3396 m_pSerializer->singleElementNS( XML_w, XML_caps, FSNS( XML_w, XML_val ), "false", FSEND );
3397 break;
3401 void DocxAttributeOutput::CharColor( const SvxColorItem& rColor )
3403 const Color aColor( rColor.GetValue() );
3404 OString aColorString;
3406 aColorString = msfilter::util::ConvertColor( aColor );
3408 m_pSerializer->singleElementNS( XML_w, XML_color,
3409 FSNS( XML_w, XML_val ), aColorString.getStr(), FSEND );
3412 void DocxAttributeOutput::CharContour( const SvxContourItem& rContour )
3414 if ( rContour.GetValue() )
3415 m_pSerializer->singleElementNS( XML_w, XML_outline, FSEND );
3416 else
3417 m_pSerializer->singleElementNS( XML_w, XML_outline, FSNS( XML_w, XML_val ), "false", FSEND );
3420 void DocxAttributeOutput::CharCrossedOut( const SvxCrossedOutItem& rCrossedOut )
3422 switch ( rCrossedOut.GetStrikeout() )
3424 case STRIKEOUT_DOUBLE:
3425 m_pSerializer->singleElementNS( XML_w, XML_dstrike, FSEND );
3426 break;
3427 case STRIKEOUT_NONE:
3428 m_pSerializer->singleElementNS( XML_w, XML_dstrike, FSNS( XML_w, XML_val ), "false", FSEND );
3429 m_pSerializer->singleElementNS( XML_w, XML_strike, FSNS( XML_w, XML_val ), "false", FSEND );
3430 break;
3431 default:
3432 m_pSerializer->singleElementNS( XML_w, XML_strike, FSEND );
3433 break;
3437 void DocxAttributeOutput::CharEscapement( const SvxEscapementItem& rEscapement )
3439 OString sIss;
3440 short nEsc = rEscapement.GetEsc(), nProp = rEscapement.GetProp();
3441 if ( !nEsc )
3443 sIss = OString( "baseline" );
3444 nEsc = 0;
3445 nProp = 100;
3447 else if ( DFLT_ESC_PROP == nProp )
3449 if ( DFLT_ESC_SUB == nEsc || DFLT_ESC_AUTO_SUB == nEsc )
3450 sIss = OString( "subscript" );
3451 else if ( DFLT_ESC_SUPER == nEsc || DFLT_ESC_AUTO_SUPER == nEsc )
3452 sIss = OString( "superscript" );
3455 if ( !sIss.isEmpty() )
3456 m_pSerializer->singleElementNS( XML_w, XML_vertAlign,
3457 FSNS( XML_w, XML_val ), sIss.getStr(), FSEND );
3459 if ( sIss.isEmpty() || sIss.match( OString( "baseline" ) ) )
3461 long nHeight = ((SvxFontHeightItem&)m_rExport.GetItem(
3462 RES_CHRATR_FONTSIZE )).GetHeight();
3463 OString sPos = OString::valueOf( ( nHeight * nEsc + 500 ) / 1000 );
3464 m_pSerializer->singleElementNS( XML_w, XML_position,
3465 FSNS( XML_w, XML_val ), sPos.getStr( ), FSEND );
3467 if( 100 != nProp || sIss.match( OString( "baseline" ) ) )
3469 OString sSize = OString::valueOf( ( nHeight * nProp + 500 ) / 1000 );
3470 m_pSerializer->singleElementNS( XML_w, XML_sz,
3471 FSNS( XML_w, XML_val ), sSize.getStr( ), FSEND );
3476 void DocxAttributeOutput::CharFont( const SvxFontItem& rFont)
3478 if (!m_pFontsAttrList)
3479 m_pFontsAttrList = m_pSerializer->createAttrList();
3480 GetExport().GetId( rFont ); // ensure font info is written to fontTable.xml
3481 OUString sFontName(rFont.GetFamilyName());
3482 OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8);
3483 m_pFontsAttrList->add(FSNS(XML_w, XML_ascii), sFontNameUtf8);
3484 m_pFontsAttrList->add(FSNS(XML_w, XML_hAnsi), sFontNameUtf8);
3487 void DocxAttributeOutput::CharFontSize( const SvxFontHeightItem& rFontSize)
3489 OString fontSize = OString::valueOf( sal_Int32( ( rFontSize.GetHeight() + 5 ) / 10 ) );
3491 switch ( rFontSize.Which() )
3493 case RES_CHRATR_FONTSIZE:
3494 case RES_CHRATR_CJK_FONTSIZE:
3495 m_pSerializer->singleElementNS( XML_w, XML_sz, FSNS( XML_w, XML_val ), fontSize.getStr(), FSEND );
3496 break;
3497 case RES_CHRATR_CTL_FONTSIZE:
3498 m_pSerializer->singleElementNS( XML_w, XML_szCs, FSNS( XML_w, XML_val ), fontSize.getStr(), FSEND );
3499 break;
3503 void DocxAttributeOutput::CharKerning( const SvxKerningItem& rKerning )
3505 OString aKerning = OString::valueOf( ( sal_Int32 ) rKerning.GetValue() );
3506 m_pSerializer->singleElementNS( XML_w, XML_spacing, FSNS(XML_w, XML_val), aKerning.getStr(), FSEND );
3509 void DocxAttributeOutput::CharLanguage( const SvxLanguageItem& rLanguage )
3511 if (!m_pCharLangAttrList)
3512 m_pCharLangAttrList = m_pSerializer->createAttrList();
3514 ::com::sun::star::lang::Locale xLocale= LanguageTag( rLanguage.GetLanguage( ) ).getLocale();
3515 OString sLanguage = OUStringToOString(xLocale.Language, RTL_TEXTENCODING_UTF8);
3516 OString sCountry = OUStringToOString(xLocale.Country, RTL_TEXTENCODING_UTF8);
3518 OString aLanguageCode = sLanguage + "-" + sCountry;
3520 switch ( rLanguage.Which() )
3522 case RES_CHRATR_LANGUAGE:
3523 m_pCharLangAttrList->add(FSNS(XML_w, XML_val), aLanguageCode);
3524 break;
3525 case RES_CHRATR_CJK_LANGUAGE:
3526 m_pCharLangAttrList->add(FSNS(XML_w, XML_eastAsia), aLanguageCode);
3527 break;
3528 case RES_CHRATR_CTL_LANGUAGE:
3529 m_pCharLangAttrList->add(FSNS(XML_w, XML_bidi), aLanguageCode);
3530 break;
3534 void DocxAttributeOutput::CharPosture( const SvxPostureItem& rPosture )
3536 if ( rPosture.GetPosture() != ITALIC_NONE )
3537 m_pSerializer->singleElementNS( XML_w, XML_i, FSEND );
3538 else
3539 m_pSerializer->singleElementNS( XML_w, XML_i, FSNS( XML_w, XML_val ), "false", FSEND );
3542 void DocxAttributeOutput::CharShadow( const SvxShadowedItem& rShadow )
3544 if ( rShadow.GetValue() )
3545 m_pSerializer->singleElementNS( XML_w, XML_shadow, FSEND );
3546 else
3547 m_pSerializer->singleElementNS( XML_w, XML_shadow, FSNS( XML_w, XML_val ), "false", FSEND );
3550 void DocxAttributeOutput::CharUnderline( const SvxUnderlineItem& rUnderline )
3552 const char *pUnderline;
3554 switch ( rUnderline.GetLineStyle() )
3556 case UNDERLINE_SINGLE: pUnderline = "single"; break;
3557 case UNDERLINE_BOLD: pUnderline = "thick"; break;
3558 case UNDERLINE_DOUBLE: pUnderline = "double"; break;
3559 case UNDERLINE_DOTTED: pUnderline = "dotted"; break;
3560 case UNDERLINE_DASH: pUnderline = "dash"; break;
3561 case UNDERLINE_DASHDOT: pUnderline = "dotDash"; break;
3562 case UNDERLINE_DASHDOTDOT: pUnderline = "dotDotDash"; break;
3563 case UNDERLINE_WAVE: pUnderline = "wave"; break;
3564 case UNDERLINE_BOLDDOTTED: pUnderline = "dottedHeavy"; break;
3565 case UNDERLINE_BOLDDASH: pUnderline = "dashedHeavy"; break;
3566 case UNDERLINE_LONGDASH: pUnderline = "dashLongHeavy"; break;
3567 case UNDERLINE_BOLDLONGDASH: pUnderline = "dashLongHeavy"; break;
3568 case UNDERLINE_BOLDDASHDOT: pUnderline = "dashDotHeavy"; break;
3569 case UNDERLINE_BOLDDASHDOTDOT: pUnderline = "dashDotDotHeavy"; break;
3570 case UNDERLINE_BOLDWAVE: pUnderline = "wavyHeavy"; break;
3571 case UNDERLINE_DOUBLEWAVE: pUnderline = "wavyDouble"; break;
3572 case UNDERLINE_NONE: // fall through
3573 default: pUnderline = "none"; break;
3576 m_pSerializer->singleElementNS( XML_w, XML_u, FSNS( XML_w, XML_val ), pUnderline, FSEND );
3579 void DocxAttributeOutput::CharWeight( const SvxWeightItem& rWeight )
3581 if ( rWeight.GetWeight() == WEIGHT_BOLD )
3582 m_pSerializer->singleElementNS( XML_w, XML_b, FSEND );
3583 else
3584 m_pSerializer->singleElementNS( XML_w, XML_b, FSNS( XML_w, XML_val ), "false", FSEND );
3587 void DocxAttributeOutput::CharAutoKern( const SvxAutoKernItem& )
3589 OSL_TRACE( "TODO DocxAttributeOutput::CharAutoKern()" );
3592 void DocxAttributeOutput::CharAnimatedText( const SvxBlinkItem& rBlink )
3594 if ( rBlink.GetValue() )
3595 m_pSerializer->singleElementNS(XML_w, XML_effect, FSNS( XML_w, XML_val ), "blinkBackground", FSEND );
3596 else
3597 m_pSerializer->singleElementNS(XML_w, XML_effect, FSNS( XML_w, XML_val ), "none", FSEND );
3600 void DocxAttributeOutput::CharBackground( const SvxBrushItem& rBrush )
3602 m_pSerializer->singleElementNS( XML_w, XML_shd,
3603 FSNS( XML_w, XML_fill ), msfilter::util::ConvertColor( rBrush.GetColor() ).getStr(),
3604 FSNS( XML_w, XML_val ), "clear",
3605 FSEND );
3608 void DocxAttributeOutput::CharFontCJK( const SvxFontItem& rFont )
3610 if (!m_pFontsAttrList)
3611 m_pFontsAttrList = m_pSerializer->createAttrList();
3612 OUString sFontName(rFont.GetFamilyName());
3613 OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8);
3614 m_pFontsAttrList->add(FSNS(XML_w, XML_eastAsia), sFontNameUtf8);
3617 void DocxAttributeOutput::CharPostureCJK( const SvxPostureItem& rPosture )
3619 if ( rPosture.GetPosture() != ITALIC_NONE )
3620 m_pSerializer->singleElementNS( XML_w, XML_i, FSEND );
3621 else
3622 m_pSerializer->singleElementNS( XML_w, XML_i, FSNS( XML_w, XML_val ), "false", FSEND );
3625 void DocxAttributeOutput::CharWeightCJK( const SvxWeightItem& rWeight )
3627 if ( rWeight.GetWeight() == WEIGHT_BOLD )
3628 m_pSerializer->singleElementNS( XML_w, XML_b, FSEND );
3629 else
3630 m_pSerializer->singleElementNS( XML_w, XML_b, FSNS( XML_w, XML_val ), "false", FSEND );
3633 void DocxAttributeOutput::CharFontCTL( const SvxFontItem& rFont )
3635 if (!m_pFontsAttrList)
3636 m_pFontsAttrList = m_pSerializer->createAttrList();
3637 OUString sFontName(rFont.GetFamilyName());
3638 OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8);
3639 m_pFontsAttrList->add(FSNS(XML_w, XML_cs), sFontNameUtf8);
3643 void DocxAttributeOutput::CharPostureCTL( const SvxPostureItem& rPosture)
3645 if ( rPosture.GetPosture() != ITALIC_NONE )
3646 m_pSerializer->singleElementNS( XML_w, XML_iCs, FSEND );
3647 else
3648 m_pSerializer->singleElementNS( XML_w, XML_iCs, FSNS( XML_w, XML_val ), "false", FSEND );
3651 void DocxAttributeOutput::CharWeightCTL( const SvxWeightItem& rWeight )
3653 if ( rWeight.GetWeight() == WEIGHT_BOLD )
3654 m_pSerializer->singleElementNS( XML_w, XML_bCs, FSEND );
3655 else
3656 m_pSerializer->singleElementNS( XML_w, XML_bCs, FSNS( XML_w, XML_val ), "false", FSEND );
3659 void DocxAttributeOutput::CharRotate( const SvxCharRotateItem& rRotate)
3661 // Not rorated or we the rotation already handled?
3662 if ( !rRotate.GetValue() || m_bBtLr)
3663 return;
3665 if (!m_pEastAsianLayoutAttrList)
3666 m_pEastAsianLayoutAttrList = m_pSerializer->createAttrList();
3667 OString sTrue((sal_Char *)"true");
3668 m_pEastAsianLayoutAttrList->add(FSNS(XML_w, XML_vert), sTrue);
3670 if (rRotate.IsFitToLine())
3671 m_pEastAsianLayoutAttrList->add(FSNS(XML_w, XML_vertCompress), sTrue);
3674 void DocxAttributeOutput::CharEmphasisMark( const SvxEmphasisMarkItem& rEmphasisMark )
3676 const char *pEmphasis;
3678 switch ( rEmphasisMark.GetValue() )
3680 case EMPHASISMARK_NONE: pEmphasis = "none"; break;
3681 case EMPHASISMARK_SIDE_DOTS: pEmphasis = "dot"; break;
3682 case EMPHASISMARK_CIRCLE_ABOVE: pEmphasis = "circle"; break;
3683 case EMPHASISMARK_DOTS_BELOW: pEmphasis = "underDot"; break;
3684 default: pEmphasis = "comma"; break;
3687 m_pSerializer->singleElementNS( XML_w, XML_em, FSNS( XML_w, XML_val ), pEmphasis, FSEND );
3690 void DocxAttributeOutput::CharTwoLines( const SvxTwoLinesItem& rTwoLines )
3692 if ( !rTwoLines.GetValue() )
3693 return;
3695 if (!m_pEastAsianLayoutAttrList)
3696 m_pEastAsianLayoutAttrList = m_pSerializer->createAttrList();
3697 OString sTrue((sal_Char *)"true");
3698 m_pEastAsianLayoutAttrList->add(FSNS(XML_w, XML_combine), sTrue);
3700 sal_Unicode cStart = rTwoLines.GetStartBracket();
3701 sal_Unicode cEnd = rTwoLines.GetEndBracket();
3703 if (!cStart && !cEnd)
3704 return;
3706 OString sBracket;
3707 if ((cStart == '{') || (cEnd == '}'))
3708 sBracket = (sal_Char *)"curly";
3709 else if ((cStart == '<') || (cEnd == '>'))
3710 sBracket = (sal_Char *)"angle";
3711 else if ((cStart == '[') || (cEnd == ']'))
3712 sBracket = (sal_Char *)"square";
3713 else
3714 sBracket = (sal_Char *)"round";
3715 m_pEastAsianLayoutAttrList->add(FSNS(XML_w, XML_combineBrackets), sBracket);
3718 void DocxAttributeOutput::CharScaleWidth( const SvxCharScaleWidthItem& rScaleWidth )
3720 m_pSerializer->singleElementNS( XML_w, XML_w,
3721 FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( rScaleWidth.GetValue() ) ).getStr(), FSEND );
3724 void DocxAttributeOutput::CharRelief( const SvxCharReliefItem& rRelief )
3726 switch ( rRelief.GetValue() )
3728 case RELIEF_EMBOSSED:
3729 m_pSerializer->singleElementNS( XML_w, XML_emboss, FSEND );
3730 break;
3731 case RELIEF_ENGRAVED:
3732 m_pSerializer->singleElementNS( XML_w, XML_imprint, FSEND );
3733 break;
3734 default:
3735 m_pSerializer->singleElementNS( XML_w, XML_emboss, FSNS( XML_w, XML_val ), "false", FSEND );
3736 m_pSerializer->singleElementNS( XML_w, XML_imprint, FSNS( XML_w, XML_val ), "false", FSEND );
3737 break;
3741 void DocxAttributeOutput::CharHidden( const SvxCharHiddenItem& rHidden )
3743 if ( rHidden.GetValue() )
3744 m_pSerializer->singleElementNS( XML_w, XML_vanish, FSEND );
3745 else
3746 m_pSerializer->singleElementNS( XML_w, XML_vanish, FSNS( XML_w, XML_val ), "false", FSEND );
3749 void DocxAttributeOutput::TextINetFormat( const SwFmtINetFmt& rLink )
3751 const SwTxtINetFmt* pINetFmt = rLink.GetTxtINetFmt();
3752 const SwCharFmt* pCharFmt = pINetFmt->GetCharFmt();
3754 OString aStyleId( "style" );
3755 aStyleId += OString::valueOf( sal_Int32( m_rExport.GetId( *pCharFmt ) ) );
3757 m_pSerializer->singleElementNS( XML_w, XML_rStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND );
3760 void DocxAttributeOutput::TextCharFormat( const SwFmtCharFmt& rCharFmt )
3762 OString aStyleId( "style" );
3763 aStyleId += OString::valueOf( sal_Int32( m_rExport.GetId( *rCharFmt.GetCharFmt() ) ) );
3765 m_pSerializer->singleElementNS( XML_w, XML_rStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND );
3768 void DocxAttributeOutput::RefField( const SwField& rFld, const String& rRef )
3770 sal_uInt16 nType = rFld.GetTyp( )->Which( );
3771 if ( nType == RES_GETEXPFLD )
3773 String sCmd = FieldString( ww::eREF );
3774 sCmd.AppendAscii( "\"" );
3775 sCmd += rRef;
3776 sCmd.AppendAscii( "\" " );
3778 m_rExport.OutputField( &rFld, ww::eREF, sCmd );
3781 // There is nothing to do here for the set fields
3784 void DocxAttributeOutput::HiddenField( const SwField& /*rFld*/ )
3786 OSL_TRACE( "TODO DocxAttributeOutput::HiddenField()" );
3789 void DocxAttributeOutput::PostitField( const SwField* pFld )
3791 assert( dynamic_cast< const SwPostItField* >( pFld ));
3792 m_postitFields.push_back( static_cast< const SwPostItField* >( pFld ));
3795 void DocxAttributeOutput::WritePostitFieldReference()
3797 while( m_postitFieldsMaxId < m_postitFields.size())
3799 OString idstr = OString::valueOf( sal_Int32( m_postitFieldsMaxId ));
3800 m_pSerializer->singleElementNS( XML_w, XML_commentReference, FSNS( XML_w, XML_id ), idstr.getStr(), FSEND );
3801 ++m_postitFieldsMaxId;
3805 void DocxAttributeOutput::WritePostitFieldStart()
3807 m_bPostitStart = true;
3810 void DocxAttributeOutput::WritePostitFieldEnd()
3812 m_bPostitEnd = true;
3815 void DocxAttributeOutput::WritePostitFields()
3817 for( unsigned int i = 0;
3818 i < m_postitFields.size();
3819 ++i )
3821 OString idstr = OString::valueOf( sal_Int32( i ));
3822 const SwPostItField* f = m_postitFields[ i ];
3823 m_pSerializer->startElementNS( XML_w, XML_comment, FSNS( XML_w, XML_id ), idstr.getStr(),
3824 FSNS( XML_w, XML_author ), OUStringToOString( f->GetPar1(), RTL_TEXTENCODING_UTF8 ).getStr(),
3825 FSNS( XML_w, XML_date ), msfilter::util::DateTimeToOString(f->GetDateTime()).getStr(),
3826 FSNS( XML_w, XML_initials ), OUStringToOString( f->GetInitials(), RTL_TEXTENCODING_UTF8 ).getStr(), FSEND );
3827 // Check for the text object existing, it seems that it can be NULL when saving a newly created
3828 // comment without giving focus back to the main document. As GetTxt() is empty in that case as well,
3829 // that is probably a bug in the Writer core.
3830 if( f->GetTextObject() != NULL )
3831 GetExport().WriteOutliner( *f->GetTextObject(), TXT_ATN );
3832 m_pSerializer->endElementNS( XML_w, XML_comment );
3836 bool DocxAttributeOutput::DropdownField( const SwField* pFld )
3838 bool bExpand = false;
3840 ww::eField eType = ww::eFORMDROPDOWN;
3841 String sCmd = FieldString( eType );
3842 GetExport( ).OutputField( pFld, eType, sCmd );
3844 return bExpand;
3847 bool DocxAttributeOutput::PlaceholderField( const SwField* pFld )
3849 assert( pendingPlaceholder == NULL );
3850 pendingPlaceholder = pFld;
3851 return false; // do not expand
3854 void DocxAttributeOutput::WritePendingPlaceholder()
3856 if( pendingPlaceholder == NULL )
3857 return;
3858 const SwField* pFld = pendingPlaceholder;
3859 pendingPlaceholder = NULL;
3860 m_pSerializer->startElementNS( XML_w, XML_sdt, FSEND );
3861 m_pSerializer->startElementNS( XML_w, XML_sdtPr, FSEND );
3862 if( !pFld->GetPar2().isEmpty())
3863 m_pSerializer->singleElementNS( XML_w, XML_alias,
3864 FSNS( XML_w, XML_val ), OUStringToOString( pFld->GetPar2(), RTL_TEXTENCODING_UTF8 ), FSEND );
3865 m_pSerializer->singleElementNS( XML_w, XML_temporary, FSEND );
3866 m_pSerializer->singleElementNS( XML_w, XML_showingPlcHdr, FSEND );
3867 m_pSerializer->singleElementNS( XML_w, XML_text, FSEND );
3868 m_pSerializer->endElementNS( XML_w, XML_sdtPr );
3869 m_pSerializer->startElementNS( XML_w, XML_sdtContent, FSEND );
3870 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
3871 RunText( pFld->GetPar1());
3872 m_pSerializer->endElementNS( XML_w, XML_r );
3873 m_pSerializer->endElementNS( XML_w, XML_sdtContent );
3874 m_pSerializer->endElementNS( XML_w, XML_sdt );
3877 void DocxAttributeOutput::SetField( const SwField& rFld, ww::eField eType, const String& rCmd )
3879 // field bookmarks are handled in the EndRun method
3880 GetExport().OutputField(&rFld, eType, rCmd );
3883 void DocxAttributeOutput::WriteExpand( const SwField* pFld )
3885 // Will be written in the next End Run
3886 String sCmd;
3887 m_rExport.OutputField( pFld, ww::eUNKNOWN, sCmd );
3890 void DocxAttributeOutput::WriteField_Impl( const SwField* pFld, ww::eField eType, const String& rFldCmd, sal_uInt8 nMode )
3892 struct FieldInfos infos;
3893 if (pFld)
3894 infos.pField = pFld->CopyField();
3895 infos.sCmd = rFldCmd;
3896 infos.eType = eType;
3897 infos.bClose = WRITEFIELD_CLOSE & nMode;
3898 infos.bOpen = WRITEFIELD_START & nMode;
3899 m_Fields.push_back( infos );
3901 if ( pFld )
3903 sal_uInt16 nType = pFld->GetTyp( )->Which( );
3904 sal_uInt16 nSubType = pFld->GetSubType();
3906 // TODO Any other field types here ?
3907 if ( ( nType == RES_SETEXPFLD ) && ( nSubType & nsSwGetSetExpType::GSE_STRING ) )
3909 const SwSetExpField *pSet = ( const SwSetExpField* )( pFld );
3910 m_sFieldBkm = pSet->GetPar1( );
3912 else if ( nType == RES_DROPDOWN )
3914 const SwDropDownField* pDropDown = ( const SwDropDownField* )( pFld );
3915 m_sFieldBkm = pDropDown->GetName( );
3920 void DocxAttributeOutput::WriteFormData_Impl( const ::sw::mark::IFieldmark& rFieldmark )
3922 if ( !m_Fields.empty() )
3923 m_Fields.begin()->pFieldmark = &rFieldmark;
3926 void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts,
3927 std::vector< OUString >& rEnds )
3929 for ( std::vector< OUString >::const_iterator it = rStarts.begin(), end = rStarts.end(); it != end; ++it )
3931 OString rName = OUStringToOString( *it, RTL_TEXTENCODING_UTF8 ).getStr( );
3932 m_rMarksStart.push_back( rName );
3934 rStarts.clear();
3936 for ( std::vector< OUString >::const_iterator it = rEnds.begin(), end = rEnds.end(); it != end; ++it )
3938 OString rName = OUStringToOString( *it, RTL_TEXTENCODING_UTF8 ).getStr( );
3939 m_rMarksEnd.push_back( rName );
3941 rEnds.clear();
3944 void DocxAttributeOutput::TextFootnote_Impl( const SwFmtFtn& rFootnote )
3946 const SwEndNoteInfo& rInfo = rFootnote.IsEndNote()?
3947 m_rExport.pDoc->GetEndNoteInfo(): m_rExport.pDoc->GetFtnInfo();
3949 // footnote/endnote run properties
3950 const SwCharFmt* pCharFmt = rInfo.GetAnchorCharFmt( *m_rExport.pDoc );
3952 OString aStyleId( "style" );
3953 aStyleId += OString::valueOf( sal_Int32( m_rExport.GetId( *pCharFmt ) ) );
3955 m_pSerializer->singleElementNS( XML_w, XML_rStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND );
3957 // remember the footnote/endnote to
3958 // 1) write the footnoteReference/endnoteReference in EndRunProperties()
3959 // 2) be able to dump them all to footnotes.xml/endnotes.xml
3960 if ( !rFootnote.IsEndNote() )
3961 m_pFootnotesList->add( rFootnote );
3962 else
3963 m_pEndnotesList->add( rFootnote );
3966 void DocxAttributeOutput::FootnoteEndnoteReference()
3968 sal_Int32 nId;
3969 const SwFmtFtn *pFootnote = m_pFootnotesList->getCurrent( nId );
3971 // both cannot be set at the same time - if they are, it's a bug
3972 if ( !pFootnote )
3973 pFootnote = m_pEndnotesList->getCurrent( nId );
3975 if ( !pFootnote )
3976 return;
3978 sal_Int32 nToken = pFootnote->IsEndNote()? XML_endnoteReference: XML_footnoteReference;
3980 // write it
3981 if ( pFootnote->GetNumStr().Len() == 0 )
3983 // autonumbered
3984 m_pSerializer->singleElementNS( XML_w, nToken,
3985 FSNS( XML_w, XML_id ), OString::valueOf( nId ).getStr(),
3986 FSEND );
3988 else
3990 // not autonumbered
3991 m_pSerializer->singleElementNS( XML_w, nToken,
3992 FSNS( XML_w, XML_customMarkFollows ), "1",
3993 FSNS( XML_w, XML_id ), OString::valueOf( nId ).getStr(),
3994 FSEND );
3996 RunText( pFootnote->GetNumStr() );
4000 void DocxAttributeOutput::FootnotesEndnotes( bool bFootnotes )
4002 const FootnotesVector& rVector = bFootnotes? m_pFootnotesList->getVector(): m_pEndnotesList->getVector();
4004 sal_Int32 nBody = bFootnotes? XML_footnotes: XML_endnotes;
4005 sal_Int32 nItem = bFootnotes? XML_footnote: XML_endnote;
4007 m_pSerializer->startElementNS( XML_w, nBody,
4008 FSNS( XML_xmlns, XML_w ), "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
4009 FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
4010 FSEND );
4012 sal_Int32 nIndex = 0;
4014 // separator
4015 m_pSerializer->startElementNS( XML_w, nItem,
4016 FSNS( XML_w, XML_id ), OString::valueOf( nIndex++ ).getStr(),
4017 FSNS( XML_w, XML_type ), "separator",
4018 FSEND );
4019 m_pSerializer->startElementNS( XML_w, XML_p, FSEND );
4020 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
4021 m_pSerializer->singleElementNS( XML_w, XML_separator, FSEND );
4022 m_pSerializer->endElementNS( XML_w, XML_r );
4023 m_pSerializer->endElementNS( XML_w, XML_p );
4024 m_pSerializer->endElementNS( XML_w, nItem );
4026 // separator
4027 m_pSerializer->startElementNS( XML_w, nItem,
4028 FSNS( XML_w, XML_id ), OString::valueOf( nIndex++ ).getStr(),
4029 FSNS( XML_w, XML_type ), "continuationSeparator",
4030 FSEND );
4031 m_pSerializer->startElementNS( XML_w, XML_p, FSEND );
4032 m_pSerializer->startElementNS( XML_w, XML_r, FSEND );
4033 m_pSerializer->singleElementNS( XML_w, XML_continuationSeparator, FSEND );
4034 m_pSerializer->endElementNS( XML_w, XML_r );
4035 m_pSerializer->endElementNS( XML_w, XML_p );
4036 m_pSerializer->endElementNS( XML_w, nItem );
4038 // if new special ones are added, update also WriteFootnoteEndnotePr()
4040 // footnotes/endnotes themselves
4041 for ( FootnotesVector::const_iterator i = rVector.begin(); i != rVector.end(); ++i, ++nIndex )
4043 m_pSerializer->startElementNS( XML_w, nItem,
4044 FSNS( XML_w, XML_id ), OString::valueOf( nIndex ).getStr(),
4045 FSEND );
4047 const SwNodeIndex* pIndex = (*i)->GetTxtFtn()->GetStartNode();
4048 // tag required at the start of each footnote/endnote
4049 m_footnoteEndnoteRefTag = bFootnotes ? XML_footnoteRef : XML_endnoteRef;
4051 m_rExport.WriteSpecialText( pIndex->GetIndex() + 1,
4052 pIndex->GetNode().EndOfSectionIndex(),
4053 bFootnotes? TXT_FTN: TXT_EDN );
4055 m_pSerializer->endElementNS( XML_w, nItem );
4058 m_pSerializer->endElementNS( XML_w, nBody );
4062 void DocxAttributeOutput::WriteFootnoteEndnotePr( ::sax_fastparser::FSHelperPtr fs, int tag,
4063 const SwEndNoteInfo& info, int listtag )
4065 fs->startElementNS( XML_w, tag, FSEND );
4066 const char* fmt = NULL;
4067 switch( info.aFmt.GetNumberingType())
4069 case SVX_NUM_CHARS_UPPER_LETTER_N: // fall through, map to upper letters
4070 case SVX_NUM_CHARS_UPPER_LETTER:
4071 fmt = "upperLetter";
4072 break;
4073 case SVX_NUM_CHARS_LOWER_LETTER_N: // fall through, map to lower letters
4074 case SVX_NUM_CHARS_LOWER_LETTER:
4075 fmt = "lowerLetter";
4076 break;
4077 case SVX_NUM_ROMAN_UPPER:
4078 fmt = "upperRoman";
4079 break;
4080 case SVX_NUM_ROMAN_LOWER:
4081 fmt = "lowerRoman";
4082 break;
4083 case SVX_NUM_ARABIC:
4084 fmt = "decimal";
4085 break;
4086 case SVX_NUM_NUMBER_NONE:
4087 fmt = "none";
4088 break;
4089 case SVX_NUM_CHAR_SPECIAL:
4090 fmt = "bullet";
4091 break;
4092 case SVX_NUM_PAGEDESC:
4093 case SVX_NUM_BITMAP:
4094 default:
4095 break; // no format
4097 if( fmt != NULL )
4098 fs->singleElementNS( XML_w, XML_numFmt, FSNS( XML_w, XML_val ), fmt, FSEND );
4099 if( info.nFtnOffset != 0 )
4100 fs->singleElementNS( XML_w, XML_numStart, FSNS( XML_w, XML_val ),
4101 OString::valueOf( sal_Int32( info.nFtnOffset + 1 )).getStr(), FSEND );
4102 if( listtag != 0 ) // we are writing to settings.xml, write also special footnote/endnote list
4103 { // there are currently only two hardcoded ones ( see FootnotesEndnotes())
4104 fs->singleElementNS( XML_w, listtag, FSNS( XML_w, XML_id ), "0", FSEND );
4105 fs->singleElementNS( XML_w, listtag, FSNS( XML_w, XML_id ), "1", FSEND );
4107 fs->endElementNS( XML_w, tag );
4110 void DocxAttributeOutput::SectFootnoteEndnotePr()
4112 if( HasFootnotes())
4113 WriteFootnoteEndnotePr( m_pSerializer, XML_footnotePr, m_rExport.pDoc->GetFtnInfo(), 0 );
4114 if( HasEndnotes())
4115 WriteFootnoteEndnotePr( m_pSerializer, XML_endnotePr, m_rExport.pDoc->GetEndNoteInfo(), 0 );
4118 void DocxAttributeOutput::ParaLineSpacing_Impl( short nSpace, short nMulti )
4120 if ( !m_pParagraphSpacingAttrList )
4121 m_pParagraphSpacingAttrList = m_pSerializer->createAttrList();
4123 if ( nSpace < 0 )
4125 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_lineRule ), "exact" );
4126 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_line ), OString::valueOf( sal_Int32( -nSpace ) ) );
4128 else if( nMulti )
4130 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_lineRule ), "auto" );
4131 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_line ), OString::valueOf( sal_Int32( nSpace ) ) );
4133 else if ( nSpace > 0 )
4135 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_lineRule ), "atLeast" );
4136 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_line ), OString::valueOf( sal_Int32( nSpace ) ) );
4138 else
4139 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_lineRule ), "auto" );
4142 void DocxAttributeOutput::ParaAdjust( const SvxAdjustItem& rAdjust )
4144 const char *pAdjustString;
4146 bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT;
4148 const SfxItemSet* pItems = GetExport().GetCurItemSet();
4149 const SvxFrameDirectionItem* rFrameDir = static_cast< const SvxFrameDirectionItem* >( pItems->GetItem( RES_FRAMEDIR ) );
4151 short nDir = FRMDIR_ENVIRONMENT;
4152 if( rFrameDir != NULL )
4153 nDir = rFrameDir->GetValue();
4154 if ( nDir == FRMDIR_ENVIRONMENT )
4155 nDir = GetExport( ).GetDefaultFrameDirection( );
4156 bool bRtl = ( nDir == FRMDIR_HORI_RIGHT_TOP );
4158 switch ( rAdjust.GetAdjust() )
4160 case SVX_ADJUST_LEFT:
4161 if ( bEcma )
4162 pAdjustString = "left";
4163 else if ( bRtl )
4164 pAdjustString = "end";
4165 else
4166 pAdjustString = "start";
4167 break;
4168 case SVX_ADJUST_RIGHT:
4169 if ( bEcma )
4170 pAdjustString = "right";
4171 else if ( bRtl )
4172 pAdjustString = "start";
4173 else
4174 pAdjustString = "end";
4175 break;
4176 case SVX_ADJUST_BLOCKLINE:
4177 case SVX_ADJUST_BLOCK:
4178 pAdjustString = "both";
4179 break;
4180 case SVX_ADJUST_CENTER:
4181 pAdjustString = "center";
4182 break;
4183 default:
4184 return; // not supported attribute
4186 m_pSerializer->singleElementNS( XML_w, XML_jc, FSNS( XML_w, XML_val ), pAdjustString, FSEND );
4189 void DocxAttributeOutput::ParaSplit( const SvxFmtSplitItem& rSplit )
4191 if (rSplit.GetValue())
4192 m_pSerializer->singleElementNS( XML_w, XML_keepLines, FSNS( XML_w, XML_val ), "false", FSEND );
4193 else
4194 m_pSerializer->singleElementNS( XML_w, XML_keepLines, FSEND );
4197 void DocxAttributeOutput::ParaWidows( const SvxWidowsItem& rWidows )
4199 if (rWidows.GetValue())
4200 m_pSerializer->singleElementNS( XML_w, XML_widowControl, FSEND );
4201 else
4202 m_pSerializer->singleElementNS( XML_w, XML_widowControl, FSNS( XML_w, XML_val ), "false", FSEND );
4205 static void impl_WriteTabElement( FSHelperPtr pSerializer,
4206 const SvxTabStop& rTab, long /* nCurrentLeft */ )
4208 FastAttributeList *pTabElementAttrList = pSerializer->createAttrList();
4210 switch (rTab.GetAdjustment())
4212 case SVX_TAB_ADJUST_RIGHT:
4213 pTabElementAttrList->add( FSNS( XML_w, XML_val ), OString( (sal_Char *)"right") );
4214 break;
4215 case SVX_TAB_ADJUST_DECIMAL:
4216 pTabElementAttrList->add( FSNS( XML_w, XML_val ), OString( (sal_Char *)"decimal") );
4217 break;
4218 case SVX_TAB_ADJUST_CENTER:
4219 pTabElementAttrList->add( FSNS( XML_w, XML_val ), OString( (sal_Char *)"center") );
4220 break;
4221 case SVX_TAB_ADJUST_DEFAULT:
4222 case SVX_TAB_ADJUST_LEFT:
4223 default:
4224 pTabElementAttrList->add( FSNS( XML_w, XML_val ), OString( (sal_Char *)"left") );
4225 break;
4228 // Because GetTabPos already includes indent, we don't need to add nCurrentLeft (CurrentLeft is indentation information)
4229 //pTabElementAttrList->add( FSNS( XML_w, XML_pos ), OString::valueOf( rTab.GetTabPos() + nCurrentLeft ) );
4230 pTabElementAttrList->add( FSNS( XML_w, XML_pos ), OString::valueOf( rTab.GetTabPos() ) );
4232 sal_Unicode cFillChar = rTab.GetFill();
4234 if (sal_Unicode('.') == cFillChar )
4235 pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "dot" ) );
4236 else if ( sal_Unicode('-') == cFillChar )
4237 pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "hyphen" ) );
4238 else if ( sal_Unicode(0xB7) == cFillChar ) // middle dot
4239 pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "middleDot" ) );
4240 else if ( sal_Unicode('_') == cFillChar )
4241 pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "underscore" ) );
4242 else
4243 pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "none" ) );
4245 pSerializer->singleElementNS( XML_w, XML_tab, pTabElementAttrList );
4248 void DocxAttributeOutput::ParaTabStop( const SvxTabStopItem& rTabStop )
4250 const SfxPoolItem* pLR = m_rExport.HasItem( RES_LR_SPACE );
4251 long nCurrentLeft = pLR ? ((const SvxLRSpaceItem*)pLR)->GetTxtLeft() : 0;
4253 sal_uInt16 nCount = rTabStop.Count();
4255 // <w:tabs> must contain at least one <w:tab>, so don't write it empty
4256 if( nCount == 0 )
4257 return;
4258 if( nCount == 1 && rTabStop[ 0 ].GetAdjustment() == SVX_TAB_ADJUST_DEFAULT )
4260 GetExport().setDefaultTabStop( rTabStop[ 0 ].GetTabPos());
4261 return;
4264 m_pSerializer->startElementNS( XML_w, XML_tabs, FSEND );
4266 for (sal_uInt16 i = 0; i < nCount; i++ )
4268 if( rTabStop[i].GetAdjustment() != SVX_TAB_ADJUST_DEFAULT )
4269 impl_WriteTabElement( m_pSerializer, rTabStop[i], nCurrentLeft );
4270 else
4271 GetExport().setDefaultTabStop( rTabStop[i].GetTabPos());
4274 m_pSerializer->endElementNS( XML_w, XML_tabs );
4277 void DocxAttributeOutput::ParaHyphenZone( const SvxHyphenZoneItem& rHyphenZone )
4279 m_pSerializer->singleElementNS( XML_w, XML_suppressAutoHyphens,
4280 FSNS( XML_w, XML_val ), rHyphenZone.IsHyphen( ) ? "false" : "true" ,
4281 FSEND );
4284 void DocxAttributeOutput::ParaNumRule_Impl( const SwTxtNode* /*pTxtNd*/, sal_Int32 nLvl, sal_Int32 nNumId )
4286 if ( USHRT_MAX != nNumId && 0 != nNumId )
4288 m_pSerializer->startElementNS( XML_w, XML_numPr, FSEND );
4289 m_pSerializer->singleElementNS( XML_w, XML_ilvl, FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nLvl )).getStr(), FSEND );
4290 m_pSerializer->singleElementNS( XML_w, XML_numId, FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nNumId )).getStr(), FSEND );
4291 m_pSerializer->endElementNS( XML_w, XML_numPr );
4295 void DocxAttributeOutput::ParaScriptSpace( const SfxBoolItem& rScriptSpace )
4297 sal_uInt16 nXmlElement = 0;
4299 switch ( rScriptSpace.Which( ) )
4301 case RES_PARATR_SCRIPTSPACE:
4302 nXmlElement = XML_autoSpaceDE;
4303 break;
4304 case RES_PARATR_HANGINGPUNCTUATION:
4305 nXmlElement = XML_overflowPunct;
4306 break;
4307 case RES_PARATR_FORBIDDEN_RULES:
4308 nXmlElement = XML_kinsoku;
4309 break;
4312 if ( nXmlElement )
4314 m_pSerializer->singleElementNS( XML_w, nXmlElement,
4315 FSNS( XML_w, XML_val ), rScriptSpace.GetValue( ) ? "true": "false",
4316 FSEND );
4320 void DocxAttributeOutput::ParaVerticalAlign( const SvxParaVertAlignItem& rAlign )
4322 const char *pAlignString;
4324 switch ( rAlign.GetValue() )
4326 case SvxParaVertAlignItem::BASELINE:
4327 pAlignString = "baseline";
4328 break;
4329 case SvxParaVertAlignItem::TOP:
4330 pAlignString = "top";
4331 break;
4332 case SvxParaVertAlignItem::CENTER:
4333 pAlignString = "center";
4334 break;
4335 case SvxParaVertAlignItem::BOTTOM:
4336 pAlignString = "bottom";
4337 break;
4338 case SvxParaVertAlignItem::AUTOMATIC:
4339 pAlignString = "auto";
4340 break;
4341 default:
4342 return; // not supported attribute
4344 m_pSerializer->singleElementNS( XML_w, XML_textAlignment, FSNS( XML_w, XML_val ), pAlignString, FSEND );
4347 void DocxAttributeOutput::ParaSnapToGrid( const SvxParaGridItem& rGrid )
4349 m_pSerializer->singleElementNS( XML_w, XML_snapToGrid,
4350 FSNS( XML_w, XML_val ), rGrid.GetValue( ) ? "true": "false",
4351 FSEND );
4354 void DocxAttributeOutput::FormatFrameSize( const SwFmtFrmSize& rSize )
4356 if (m_bTextFrameSyntax && m_pFlyFrameSize)
4358 m_aTextFrameStyle.append(";width:").append(double(m_pFlyFrameSize->Width()) / 20);
4359 m_aTextFrameStyle.append("pt;height:").append(double(m_pFlyFrameSize->Height()) / 20).append("pt");
4361 else if ( m_rExport.bOutFlyFrmAttrs )
4363 if ( !m_pFlyAttrList )
4364 m_pFlyAttrList = m_pSerializer->createAttrList( );
4366 if ( rSize.GetWidth() && rSize.GetWidthSizeType() == ATT_FIX_SIZE )
4368 m_pFlyAttrList->add( FSNS( XML_w, XML_w ), OString::valueOf( rSize.GetWidth( ) ) );
4371 if ( rSize.GetHeight() )
4373 OString sRule( "exact" );
4374 if ( rSize.GetHeightSizeType() == ATT_MIN_SIZE )
4375 sRule = OString( "atLeast" );
4376 m_pFlyAttrList->add( FSNS( XML_w, XML_hRule ), sRule );
4377 m_pFlyAttrList->add( FSNS( XML_w, XML_h ), OString::valueOf( rSize.GetHeight( ) ) );
4380 else if ( m_rExport.bOutPageDescs )
4382 FastAttributeList *attrList = m_pSerializer->createAttrList( );
4383 if ( m_rExport.pAktPageDesc->GetLandscape( ) )
4384 attrList->add( FSNS( XML_w, XML_orient ), "landscape" );
4386 attrList->add( FSNS( XML_w, XML_w ), OString::valueOf( rSize.GetWidth( ) ) );
4387 attrList->add( FSNS( XML_w, XML_h ), OString::valueOf( rSize.GetHeight( ) ) );
4389 XFastAttributeListRef xAttrList( attrList );
4390 attrList = NULL;
4392 m_pSerializer->singleElementNS( XML_w, XML_pgSz, xAttrList );
4396 void DocxAttributeOutput::FormatPaperBin( const SvxPaperBinItem& )
4398 OSL_TRACE( "TODO DocxAttributeOutput::FormatPaperBin()" );
4401 void DocxAttributeOutput::FormatLRSpace( const SvxLRSpaceItem& rLRSpace )
4403 bool bEcma = m_rExport.GetFilter().getVersion( ) == oox::core::ECMA_DIALECT;
4405 if (m_bTextFrameSyntax)
4408 else if ( m_rExport.bOutFlyFrmAttrs )
4410 if ( !m_pFlyAttrList )
4411 m_pFlyAttrList = m_pSerializer->createAttrList();
4413 m_pFlyAttrList->add( FSNS( XML_w, XML_hSpace ),
4414 OString::valueOf(
4415 sal_Int32( ( rLRSpace.GetLeft() + rLRSpace.GetRight() ) / 2 ) ) );
4417 else if ( m_rExport.bOutPageDescs )
4419 if ( !m_pSectionSpacingAttrList )
4420 m_pSectionSpacingAttrList = m_pSerializer->createAttrList();
4422 sal_uInt16 nLDist, nRDist;
4423 const SfxPoolItem* pItem = m_rExport.HasItem( RES_BOX );
4424 if ( pItem )
4426 nRDist = ((SvxBoxItem*)pItem)->CalcLineSpace( BOX_LINE_LEFT );
4427 nLDist = ((SvxBoxItem*)pItem)->CalcLineSpace( BOX_LINE_RIGHT );
4429 else
4430 nLDist = nRDist = 0;
4431 nLDist = nLDist + (sal_uInt16)rLRSpace.GetLeft();
4432 nRDist = nRDist + (sal_uInt16)rLRSpace.GetRight();
4434 m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_left ), OString::valueOf( sal_Int32( nLDist ) ) );
4435 m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_right ), OString::valueOf( sal_Int32( nRDist ) ) );
4437 else
4439 FastAttributeList *pLRSpaceAttrList = m_pSerializer->createAttrList();
4441 pLRSpaceAttrList->add( FSNS( XML_w, ( bEcma ? XML_left : XML_start ) ), OString::valueOf( (sal_Int32) rLRSpace.GetTxtLeft() ) );
4442 pLRSpaceAttrList->add( FSNS( XML_w, ( bEcma ? XML_right : XML_end ) ), OString::valueOf( (sal_Int32) rLRSpace.GetRight() ) );
4444 sal_Int32 nFirstLineAdjustment = rLRSpace.GetTxtFirstLineOfst();
4445 if (nFirstLineAdjustment > 0)
4446 pLRSpaceAttrList->add( FSNS( XML_w, XML_firstLine ), OString::valueOf( nFirstLineAdjustment ) );
4447 else
4448 pLRSpaceAttrList->add( FSNS( XML_w, XML_hanging ), OString::valueOf( - nFirstLineAdjustment ) );
4449 m_pSerializer->singleElementNS( XML_w, XML_ind, pLRSpaceAttrList );
4453 void DocxAttributeOutput::FormatULSpace( const SvxULSpaceItem& rULSpace )
4456 if (m_bTextFrameSyntax)
4459 else if ( m_rExport.bOutFlyFrmAttrs )
4461 if ( !m_pFlyAttrList )
4462 m_pFlyAttrList = m_pSerializer->createAttrList();
4464 m_pFlyAttrList->add( FSNS( XML_w, XML_vSpace ),
4465 OString::valueOf(
4466 sal_Int32( ( rULSpace.GetLower() + rULSpace.GetUpper() ) / 2 ) ) );
4468 else if (m_rExport.bOutPageDescs )
4470 OSL_ENSURE( m_rExport.GetCurItemSet(), "Impossible" );
4471 if ( !m_rExport.GetCurItemSet() )
4472 return;
4474 if ( !m_pSectionSpacingAttrList )
4475 m_pSectionSpacingAttrList = m_pSerializer->createAttrList();
4477 HdFtDistanceGlue aDistances( *m_rExport.GetCurItemSet() );
4479 sal_Int32 nHeader = 0;
4480 if ( aDistances.HasHeader() )
4481 nHeader = sal_Int32( aDistances.dyaHdrTop );
4482 m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_header ), OString::valueOf( nHeader ) );
4484 // Page top
4485 m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_top ),
4486 OString::valueOf( sal_Int32( aDistances.dyaTop ) ) );
4488 sal_Int32 nFooter = 0;
4489 if ( aDistances.HasFooter() )
4490 nFooter = sal_Int32( aDistances.dyaHdrBottom );
4491 m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_footer ), OString::valueOf( nFooter ) );
4493 // Page Bottom
4494 m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_bottom ),
4495 OString::valueOf( sal_Int32( aDistances.dyaBottom ) ) );
4497 // FIXME Page Gutter is not handled ATM, setting to 0 as it's mandatory for OOXML
4498 m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_gutter ),
4499 OString::valueOf( sal_Int32( 0 ) ) );
4502 else
4504 if ( !m_pParagraphSpacingAttrList )
4505 m_pParagraphSpacingAttrList = m_pSerializer->createAttrList();
4506 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_before ),
4507 OString::valueOf( (sal_Int32)rULSpace.GetUpper() ) );
4508 m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_after ),
4509 OString::valueOf( (sal_Int32)rULSpace.GetLower() ) );
4510 if (rULSpace.GetContext())
4511 m_pSerializer->singleElementNS( XML_w, XML_contextualSpacing, FSEND );
4512 else
4513 m_pSerializer->singleElementNS( XML_w, XML_contextualSpacing, FSNS( XML_w, XML_val ), "false", FSEND );
4517 void DocxAttributeOutput::FormatSurround( const SwFmtSurround& rSurround )
4519 if (m_bTextFrameSyntax)
4521 OString sType, sSide;
4522 switch (rSurround.GetSurround())
4524 case SURROUND_NONE:
4525 sType = "topAndBottom";
4526 break;
4527 case SURROUND_PARALLEL:
4528 sType = "square";
4529 break;
4530 case SURROUND_IDEAL:
4531 sType = "square";
4532 sSide = "largest";
4533 break;
4534 case SURROUND_LEFT:
4535 sType = "square";
4536 sSide = "left";
4537 break;
4538 case SURROUND_RIGHT:
4539 sType = "square";
4540 sSide = "right";
4541 break;
4542 case SURROUND_THROUGHT:
4543 /* empty type and side means throught */
4544 default:
4545 break;
4547 if (!sType.isEmpty() || !sSide.isEmpty())
4549 m_pFlyWrapAttrList = m_pSerializer->createAttrList();
4550 if (!sType.isEmpty())
4551 m_pFlyWrapAttrList->add(XML_type, sType);
4552 if (!sSide.isEmpty())
4553 m_pFlyWrapAttrList->add(XML_side, sSide);
4556 else if ( m_rExport.bOutFlyFrmAttrs )
4558 if ( !m_pFlyAttrList )
4559 m_pFlyAttrList = m_pSerializer->createAttrList();
4561 OString sWrap( "auto" );
4562 switch ( rSurround.GetSurround( ) )
4564 case SURROUND_NONE:
4565 sWrap = OString( "none" );
4566 break;
4567 case SURROUND_THROUGHT:
4568 sWrap = OString( "through" );
4569 break;
4570 case SURROUND_IDEAL:
4571 case SURROUND_PARALLEL:
4572 case SURROUND_LEFT:
4573 case SURROUND_RIGHT:
4574 default:
4575 sWrap = OString( "around" );
4578 m_pFlyAttrList->add( FSNS( XML_w, XML_wrap ), sWrap );
4582 void DocxAttributeOutput::FormatVertOrientation( const SwFmtVertOrient& rFlyVert )
4584 if (m_bTextFrameSyntax)
4586 m_aTextFrameStyle.append(";margin-top:").append(double(rFlyVert.GetPos()) / 20).append("pt");
4588 else if ( m_rExport.bOutFlyFrmAttrs )
4590 if ( !m_pFlyAttrList )
4591 m_pFlyAttrList = m_pSerializer->createAttrList();
4593 OString sAlign;
4594 switch( rFlyVert.GetVertOrient() )
4596 case text::VertOrientation::NONE:
4597 break;
4598 case text::VertOrientation::CENTER:
4599 case text::VertOrientation::LINE_CENTER:
4600 sAlign = OString( "center" );
4601 break;
4602 case text::VertOrientation::BOTTOM:
4603 case text::VertOrientation::LINE_BOTTOM:
4604 sAlign = OString( "bottom" );
4605 break;
4606 case text::VertOrientation::TOP:
4607 case text::VertOrientation::LINE_TOP:
4608 default:
4609 sAlign = OString( "top" );
4610 break;
4613 if ( !sAlign.isEmpty() )
4614 m_pFlyAttrList->add( FSNS( XML_w, XML_yAlign ), sAlign );
4615 else
4616 m_pFlyAttrList->add( FSNS( XML_w, XML_y ),
4617 OString::valueOf( sal_Int32( rFlyVert.GetPos() ) ) );
4619 OString sVAnchor( "page" );
4620 switch ( rFlyVert.GetRelationOrient( ) )
4622 case text::RelOrientation::CHAR:
4623 case text::RelOrientation::PRINT_AREA:
4624 case text::RelOrientation::TEXT_LINE:
4625 sVAnchor = OString( "column" );
4626 break;
4627 case text::RelOrientation::FRAME:
4628 case text::RelOrientation::PAGE_LEFT:
4629 case text::RelOrientation::PAGE_RIGHT:
4630 case text::RelOrientation::FRAME_LEFT:
4631 case text::RelOrientation::FRAME_RIGHT:
4632 sVAnchor = OString( "margin" );
4633 break;
4634 case text::RelOrientation::PAGE_FRAME:
4635 case text::RelOrientation::PAGE_PRINT_AREA:
4636 default:
4637 break;
4640 m_pFlyAttrList->add( FSNS( XML_w, XML_vAnchor ), sVAnchor );
4644 void DocxAttributeOutput::FormatHorizOrientation( const SwFmtHoriOrient& rFlyHori )
4646 if (m_bTextFrameSyntax)
4648 m_aTextFrameStyle.append(";margin-left:").append(double(rFlyHori.GetPos()) / 20).append("pt");
4650 else if ( m_rExport.bOutFlyFrmAttrs )
4652 if ( !m_pFlyAttrList )
4653 m_pFlyAttrList = m_pSerializer->createAttrList();
4655 OString sAlign;
4656 switch( rFlyHori.GetHoriOrient() )
4658 case text::HoriOrientation::NONE:
4659 break;
4660 case text::HoriOrientation::LEFT:
4661 sAlign = OString( rFlyHori.IsPosToggle( ) ? "inside" : "left" );
4662 break;
4663 case text::HoriOrientation::RIGHT:
4664 sAlign = OString( rFlyHori.IsPosToggle( ) ? "outside" : "right" );
4665 break;
4666 case text::HoriOrientation::CENTER:
4667 case text::HoriOrientation::FULL: // FULL only for tables
4668 default:
4669 sAlign = OString( "center" );
4670 break;
4673 if ( !sAlign.isEmpty() )
4674 m_pFlyAttrList->add( FSNS( XML_w, XML_xAlign ), sAlign );
4675 else
4676 m_pFlyAttrList->add( FSNS( XML_w, XML_x ),
4677 OString::valueOf( sal_Int32( rFlyHori.GetPos() ) ) );
4679 OString sHAnchor( "page" );
4680 switch ( rFlyHori.GetRelationOrient( ) )
4682 case text::RelOrientation::CHAR:
4683 case text::RelOrientation::PRINT_AREA:
4684 sHAnchor = OString( "text" );
4685 break;
4686 case text::RelOrientation::FRAME:
4687 case text::RelOrientation::PAGE_LEFT:
4688 case text::RelOrientation::PAGE_RIGHT:
4689 case text::RelOrientation::FRAME_LEFT:
4690 case text::RelOrientation::FRAME_RIGHT:
4691 sHAnchor = OString( "margin" );
4692 break;
4693 case text::RelOrientation::PAGE_FRAME:
4694 case text::RelOrientation::PAGE_PRINT_AREA:
4695 default:
4696 break;
4699 m_pFlyAttrList->add( FSNS( XML_w, XML_hAnchor ), sHAnchor );
4703 void DocxAttributeOutput::FormatAnchor( const SwFmtAnchor& )
4705 // Fly frames: anchors here aren't matching the anchors in docx
4708 void DocxAttributeOutput::FormatBackground( const SvxBrushItem& rBrush )
4710 OString sColor = msfilter::util::ConvertColor( rBrush.GetColor( ) );
4711 if (m_bTextFrameSyntax)
4712 m_pFlyAttrList->add(XML_fillcolor, "#" + sColor);
4713 else if ( !m_rExport.bOutPageDescs )
4715 m_pSerializer->singleElementNS( XML_w, XML_shd,
4716 FSNS( XML_w, XML_fill ), sColor.getStr( ),
4717 FSNS( XML_w, XML_val ), "clear",
4718 FSEND );
4722 void DocxAttributeOutput::FormatFillStyle( const XFillStyleItem& rFillStyle )
4724 m_oFillStyle.reset(rFillStyle.GetValue());
4727 void DocxAttributeOutput::FormatFillGradient( const XFillGradientItem& rFillGradient )
4729 if (*m_oFillStyle == XFILL_GRADIENT)
4731 m_pFlyFillAttrList = m_pSerializer->createAttrList();
4732 m_pFlyFillAttrList->add(XML_type, "gradient");
4734 const XGradient& rGradient = rFillGradient.GetGradientValue();
4735 OString sStartColor = msfilter::util::ConvertColor(rGradient.GetStartColor());
4736 m_pFlyFillAttrList->add(XML_color2, "#" + sStartColor);
4737 OString sEndColor = msfilter::util::ConvertColor(rGradient.GetEndColor());
4738 m_pFlyAttrList->add(XML_fillcolor, "#" + sEndColor);
4740 switch (rGradient.GetGradientStyle())
4742 case XGRAD_LINEAR: break;
4743 case XGRAD_AXIAL:
4744 m_pFlyFillAttrList->add(XML_focus, "50%");
4745 break;
4746 case XGRAD_RADIAL: break;
4747 case XGRAD_ELLIPTICAL: break;
4748 case XGRAD_SQUARE: break;
4749 case XGRAD_RECT: break;
4752 m_oFillStyle.reset();
4755 void DocxAttributeOutput::FormatBox( const SvxBoxItem& rBox )
4757 if (m_bTextFrameSyntax)
4759 const SvxBorderLine* pLeft = rBox.GetLine(BOX_LINE_LEFT);
4760 const SvxBorderLine* pRight = rBox.GetLine(BOX_LINE_RIGHT);
4761 const SvxBorderLine* pTop = rBox.GetLine(BOX_LINE_TOP);
4762 const SvxBorderLine* pBottom = rBox.GetLine(BOX_LINE_BOTTOM);
4763 if (pLeft && pRight && pTop && pBottom &&
4764 *pLeft == *pRight && *pLeft == *pTop && *pLeft == *pBottom)
4766 OString sColor("#" + msfilter::util::ConvertColor(pTop->GetColor()));
4767 m_pFlyAttrList->add(XML_strokecolor, sColor);
4769 double const fConverted(editeng::ConvertBorderWidthToWord(pTop->GetBorderLineStyle(), pTop->GetWidth()));
4770 sal_Int32 nWidth = sal_Int32(fConverted / 20);
4771 m_pFlyAttrList->add(XML_strokeweight, OString::valueOf(nWidth) + "pt");
4774 // v:textbox's inset attribute: inner margin values for textbox text
4775 OStringBuffer aInset;
4776 aInset.append(OString::number(double(rBox.GetDistance(BOX_LINE_LEFT))/20) + "pt,");
4777 aInset.append(OString::number(double(rBox.GetDistance(BOX_LINE_TOP))/20) + "pt,");
4778 aInset.append(OString::number(double(rBox.GetDistance(BOX_LINE_RIGHT))/20) + "pt,");
4779 aInset.append(OString::number(double(rBox.GetDistance(BOX_LINE_BOTTOM))/20) + "pt");
4780 m_pTextboxAttrList->add(XML_inset, aInset.makeStringAndClear());
4781 return;
4784 if ( !m_bOpenedSectPr )
4786 // Normally open the borders tag for paragraphs
4787 m_pSerializer->startElementNS( XML_w, XML_pBdr, FSEND );
4790 impl_pageBorders( m_pSerializer, rBox, XML_pBdr, false, false );
4792 if ( m_bOpenedSectPr )
4794 // Special handling for pgBorder
4795 m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND );
4796 m_pSerializer->mergeTopMarks( );
4798 else
4800 // Normally close the borders tag for paragraphs
4801 m_pSerializer->endElementNS( XML_w, XML_pBdr );
4805 void DocxAttributeOutput::FormatColumns_Impl( sal_uInt16 nCols, const SwFmtCol& rCol, bool bEven, SwTwips nPageSize )
4807 // Get the columns attributes
4808 FastAttributeList *pColsAttrList = m_pSerializer->createAttrList();
4810 pColsAttrList->add( FSNS( XML_w, XML_num ),
4811 OString::valueOf( sal_Int32( nCols ) ). getStr( ) );
4813 const char* pEquals = "false";
4814 if ( bEven )
4816 sal_uInt16 nWidth = rCol.GetGutterWidth( true );
4817 pColsAttrList->add( FSNS( XML_w, XML_space ),
4818 OString::valueOf( sal_Int32( nWidth ) ).getStr( ) );
4820 pEquals = "true";
4823 pColsAttrList->add( FSNS( XML_w, XML_equalWidth ), pEquals );
4825 bool bHasSep = COLADJ_NONE == rCol.GetLineAdj( );
4826 pColsAttrList->add( FSNS( XML_w, XML_sep ), bHasSep ? "true" : "false" );
4828 // Write the element
4829 m_pSerializer->startElementNS( XML_w, XML_cols, pColsAttrList );
4831 // Write the columns width if non-equals
4832 const SwColumns & rColumns = rCol.GetColumns( );
4833 if ( !bEven )
4835 for ( sal_uInt16 n = 0; n < nCols; ++n )
4837 FastAttributeList *pColAttrList = m_pSerializer->createAttrList();
4838 sal_uInt16 nWidth = rCol.CalcPrtColWidth( n, ( sal_uInt16 ) nPageSize );
4839 pColAttrList->add( FSNS( XML_w, XML_w ),
4840 OString::valueOf( sal_Int32( nWidth ) ).getStr( ) );
4842 if ( n + 1 != nCols )
4844 sal_uInt16 nSpacing = rColumns[n].GetRight( ) + rColumns[n + 1].GetLeft( );
4845 pColAttrList->add( FSNS( XML_w, XML_space ),
4846 OString::valueOf( sal_Int32( nSpacing ) ).getStr( ) );
4849 m_pSerializer->singleElementNS( XML_w, XML_col, pColAttrList );
4853 m_pSerializer->endElementNS( XML_w, XML_cols );
4856 void DocxAttributeOutput::FormatKeep( const SvxFmtKeepItem& )
4858 m_pSerializer->singleElementNS( XML_w, XML_keepNext, FSEND );
4861 void DocxAttributeOutput::FormatTextGrid( const SwTextGridItem& rGrid )
4863 FastAttributeList *pGridAttrList = m_pSerializer->createAttrList();
4865 OString sGridType;
4866 switch ( rGrid.GetGridType( ) )
4868 default:
4869 case GRID_NONE:
4870 sGridType = OString( "default" );
4871 break;
4872 case GRID_LINES_ONLY:
4873 sGridType = OString( "lines" );
4874 break;
4875 case GRID_LINES_CHARS:
4876 if ( rGrid.IsSnapToChars( ) )
4877 sGridType = OString( "snapToChars" );
4878 else
4879 sGridType = OString( "linesAndChars" );
4880 break;
4882 pGridAttrList->add( FSNS( XML_w, XML_type ), sGridType.getStr( ) );
4884 sal_uInt16 nHeight = rGrid.GetBaseHeight() + rGrid.GetRubyHeight();
4885 pGridAttrList->add( FSNS( XML_w, XML_linePitch ),
4886 OString::valueOf( sal_Int32( nHeight ) ).getStr( ) );
4888 pGridAttrList->add( FSNS( XML_w, XML_charSpace ),
4889 OString::valueOf( sal_Int32( GridCharacterPitch( rGrid ) ) ).getStr( ) );
4891 m_pSerializer->singleElementNS( XML_w, XML_docGrid, pGridAttrList );
4894 void DocxAttributeOutput::FormatLineNumbering( const SwFmtLineNumber& rNumbering )
4896 if ( !rNumbering.IsCount( ) )
4897 m_pSerializer->singleElementNS( XML_w, XML_suppressLineNumbers, FSEND );
4900 void DocxAttributeOutput::FormatFrameDirection( const SvxFrameDirectionItem& rDirection )
4902 OString sTextFlow;
4903 bool bBiDi = false;
4904 short nDir = rDirection.GetValue();
4906 if ( nDir == FRMDIR_ENVIRONMENT )
4907 nDir = GetExport( ).GetDefaultFrameDirection( );
4909 switch ( nDir )
4911 default:
4912 case FRMDIR_HORI_LEFT_TOP:
4913 sTextFlow = OString( "lrTb" );
4914 break;
4915 case FRMDIR_HORI_RIGHT_TOP:
4916 sTextFlow = OString( "lrTb" );
4917 bBiDi = true;
4918 break;
4919 case FRMDIR_VERT_TOP_LEFT: // many things but not this one
4920 case FRMDIR_VERT_TOP_RIGHT:
4921 sTextFlow = OString( "tbRl" );
4922 break;
4925 if ( m_rExport.bOutPageDescs )
4927 m_pSerializer->singleElementNS( XML_w, XML_textDirection,
4928 FSNS( XML_w, XML_val ), sTextFlow.getStr( ),
4929 FSEND );
4930 if ( bBiDi )
4931 m_pSerializer->singleElementNS( XML_w, XML_bidi, FSEND );
4933 else if ( !m_rExport.bOutFlyFrmAttrs )
4935 if ( bBiDi )
4936 m_pSerializer->singleElementNS( XML_w, XML_bidi, FSEND );
4940 DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSerializer, oox::drawingml::DrawingML* pDrawingML )
4941 : m_rExport( rExport ),
4942 m_pSerializer( pSerializer ),
4943 m_rDrawingML( *pDrawingML ),
4944 m_pFontsAttrList( NULL ),
4945 m_pEastAsianLayoutAttrList( NULL ),
4946 m_pCharLangAttrList( NULL ),
4947 m_pSectionSpacingAttrList( NULL ),
4948 m_pParagraphSpacingAttrList( NULL ),
4949 m_pHyperlinkAttrList( NULL ),
4950 m_pFlyAttrList( NULL ),
4951 m_pFlyFillAttrList( NULL ),
4952 m_pFlyWrapAttrList( NULL ),
4953 m_pTextboxAttrList( NULL ),
4954 m_pFlyFrameSize(0),
4955 m_pFootnotesList( new ::docx::FootnotesList() ),
4956 m_pEndnotesList( new ::docx::FootnotesList() ),
4957 m_footnoteEndnoteRefTag( 0 ),
4958 m_pSectionInfo( NULL ),
4959 m_pRedlineData( NULL ),
4960 m_nRedlineId( 0 ),
4961 m_bOpenedSectPr( false ),
4962 m_sFieldBkm( ),
4963 m_nNextMarkId( 0 ),
4964 m_bPostitStart(false),
4965 m_bPostitEnd(false),
4966 m_pTableWrt( NULL ),
4967 m_bTableCellOpen( false ),
4968 m_nTableDepth( 0 ),
4969 m_bParagraphOpened( false ),
4970 m_nColBreakStatus( COLBRK_NONE ),
4971 m_bTextFrameSyntax( false ),
4972 m_closeHyperlinkInThisRun( false ),
4973 m_closeHyperlinkInPreviousRun( false ),
4974 m_startedHyperlink( false ),
4975 m_postponedGraphic( NULL ),
4976 m_postponedMath( NULL ),
4977 pendingPlaceholder( NULL ),
4978 m_postitFieldsMaxId( 0 ),
4979 m_anchorId( 0 ),
4980 m_nextFontId( 1 ),
4981 m_bBtLr(false)
4985 DocxAttributeOutput::~DocxAttributeOutput()
4987 delete m_pFontsAttrList, m_pFontsAttrList = NULL;
4988 delete m_pEastAsianLayoutAttrList, m_pEastAsianLayoutAttrList = NULL;
4989 delete m_pCharLangAttrList, m_pCharLangAttrList = NULL;
4990 delete m_pSectionSpacingAttrList, m_pSectionSpacingAttrList = NULL;
4991 delete m_pParagraphSpacingAttrList, m_pParagraphSpacingAttrList = NULL;
4992 delete m_pHyperlinkAttrList, m_pHyperlinkAttrList = NULL;
4993 delete m_pFlyAttrList, m_pFlyAttrList = NULL;
4994 delete m_pTextboxAttrList, m_pTextboxAttrList = NULL;
4996 delete m_pFootnotesList, m_pFootnotesList = NULL;
4997 delete m_pEndnotesList, m_pEndnotesList = NULL;
4999 delete m_pTableWrt, m_pTableWrt = NULL;
5002 DocxExport& DocxAttributeOutput::GetExport()
5004 return m_rExport;
5007 bool DocxAttributeOutput::HasFootnotes() const
5009 return !m_pFootnotesList->isEmpty();
5012 bool DocxAttributeOutput::HasEndnotes() const
5014 return !m_pEndnotesList->isEmpty();
5017 bool DocxAttributeOutput::HasPostitFields() const
5019 return !m_postitFields.empty();
5022 void DocxAttributeOutput::BulletDefinition(int nId, const Graphic& rGraphic, Size aSize)
5024 m_pSerializer->startElementNS(XML_w, XML_numPicBullet,
5025 FSNS(XML_w, XML_numPicBulletId), OString::number(nId).getStr(),
5026 FSEND);
5028 OStringBuffer aStyle;
5029 // Size is in twips, we need it in points.
5030 aStyle.append("width:").append(double(aSize.Width()) / 20);
5031 aStyle.append("pt;height:").append(double(aSize.Height()) / 20).append("pt");
5032 m_pSerializer->startElementNS( XML_w, XML_pict, FSEND);
5033 m_pSerializer->startElementNS( XML_v, XML_shape,
5034 XML_style, aStyle.getStr(),
5035 FSNS(XML_o, XML_bullet), "t",
5036 FSEND);
5038 m_rDrawingML.SetFS(m_pSerializer);
5039 OUString aRelId = m_rDrawingML.WriteImage(rGraphic);
5040 m_pSerializer->singleElementNS( XML_v, XML_imagedata,
5041 FSNS(XML_r, XML_id), OUStringToOString(aRelId, RTL_TEXTENCODING_UTF8),
5042 FSNS(XML_o, XML_title), "",
5043 FSEND);
5045 m_pSerializer->endElementNS(XML_v, XML_shape);
5046 m_pSerializer->endElementNS(XML_w, XML_pict);
5048 m_pSerializer->endElementNS(XML_w, XML_numPicBullet);
5051 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */