diff options
Diffstat (limited to 'sw/source/filter/ww8/docxattributeoutput.cxx')
-rw-r--r-- | sw/source/filter/ww8/docxattributeoutput.cxx | 4172 |
1 files changed, 4172 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx new file mode 100644 index 000000000000..497f8bc4f07b --- /dev/null +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -0,0 +1,4172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "docxattributeoutput.hxx" +#include "docxexport.hxx" +#include "docxexportfilter.hxx" +#include "docxfootnotes.hxx" +#include "writerwordglue.hxx" +#include "wrtww8.hxx" +#include "ww8par.hxx" +#include "fmtcntnt.hxx" +#include "fmtsrnd.hxx" +#include "fchrfmt.hxx" +#include "tgrditem.hxx" +#include "fmtruby.hxx" +#include "charfmt.hxx" +#include "breakit.hxx" + +#include <oox/token/tokens.hxx> +#include <oox/export/drawingml.hxx> +#include <oox/export/utils.hxx> +#include <oox/export/vmlexport.hxx> + +#include <i18npool/mslangid.hxx> + +#include <hintids.hxx> + +#include <svl/poolitem.hxx> + +#include <editeng/fontitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/spltitem.hxx> +#include <editeng/widwitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/hyznitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/pbinitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/twolinesitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charrotateitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/paravertalignitem.hxx> +#include <editeng/pgrditem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/blnkitem.hxx> +#include <editeng/charhiddenitem.hxx> +#include <editeng/opaqitem.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdobj.hxx> + +#include <anchoredobject.hxx> +#include <docufld.hxx> +#include <flddropdown.hxx> +#include <format.hxx> +#include <fmtanchr.hxx> +#include <fmtclds.hxx> +#include <fmtinfmt.hxx> +#include <fmtfld.hxx> +#include <fmtfsize.hxx> +#include <fmtftn.hxx> +#include <fmtrowsplt.hxx> +#include <fmtline.hxx> +#include <frmfmt.hxx> +#include <frmatr.hxx> +#include <ftninfo.hxx> +#include <htmltbl.hxx> +#include <lineinfo.hxx> +#include <ndgrf.hxx> +#include <ndtxt.hxx> +#include <node.hxx> +#include <pagedesc.hxx> +#include <paratr.hxx> +#include <swmodule.hxx> +#include <swtable.hxx> +#include <txtftn.hxx> +#include <txtinet.hxx> +#include <numrule.hxx> + +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> + +#include <tools/color.hxx> + +#include <com/sun/star/i18n/ScriptType.hdl> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <IMark.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +using ::editeng::SvxBorderLine; +using rtl::OString; +using rtl::OStringBuffer; +using rtl::OUString; +using rtl::OUStringBuffer; +using rtl::OUStringToOString; + +using namespace oox; +using namespace docx; +using namespace sax_fastparser; +using namespace nsSwDocInfoSubType; +using namespace nsFieldFlags; +using namespace sw::util; +using namespace ::com::sun::star; + +class FFDataWriterHelper +{ + ::sax_fastparser::FSHelperPtr m_pSerializer; + void writeCommonStart( const rtl::OUString& rName ) + { + m_pSerializer->startElementNS( XML_w, XML_ffData, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_name, + FSNS( XML_w, XML_val ), OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr(), + FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_enabled, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_calcOnExit, + FSNS( XML_w, XML_val ), + "0", FSEND ); + } + void writeFinish() + { + m_pSerializer->endElementNS( XML_w, XML_ffData ); + } +public: + FFDataWriterHelper( const ::sax_fastparser::FSHelperPtr pSerializer ) : m_pSerializer( pSerializer ){} + void WriteFormCheckbox( const rtl::OUString& rName, const rtl::OUString& rDefault, bool bChecked ) + { + writeCommonStart( rName ); + // Checkbox specific bits + m_pSerializer->startElementNS( XML_w, XML_checkBox, FSEND ); + // currently hardcoding autosize + // #TODO check if this defaulted + m_pSerializer->startElementNS( XML_w, XML_sizeAuto, FSEND ); + m_pSerializer->endElementNS( XML_w, XML_sizeAuto ); + if ( rDefault.getLength() ) + { + m_pSerializer->singleElementNS( XML_w, XML_default, + FSNS( XML_w, XML_val ), + rtl::OUStringToOString( rDefault, RTL_TEXTENCODING_UTF8 ).getStr(), FSEND ); + } + if ( bChecked ) + m_pSerializer->singleElementNS( XML_w, XML_checked, FSEND ); + m_pSerializer->endElementNS( XML_w, XML_checkBox ); + writeFinish(); + } + void WriteFormText( const rtl::OUString& rName, const rtl::OUString& rDefault ) + { + writeCommonStart( rName ); + if ( rDefault.getLength() ) + { + m_pSerializer->startElementNS( XML_w, XML_textInput, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_default, + FSNS( XML_w, XML_val ), + rtl::OUStringToOString( rDefault, RTL_TEXTENCODING_UTF8 ).getStr(), FSEND ); + m_pSerializer->endElementNS( XML_w, XML_textInput ); + } + writeFinish(); + } +}; + +class FieldMarkParamsHelper +{ + const sw::mark::IFieldmark& mrFieldmark; + public: + FieldMarkParamsHelper( const sw::mark::IFieldmark& rFieldmark ) : mrFieldmark( rFieldmark ) {} + rtl::OUString getName() { return mrFieldmark.GetName(); } + template < typename T > + bool extractParam( const rtl::OUString& rKey, T& rResult ) + { + bool bResult = false; + if ( mrFieldmark.GetParameters() ) + { + sw::mark::IFieldmark::parameter_map_t::const_iterator it = mrFieldmark.GetParameters()->find( rKey ); + if ( it != mrFieldmark.GetParameters()->end() ) + bResult = ( it->second >>= rResult ); + } + return bResult; + } +}; +void DocxAttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 /*nScript*/ ) +{ + if (bIsRTL) + m_pSerializer->singleElementNS( XML_w, XML_rtl, FSNS( XML_w, XML_val ), "true", FSEND ); +} + +void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo ) +{ + if ( m_nColBreakStatus == COLBRK_POSTPONE ) + m_nColBreakStatus = COLBRK_WRITE; + + // Output table/table row/table cell starts if needed + if ( pTextNodeInfo.get() ) + { + sal_uInt32 nRow = pTextNodeInfo->getRow(); + sal_uInt32 nCell = pTextNodeInfo->getCell(); + + // New cell/row? + if ( m_nTableDepth > 0 && !m_bTableCellOpen ) + { + ww8::WW8TableNodeInfoInner::Pointer_t pDeepInner( pTextNodeInfo->getInnerForDepth( m_nTableDepth ) ); + if ( pDeepInner->getCell() == 0 ) + StartTableRow( pDeepInner ); + + StartTableCell( pDeepInner ); + } + + if ( nRow == 0 && nCell == 0 ) + { + // Do we have to start the table? + // [If we are at the rigth depth already, it means that we + // continue the table cell] + sal_uInt32 nCurrentDepth = pTextNodeInfo->getDepth(); + + if ( nCurrentDepth > m_nTableDepth ) + { + // Start all the tables that begin here + for ( sal_uInt32 nDepth = m_nTableDepth + 1; nDepth <= pTextNodeInfo->getDepth(); ++nDepth ) + { + ww8::WW8TableNodeInfoInner::Pointer_t pInner( pTextNodeInfo->getInnerForDepth( nDepth ) ); + + StartTable( pInner ); + StartTableRow( pInner ); + StartTableCell( pInner ); + } + + m_nTableDepth = nCurrentDepth; + } + } + } + + m_pSerializer->startElementNS( XML_w, XML_p, FSEND ); + + // postpone the output of the run (we get it before the paragraph + // properties, but must write it after them) + m_pSerializer->mark(); + + // no section break in this paragraph yet; can be set in SectionBreak() + m_pSectionInfo = NULL; + + m_bParagraphOpened = true; +} + +void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner ) +{ + // write the paragraph properties + the run, already in the correct order + m_pSerializer->mergeTopMarks(); + m_pSerializer->endElementNS( XML_w, XML_p ); + + // Check for end of cell, rows, tables here + FinishTableRowCell( pTextNodeInfoInner ); + + m_bParagraphOpened = false; + + // Write the anchored frame if any + if ( m_pParentFrame ) + { + const SwFrmFmt& rFrmFmt = m_pParentFrame->GetFrmFmt( ); + const SwNodeIndex* pNodeIndex = rFrmFmt.GetCntnt().GetCntntIdx(); + + sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex()+1 : 0; + sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0; + + m_rExport.SaveData( nStt, nEnd ); + + m_rExport.mpParentFrame = m_pParentFrame; + m_pParentFrame = NULL; + + m_rExport.WriteText( ); + + m_rExport.RestoreData(); + } +} + +void DocxAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointer_t pInner, bool bForceEmptyParagraph ) +{ + if ( pInner.get() ) + { + // Where are we in the table + sal_uInt32 nRow = pInner->getRow( ); + + const SwTable *pTable = pInner->getTable( ); + const SwTableLines& rLines = pTable->GetTabLines( ); + sal_uInt16 nLinesCount = rLines.Count( ); + // HACK + // msoffice seems to have an internal limitation of 63 columns for tables + // and refuses to load .docx with more, even though the spec seems to allow that; + // so simply if there are more columns, don't close the last one msoffice will handle + // and merge the contents of the remaining ones into it (since we don't close the cell + // here, following ones will not be opened) + bool limitWorkaround = ( pInner->getCell() >= 62 && !pInner->isEndOfLine()); + + if ( pInner->isEndOfCell() && !limitWorkaround ) + { + if ( bForceEmptyParagraph ) + m_pSerializer->singleElementNS( XML_w, XML_p, FSEND ); + + EndTableCell(); + } + + // This is a line end + if ( pInner->isEndOfLine() ) + EndTableRow(); + + // This is the end of the table + if ( pInner->isEndOfLine( ) && ( nRow + 1 ) == nLinesCount ) + EndTable(); + } +} + +void DocxAttributeOutput::EmptyParagraph() +{ + m_pSerializer->singleElementNS( XML_w, XML_p, FSEND ); +} + +void DocxAttributeOutput::StartParagraphProperties( const SwTxtNode& rNode ) +{ + // output page/section breaks + // Writer can have them at the beginning of a paragraph, or at the end, but + // in docx, we have to output them in the paragraph properties of the last + // paragraph in a section. To get it right, we have to switch to the next + // paragraph, and detect the section breaks there. + SwNodeIndex aNextIndex( rNode, 1 ); + if ( aNextIndex.GetNode().IsTxtNode() ) + { + const SwTxtNode* pTxtNode = static_cast< SwTxtNode* >( &aNextIndex.GetNode() ); + m_rExport.OutputSectionBreaks( pTxtNode->GetpSwAttrSet(), *pTxtNode ); + } + else if ( aNextIndex.GetNode().IsTableNode() ) + { + const SwTableNode* pTableNode = static_cast< SwTableNode* >( &aNextIndex.GetNode() ); + const SwFrmFmt *pFmt = pTableNode->GetTable().GetFrmFmt(); + m_rExport.OutputSectionBreaks( &(pFmt->GetAttrSet()), *pTableNode ); + } + + m_pSerializer->mark( ); + + m_pSerializer->startElementNS( XML_w, XML_pPr, FSEND ); + + // and output the section break now (if it appeared) + if ( m_pSectionInfo ) + { + m_rExport.SectionProperties( *m_pSectionInfo ); + m_pSectionInfo = NULL; + } + + InitCollectedParagraphProperties(); +} + +void DocxAttributeOutput::InitCollectedParagraphProperties() +{ + m_pParagraphSpacingAttrList = NULL; + + // Write the elements in the spec order + static const sal_Int32 aOrder[] = + { + FSNS( XML_w, XML_pStyle ), + FSNS( XML_w, XML_keepNext ), + FSNS( XML_w, XML_keepLines ), + FSNS( XML_w, XML_pageBreakBefore ), + FSNS( XML_w, XML_framePr ), + FSNS( XML_w, XML_widowControl ), + FSNS( XML_w, XML_numPr ), + FSNS( XML_w, XML_suppressLineNumbers ), + FSNS( XML_w, XML_pBdr ), + FSNS( XML_w, XML_shd ), + FSNS( XML_w, XML_tabs ), + FSNS( XML_w, XML_suppressAutoHyphens ), + FSNS( XML_w, XML_kinsoku ), + FSNS( XML_w, XML_wordWrap ), + FSNS( XML_w, XML_overflowPunct ), + FSNS( XML_w, XML_topLinePunct ), + FSNS( XML_w, XML_autoSpaceDE ), + FSNS( XML_w, XML_autoSpaceDN ), + FSNS( XML_w, XML_bidi ), + FSNS( XML_w, XML_adjustRightInd ), + FSNS( XML_w, XML_snapToGrid ), + FSNS( XML_w, XML_spacing ), + FSNS( XML_w, XML_ind ), + FSNS( XML_w, XML_contextualSpacing ), + FSNS( XML_w, XML_mirrorIndents ), + FSNS( XML_w, XML_suppressOverlap ), + FSNS( XML_w, XML_jc ), + FSNS( XML_w, XML_textDirection ), + FSNS( XML_w, XML_textAlignment ), + FSNS( XML_w, XML_textboxTightWrap ), + FSNS( XML_w, XML_outlineLvl ), + FSNS( XML_w, XML_divId ), + FSNS( XML_w, XML_cnfStyle ), + FSNS( XML_w, XML_rPr ), + FSNS( XML_w, XML_sectPr ), + FSNS( XML_w, XML_pPrChange ) + }; + + // postpone the output so that we can later [in EndParagraphProperties()] + // prepend the properties before the run + sal_Int32 len = sizeof ( aOrder ) / sizeof( sal_Int32 ); + uno::Sequence< sal_Int32 > aSeqOrder( len ); + for ( sal_Int32 i = 0; i < len; i++ ) + aSeqOrder[i] = aOrder[i]; + + m_pSerializer->mark( aSeqOrder ); +} + +void DocxAttributeOutput::WriteCollectedParagraphProperties() +{ + if ( m_pFlyAttrList ) + { + XFastAttributeListRef xAttrList( m_pFlyAttrList ); + m_pFlyAttrList = NULL; + + m_pSerializer->singleElementNS( XML_w, XML_framePr, xAttrList ); + } + + if ( m_pParagraphSpacingAttrList ) + { + XFastAttributeListRef xAttrList( m_pParagraphSpacingAttrList ); + m_pParagraphSpacingAttrList = NULL; + + m_pSerializer->singleElementNS( XML_w, XML_spacing, xAttrList ); + } + + // Merge the marks for the ordered elements + m_pSerializer->mergeTopMarks( ); +} + +void DocxAttributeOutput::EndParagraphProperties() +{ + WriteCollectedParagraphProperties(); + + m_pSerializer->endElementNS( XML_w, XML_pPr ); + + if ( m_nColBreakStatus == COLBRK_WRITE ) + { + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_br, + FSNS( XML_w, XML_type ), "column", FSEND ); + m_pSerializer->endElementNS( XML_w, XML_r ); + + m_nColBreakStatus = COLBRK_NONE; + } + + // merge the properties _before_ the run (strictly speaking, just + // after the start of the paragraph) + m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND ); +} + +void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData ) +{ + // if there is some redlining in the document, output it + StartRedline( pRedlineData ); + + // postpone the output of the start of a run (there are elements that need + // to be written before the start of the run, but we learn which they are + // _inside_ of the run) + m_pSerializer->mark(); // let's call it "postponed run start" + + // postpone the output of the text (we get it before the run properties, + // but must write it after them) + m_pSerializer->mark(); // let's call it "postponed text" +} + +void DocxAttributeOutput::EndRun() +{ + // Write field starts + for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin(); pIt != m_Fields.end(); ++pIt ) + { + // Add the fields starts for all but hyperlinks and TOCs + if ( pIt->bOpen && pIt->pField ) + { + StartField_Impl( *pIt ); + + // Remove the field from the stack if only the start has to be written + // Unknown fields sould be removed too + if ( !pIt->bClose || ( pIt->eType == ww::eUNKNOWN ) ) + { + m_Fields.erase( pIt ); + --pIt; + } + } + } + + // write the run properties + the text, already in the correct order + m_pSerializer->mergeTopMarks(); // merges with "postponed text", see above + + // level down, to be able to prepend the actual run start attribute (just + // before "postponed run start") + m_pSerializer->mark(); // let's call it "actual run start" + + // prepend the actual run start + if ( m_pHyperlinkAttrList ) + { + XFastAttributeListRef xAttrList ( m_pHyperlinkAttrList ); + + m_pSerializer->startElementNS( XML_w, XML_hyperlink, xAttrList ); + } + + // Write the hyperlink and toc fields starts + for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin(); pIt != m_Fields.end(); ++pIt ) + { + // Add the fields starts for hyperlinks, TOCs and index marks + if ( pIt->bOpen && !pIt->pField ) + { + StartField_Impl( *pIt, sal_True ); + + // Remove the field if no end needs to be written + if ( !pIt->bClose ) { + m_Fields.erase( pIt ); + --pIt; + } + } + } + + DoWriteBookmarks( ); + + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND ); // merges with "postponed run start", see above + + // write the run start + the run content + m_pSerializer->mergeTopMarks(); // merges the "actual run start" + + // append the actual run end + m_pSerializer->endElementNS( XML_w, XML_r ); + + if ( m_pHyperlinkAttrList ) + { + m_pSerializer->endElementNS( XML_w, XML_hyperlink ); + m_pHyperlinkAttrList = NULL; + } + + while ( m_Fields.begin() != m_Fields.end() ) + { + EndField_Impl( m_Fields.front( ) ); + m_Fields.erase( m_Fields.begin( ) ); + } + + // if there is some redlining in the document, output it + EndRedline(); +} + +void DocxAttributeOutput::DoWriteBookmarks() +{ + // Write the start bookmarks + for ( std::vector< OString >::const_iterator it = m_rMarksStart.begin(), end = m_rMarksStart.end(); + it < end; ++it ) + { + const OString& rName = *it; + + // Output the bookmark + sal_uInt16 nId = m_nNextMarkId++; + m_rOpenedMarksIds[rName] = nId; + m_pSerializer->singleElementNS( XML_w, XML_bookmarkStart, + FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( nId ) ).getStr( ), + FSNS( XML_w, XML_name ), rName.getStr(), + FSEND ); + } + m_rMarksStart.clear(); + + // export the end bookmarks + for ( std::vector< OString >::const_iterator it = m_rMarksEnd.begin(), end = m_rMarksEnd.end(); + it < end; ++it ) + { + const OString& rName = *it; + + // Get the id of the bookmark + std::map< OString, sal_uInt16 >::iterator pPos = m_rOpenedMarksIds.find( rName ); + if ( pPos != m_rOpenedMarksIds.end( ) ) + { + sal_uInt16 nId = ( *pPos ).second; + m_pSerializer->singleElementNS( XML_w, XML_bookmarkEnd, + FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( nId ) ).getStr( ), + FSEND ); + m_rOpenedMarksIds.erase( rName ); + } + } + m_rMarksEnd.clear(); +} + +void DocxAttributeOutput::WriteFFData( const FieldInfos& rInfos ) +{ + const ::sw::mark::IFieldmark& rFieldmark = *rInfos.pFieldmark; + if ( rInfos.eType == ww::eFORMDROPDOWN ) + { + uno::Sequence< ::rtl::OUString> vListEntries; + rtl::OUString sName, sHelp, sToolTip, sSelected; + + FieldMarkParamsHelper params( rFieldmark ); + params.extractParam( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODF_FORMDROPDOWN_LISTENTRY) ), vListEntries ); + sName = params.getName(); + sal_Int32 nSelectedIndex = 0; + + if ( params.extractParam( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODF_FORMDROPDOWN_RESULT) ), nSelectedIndex ) ) + { + if (nSelectedIndex < vListEntries.getLength() ) + sSelected = vListEntries[ nSelectedIndex ]; + } + + GetExport().DoComboBox( sName, sHelp, sToolTip, sSelected, vListEntries ); + } + else if ( rInfos.eType == ww::eFORMCHECKBOX ) + { + rtl::OUString sName, sDefault; + bool bChecked = false; + + FieldMarkParamsHelper params( rFieldmark ); + params.extractParam( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( ODF_FORMCHECKBOX_NAME ) ), sName ); + + const sw::mark::ICheckboxFieldmark* pCheckboxFm = dynamic_cast<const sw::mark::ICheckboxFieldmark*>(&rFieldmark); + if ( pCheckboxFm && pCheckboxFm->IsChecked() ) + bChecked = true; + + FFDataWriterHelper ffdataOut( m_pSerializer ); + ffdataOut.WriteFormCheckbox( sName, rtl::OUString(), bChecked ); + } + else if ( rInfos.eType == ww::eFORMTEXT ) + { + FieldMarkParamsHelper params( rFieldmark ); + FFDataWriterHelper ffdataOut( m_pSerializer ); + ffdataOut.WriteFormText( params.getName(), rtl::OUString() ); + } +} + +void DocxAttributeOutput::StartField_Impl( FieldInfos& rInfos, sal_Bool bWriteRun ) +{ + if ( rInfos.pField && rInfos.eType == ww::eUNKNOWN ) + { + // Expand unsupported fields + RunText( rInfos.pField->GetFieldName() ); + } + else if ( rInfos.eType != ww::eNONE ) // HYPERLINK fields are just commands + { + if ( bWriteRun ) + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + + if ( rInfos.eType == ww::eFORMDROPDOWN ) + { + m_pSerializer->startElementNS( XML_w, XML_fldChar, + FSNS( XML_w, XML_fldCharType ), "begin", + FSEND ); + if ( rInfos.pFieldmark && !rInfos.pField ) + WriteFFData( rInfos ); + if ( rInfos.pField ) + { + const SwDropDownField& rFld2 = *(SwDropDownField*)rInfos.pField; + uno::Sequence<rtl::OUString> aItems = + rFld2.GetItemSequence(); + GetExport().DoComboBox(rFld2.GetName(), + rFld2.GetHelp(), + rFld2.GetToolTip(), + rFld2.GetSelectedItem(), aItems); + } + m_pSerializer->endElementNS( XML_w, XML_fldChar ); + + if ( bWriteRun ) + m_pSerializer->endElementNS( XML_w, XML_r ); + if ( !rInfos.pField ) + CmdField_Impl( rInfos ); + + } + else + { + // Write the field start + m_pSerializer->startElementNS( XML_w, XML_fldChar, + FSNS( XML_w, XML_fldCharType ), "begin", + FSEND ); + + if ( rInfos.pFieldmark ) + WriteFFData( rInfos ); + + m_pSerializer->endElementNS( XML_w, XML_fldChar ); + + if ( bWriteRun ) + m_pSerializer->endElementNS( XML_w, XML_r ); + + // The hyperlinks fields can't be expanded: the value is + // normally in the text run + if ( !rInfos.pField ) + CmdField_Impl( rInfos ); + } + } +} + +void DocxAttributeOutput::DoWriteCmd( String& rCmd ) +{ + // Write the Field command + m_pSerializer->startElementNS( XML_w, XML_instrText, FSEND ); + m_pSerializer->writeEscaped( OUString( rCmd ) ); + m_pSerializer->endElementNS( XML_w, XML_instrText ); + +} + +void DocxAttributeOutput::CmdField_Impl( FieldInfos& rInfos ) +{ + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + xub_StrLen nNbToken = rInfos.sCmd.GetTokenCount( '\t' ); + + for ( xub_StrLen i = 0; i < nNbToken; i++ ) + { + String sToken = rInfos.sCmd.GetToken( i, '\t' ); + // Write the Field command + DoWriteCmd( sToken ); + + // Replace tabs by </instrText><tab/><instrText> + if ( i < ( nNbToken - 1 ) ) + RunText( String::CreateFromAscii( "\t" ) ); + } + + m_pSerializer->endElementNS( XML_w, XML_r ); + + // Write the Field separator + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_fldChar, + FSNS( XML_w, XML_fldCharType ), "separate", + FSEND ); + m_pSerializer->endElementNS( XML_w, XML_r ); +} + +void DocxAttributeOutput::EndField_Impl( FieldInfos& rInfos ) +{ + // The command has to be written before for the hyperlinks + if ( rInfos.pField ) + { + CmdField_Impl( rInfos ); + } + + // Write the bookmark start if any + OUString aBkmName( m_sFieldBkm ); + if ( aBkmName.getLength( ) > 0 ) + { + m_pSerializer->singleElementNS( XML_w, XML_bookmarkStart, + FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( m_nNextMarkId ) ).getStr( ), + FSNS( XML_w, XML_name ), OUStringToOString( aBkmName, RTL_TEXTENCODING_UTF8 ).getStr( ), + FSEND ); + } + + if (rInfos.pField ) // For hyperlinks and TOX + { + // Write the Field latest value + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + + // Find another way for hyperlinks + RunText( rInfos.pField->GetFieldName() ); + m_pSerializer->endElementNS( XML_w, XML_r ); + } + + // Write the bookmark end if any + if ( aBkmName.getLength( ) > 0 ) + { + m_pSerializer->singleElementNS( XML_w, XML_bookmarkEnd, + FSNS( XML_w, XML_id ), OString::valueOf( sal_Int32( m_nNextMarkId ) ).getStr( ), + FSEND ); + + m_nNextMarkId++; + } + + // Write the Field end + if ( rInfos.bClose ) + { + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_fldChar, + FSNS( XML_w, XML_fldCharType ), "end", + FSEND ); + m_pSerializer->endElementNS( XML_w, XML_r ); + } + // Write the ref field if a bookmark had to be set and the field + // should be visible + if ( rInfos.pField ) + { + sal_uInt16 nSubType = rInfos.pField->GetSubType( ); + bool bIsSetField = rInfos.pField->GetTyp( )->Which( ) == RES_SETEXPFLD; + bool bShowRef = ( !bIsSetField || ( nSubType & nsSwExtendedSubType::SUB_INVISIBLE ) ) ? false : true; + + if ( ( m_sFieldBkm.Len( ) > 0 ) && bShowRef ) + { + // Write the field beginning + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_fldChar, + FSNS( XML_w, XML_fldCharType ), "begin", + FSEND ); + m_pSerializer->endElementNS( XML_w, XML_r ); + + rInfos.sCmd = FieldString( ww::eREF ); + rInfos.sCmd.APPEND_CONST_ASC( "\"" ); + rInfos.sCmd += m_sFieldBkm; + rInfos.sCmd.APPEND_CONST_ASC( "\" " ); + + // Clean the field bookmark data to avoid infinite loop + m_sFieldBkm = String( ); + + // Write the end of the field + EndField_Impl( rInfos ); + } + } +} + +void DocxAttributeOutput::StartRunProperties() +{ + // postpone the output so that we can later [in EndRunProperties()] + // prepend the properties before the text + m_pSerializer->mark(); + + m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND ); + + InitCollectedRunProperties(); +} + +void DocxAttributeOutput::InitCollectedRunProperties() +{ + m_pFontsAttrList = NULL; + m_pEastAsianLayoutAttrList = NULL; + m_pCharLangAttrList = NULL; + + // Write the elements in the spec order + static const sal_Int32 aOrder[] = + { + FSNS( XML_w, XML_rStyle ), + FSNS( XML_w, XML_rFonts ), + FSNS( XML_w, XML_b ), + FSNS( XML_w, XML_bCs ), + FSNS( XML_w, XML_i ), + FSNS( XML_w, XML_iCs ), + FSNS( XML_w, XML_caps ), + FSNS( XML_w, XML_smallCaps ), + FSNS( XML_w, XML_strike ), + FSNS( XML_w, XML_dstrike ), + FSNS( XML_w, XML_outline ), + FSNS( XML_w, XML_shadow ), + FSNS( XML_w, XML_emboss ), + FSNS( XML_w, XML_imprint ), + FSNS( XML_w, XML_noProof ), + FSNS( XML_w, XML_snapToGrid ), + FSNS( XML_w, XML_vanish ), + FSNS( XML_w, XML_webHidden ), + FSNS( XML_w, XML_color ), + FSNS( XML_w, XML_spacing ), + FSNS( XML_w, XML_w ), + FSNS( XML_w, XML_kern ), + FSNS( XML_w, XML_position ), + FSNS( XML_w, XML_sz ), + FSNS( XML_w, XML_szCs ), + FSNS( XML_w, XML_highlight ), + FSNS( XML_w, XML_u ), + FSNS( XML_w, XML_effect ), + FSNS( XML_w, XML_bdr ), + FSNS( XML_w, XML_shd ), + FSNS( XML_w, XML_fitText ), + FSNS( XML_w, XML_vertAlign ), + FSNS( XML_w, XML_rtl ), + FSNS( XML_w, XML_cs ), + FSNS( XML_w, XML_em ), + FSNS( XML_w, XML_lang ), + FSNS( XML_w, XML_eastAsianLayout ), + FSNS( XML_w, XML_specVanish ), + FSNS( XML_w, XML_oMath ), + FSNS( XML_w, XML_rPrChange ) + }; + + // postpone the output so that we can later [in EndParagraphProperties()] + // prepend the properties before the run + sal_Int32 len = sizeof ( aOrder ) / sizeof( sal_Int32 ); + uno::Sequence< sal_Int32 > aSeqOrder( len ); + for ( sal_Int32 i = 0; i < len; i++ ) + aSeqOrder[i] = aOrder[i]; + + m_pSerializer->mark( aSeqOrder ); + +} + +void DocxAttributeOutput::WriteCollectedRunProperties() +{ + // Write all differed properties + if ( m_pFontsAttrList ) + { + XFastAttributeListRef xAttrList( m_pFontsAttrList ); + m_pFontsAttrList = NULL; + + m_pSerializer->singleElementNS( XML_w, XML_rFonts, xAttrList ); + } + + if ( m_pEastAsianLayoutAttrList ) + { + XFastAttributeListRef xAttrList( m_pEastAsianLayoutAttrList ); + m_pEastAsianLayoutAttrList = NULL; + + m_pSerializer->singleElementNS( XML_w, XML_eastAsianLayout, xAttrList ); + } + + if ( m_pCharLangAttrList ) + { + XFastAttributeListRef xAttrList( m_pCharLangAttrList ); + m_pCharLangAttrList = NULL; + + m_pSerializer->singleElementNS( XML_w, XML_lang, xAttrList ); + } + + // Merge the marks for the ordered elements + m_pSerializer->mergeTopMarks(); +} + +void DocxAttributeOutput::EndRunProperties( const SwRedlineData* /*pRedlineData*/ ) +{ + WriteCollectedRunProperties(); + + m_pSerializer->endElementNS( XML_w, XML_rPr ); + + // write footnotes/endnotes if we have any + FootnoteEndnoteReference(); + + // merge the properties _before_ the run text (strictly speaking, just + // after the start of the run) + m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND ); +} + +void DocxAttributeOutput::FootnoteEndnoteRefTag() +{ + if( m_footnoteEndnoteRefTag == 0 ) + return; + m_pSerializer->singleElementNS( XML_w, m_footnoteEndnoteRefTag, FSEND ); + m_footnoteEndnoteRefTag = 0; +} + +/** Output sal_Unicode* as a run text (<t>the text</t>). + + When bMove is true, update rBegin to point _after_ the end of the text + + 1, meaning that it skips one character after the text. This is to make + the switch in DocxAttributeOutput::RunText() nicer ;-) + */ +static void impl_WriteRunText( FSHelperPtr pSerializer, sal_Int32 nTextToken, + const sal_Unicode* &rBegin, const sal_Unicode* pEnd, bool bMove = true ) +{ + const sal_Unicode *pBegin = rBegin; + + // skip one character after the end + if ( bMove ) + rBegin = pEnd + 1; + + if ( pBegin >= pEnd ) + return; // we want to write at least one character + + // we have to add 'preserve' when starting/ending with space + if ( *pBegin == sal_Unicode( ' ' ) || *( pEnd - 1 ) == sal_Unicode( ' ' ) ) + { + pSerializer->startElementNS( XML_w, nTextToken, FSNS( XML_xml, XML_space ), "preserve", FSEND ); + } + else + pSerializer->startElementNS( XML_w, nTextToken, FSEND ); + + pSerializer->writeEscaped( OUString( pBegin, pEnd - pBegin ) ); + + pSerializer->endElementNS( XML_w, nTextToken ); +} + +void DocxAttributeOutput::RunText( const String& rText, rtl_TextEncoding /*eCharSet*/ ) +{ + OUString aText( rText ); + + // one text can be split into more <w:t>blah</w:t>'s by line breaks etc. + const sal_Unicode *pBegin = aText.getStr(); + const sal_Unicode *pEnd = pBegin + aText.getLength(); + + // the text run is usually XML_t, with the exception of the deleted text + sal_Int32 nTextToken = XML_t; + if ( m_pRedlineData && m_pRedlineData->GetType() == nsRedlineType_t::REDLINE_DELETE ) + nTextToken = XML_delText; + + for ( const sal_Unicode *pIt = pBegin; pIt < pEnd; ++pIt ) + { + switch ( *pIt ) + { + case 0x09: // tab + impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pIt ); + m_pSerializer->singleElementNS( XML_w, XML_tab, FSEND ); + break; + case 0x0b: // line break + impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pIt ); + m_pSerializer->singleElementNS( XML_w, XML_br, FSEND ); + break; + default: + if ( *pIt < 0x0020 ) // filter out the control codes + { + impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pIt ); + OSL_TRACE( "Ignored control code %x in a text run.", *pIt ); + } + break; + } + } + + impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pEnd, false ); +} + +void DocxAttributeOutput::RawText( const String& /*rText*/, bool /*bForceUnicode*/, rtl_TextEncoding /*eCharSet*/ ) +{ + OSL_TRACE("TODO DocxAttributeOutput::RawText( const String& rText, bool bForceUnicode, rtl_TextEncoding eCharSet )\n" ); +} + +void DocxAttributeOutput::StartRuby( const SwTxtNode& rNode, xub_StrLen nPos, const SwFmtRuby& rRuby ) +{ + OSL_TRACE("TODO DocxAttributeOutput::StartRuby( const SwTxtNode& rNode, const SwFmtRuby& rRuby )\n" ); + m_pSerializer->startElementNS( XML_w, XML_ruby, FSEND ); + m_pSerializer->startElementNS( XML_w, XML_rubyPr, FSEND ); + // hps + // hpsBaseText + // hpsRaise + // lid + lang::Locale aLocale( SwBreakIt::Get()->GetLocale( + rNode.GetLang( nPos ) ) ); + OUString sLang( aLocale.Language ); + if ( aLocale.Country.getLength( ) > 0 ) + sLang += OUString(RTL_CONSTASCII_USTRINGPARAM( "-" )) + OUString( aLocale.Country ); + m_pSerializer->singleElementNS( XML_w, XML_lid, + FSNS( XML_w, XML_val ), + OUStringToOString( sLang, RTL_TEXTENCODING_UTF8 ).getStr( ), FSEND ); + + OString sAlign ( "center" ); + switch ( rRuby.GetAdjustment( ) ) + { + case 0: + sAlign = OString( "left" ); + break; + case 1: + // Defaults to center + break; + case 2: + sAlign = OString( "right" ); + break; + case 3: + sAlign = OString( "distributeLetter" ); + break; + case 4: + sAlign = OString( "distributeSpace" ); + break; + default: + break; + } + m_pSerializer->singleElementNS( XML_w, XML_rubyAlign, + FSNS( XML_w, XML_val ), sAlign.getStr(), FSEND ); + m_pSerializer->endElementNS( XML_w, XML_rubyPr ); + + m_pSerializer->startElementNS( XML_w, XML_rt, FSEND ); + StartRun( NULL ); + StartRunProperties( ); + SwWW8AttrIter aAttrIt( m_rExport, rNode ); + aAttrIt.OutAttr( nPos, true ); + sal_uInt16 nStyle = m_rExport.GetId( *rRuby.GetTxtRuby()->GetCharFmt() ); + OString aStyleId( "style" ); + aStyleId += OString::valueOf( sal_Int32( nStyle ) ); + m_pSerializer->singleElementNS( XML_w, XML_rStyle, + FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND ); + EndRunProperties( NULL ); + RunText( rRuby.GetText( ) ); + EndRun( ); + m_pSerializer->endElementNS( XML_w, XML_rt ); + + m_pSerializer->startElementNS( XML_w, XML_rubyBase, FSEND ); + StartRun( NULL ); +} + +void DocxAttributeOutput::EndRuby() +{ + OSL_TRACE( "TODO DocxAttributeOutput::EndRuby()\n" ); + EndRun( ); + m_pSerializer->endElementNS( XML_w, XML_rubyBase ); + m_pSerializer->endElementNS( XML_w, XML_ruby ); +} + +bool DocxAttributeOutput::AnalyzeURL( const String& rUrl, const String& rTarget, String* pLinkURL, String* pMark ) +{ + bool bBookMarkOnly = AttributeOutputBase::AnalyzeURL( rUrl, rTarget, pLinkURL, pMark ); + + String sURL = *pLinkURL; + String sMark = *pMark; + + bool bOutputField = sMark.Len(); + + if ( bOutputField ) + { + if ( bBookMarkOnly ) + sURL = FieldString( ww::eHYPERLINK ); + else + { + String sFld( FieldString( ww::eHYPERLINK ) ); + sFld.APPEND_CONST_ASC( "\"" ); + sURL.Insert( sFld, 0 ); + sURL += '\"'; + } + + if ( sMark.Len() ) + ( ( sURL.APPEND_CONST_ASC( " \\l \"" ) ) += sMark ) += '\"'; + + if ( rTarget.Len() ) + ( sURL.APPEND_CONST_ASC( " \\n " ) ) += rTarget; + } + + *pLinkURL = sURL; + *pMark = sMark; + + return bBookMarkOnly; +} + +bool DocxAttributeOutput::StartURL( const String& rUrl, const String& rTarget ) +{ + String sMark; + String sUrl; + + bool bBookmarkOnly = AnalyzeURL( rUrl, rTarget, &sUrl, &sMark ); + + if ( sMark.Len() && !bBookmarkOnly ) + { + m_rExport.OutputField( NULL, ww::eHYPERLINK, sUrl ); + } + else + { + // Output a hyperlink XML element + + m_pHyperlinkAttrList = m_pSerializer->createAttrList(); + if ( !bBookmarkOnly ) + { + OUString osUrl( sUrl ); + + ::rtl::OString sId = m_rExport.AddRelation( + S( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ), + osUrl, S("External") ); + m_pHyperlinkAttrList->add( FSNS( XML_r, XML_id), sId.getStr()); + } + else + m_pHyperlinkAttrList->add( FSNS( XML_w, XML_anchor ), + OUStringToOString( OUString( sMark ), RTL_TEXTENCODING_UTF8 ).getStr( ) ); + + OUString sTarget( rTarget ); + if ( sTarget.getLength( ) > 0 ) + { + OString soTarget = OUStringToOString( sTarget, RTL_TEXTENCODING_UTF8 ); + m_pHyperlinkAttrList->add(FSNS( XML_w, XML_tgtFrame ), soTarget.getStr()); + } + } + + return true; +} + +bool DocxAttributeOutput::EndURL() +{ + return true; +} + +void DocxAttributeOutput::FieldVanish( const String& rTxt, ww::eField eType ) +{ + WriteField_Impl( NULL, eType, rTxt, WRITEFIELD_ALL ); +} + +void DocxAttributeOutput::Redline( const SwRedlineData* /*pRedline*/ ) +{ + OSL_TRACE( "TODO DocxAttributeOutput::Redline( const SwRedlineData* pRedline )\n" ); +} + +/// Append the number as 2-digit when less than 10. +static void impl_AppendTwoDigits( OStringBuffer &rBuffer, sal_Int32 nNum ) +{ + if ( nNum < 0 || nNum > 99 ) + { + rBuffer.append( "00" ); + return; + } + + if ( nNum < 10 ) + rBuffer.append( '0' ); + + rBuffer.append( nNum ); +} + +/** Convert DateTime to xsd::dateTime string. + +I guess there must be an implementation of this somewhere in OOo, but I failed +to find it, unfortunately :-( +*/ +static OString impl_DateTimeToOString( const DateTime& rDateTime ) +{ + DateTime aInUTC( rDateTime ); + aInUTC.ConvertToUTC(); + + OStringBuffer aBuffer( 25 ); + aBuffer.append( sal_Int32( aInUTC.GetYear() ) ); + aBuffer.append( '-' ); + + impl_AppendTwoDigits( aBuffer, aInUTC.GetMonth() ); + aBuffer.append( '-' ); + + impl_AppendTwoDigits( aBuffer, aInUTC.GetDay() ); + aBuffer.append( 'T' ); + + impl_AppendTwoDigits( aBuffer, aInUTC.GetHour() ); + aBuffer.append( ':' ); + + impl_AppendTwoDigits( aBuffer, aInUTC.GetMin() ); + aBuffer.append( ':' ); + + impl_AppendTwoDigits( aBuffer, aInUTC.GetSec() ); + aBuffer.append( 'Z' ); // we are in UTC + + return aBuffer.makeStringAndClear(); +} + +void DocxAttributeOutput::StartRedline( const SwRedlineData* pRedlineData ) +{ + m_pRedlineData = pRedlineData; + + if ( !m_pRedlineData ) + return; + + // FIXME check if it's necessary to travel over the Next()'s in pRedlineData + + OString aId( OString::valueOf( m_nRedlineId++ ) ); + + const String &rAuthor( SW_MOD()->GetRedlineAuthor( pRedlineData->GetAuthor() ) ); + OString aAuthor( OUStringToOString( rAuthor, RTL_TEXTENCODING_UTF8 ) ); + + OString aDate( impl_DateTimeToOString( pRedlineData->GetTimeStamp() ) ); + + switch ( pRedlineData->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + m_pSerializer->startElementNS( XML_w, XML_ins, + FSNS( XML_w, XML_id ), aId.getStr(), + FSNS( XML_w, XML_author ), aAuthor.getStr(), + FSNS( XML_w, XML_date ), aDate.getStr(), + FSEND ); + break; + + case nsRedlineType_t::REDLINE_DELETE: + m_pSerializer->startElementNS( XML_w, XML_del, + FSNS( XML_w, XML_id ), aId.getStr(), + FSNS( XML_w, XML_author ), aAuthor.getStr(), + FSNS( XML_w, XML_date ), aDate.getStr(), + FSEND ); + break; + + case nsRedlineType_t::REDLINE_FORMAT: + OSL_TRACE( "TODO DocxAttributeOutput::StartRedline()\n" ); + default: + break; + } +} + +void DocxAttributeOutput::EndRedline() +{ + if ( !m_pRedlineData ) + return; + + switch ( m_pRedlineData->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + m_pSerializer->endElementNS( XML_w, XML_ins ); + break; + + case nsRedlineType_t::REDLINE_DELETE: + m_pSerializer->endElementNS( XML_w, XML_del ); + break; + + case nsRedlineType_t::REDLINE_FORMAT: + OSL_TRACE( "TODO DocxAttributeOutput::EndRedline()\n" ); + break; + default: + break; + } + + m_pRedlineData = NULL; +} + +void DocxAttributeOutput::FormatDrop( const SwTxtNode& /*rNode*/, const SwFmtDrop& /*rSwFmtDrop*/, sal_uInt16 /*nStyle*/, ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/, ww8::WW8TableNodeInfoInner::Pointer_t ) +{ + OSL_TRACE( "TODO DocxAttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop& rSwFmtDrop, sal_uInt16 nStyle )\n" ); +} + +void DocxAttributeOutput::ParagraphStyle( sal_uInt16 nStyle ) +{ + OString aStyleId( "style" ); + aStyleId += OString::valueOf( sal_Int32( nStyle ) ); + + m_pSerializer->singleElementNS( XML_w, XML_pStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND ); +} + +static OString impl_ConvertColor( const Color &rColor ) +{ + OString color( "auto" ); + if ( rColor.GetColor() != COL_AUTO ) + { + const char pHexDigits[] = "0123456789ABCDEF"; + char pBuffer[] = "000000"; + + pBuffer[0] = pHexDigits[ ( rColor.GetRed() >> 4 ) & 0x0F ]; + pBuffer[1] = pHexDigits[ rColor.GetRed() & 0x0F ]; + pBuffer[2] = pHexDigits[ ( rColor.GetGreen() >> 4 ) & 0x0F ]; + pBuffer[3] = pHexDigits[ rColor.GetGreen() & 0x0F ]; + pBuffer[4] = pHexDigits[ ( rColor.GetBlue() >> 4 ) & 0x0F ]; + pBuffer[5] = pHexDigits[ rColor.GetBlue() & 0x0F ]; + + color = OString( pBuffer ); + } + return color; +} + +static void impl_borderLine( FSHelperPtr pSerializer, sal_Int32 elementToken, const SvxBorderLine* pBorderLine, sal_uInt16 nDist ) +{ + FastAttributeList* pAttr = pSerializer->createAttrList(); + + + // Compute val attribute value + // Can be one of: + // single, double, + // basicWideOutline, basicWideInline + // OOXml also supports those types of borders, but we'll try to play with the first ones. + // thickThinMediumGap, thickThinLargeGap, thickThinSmallGap + // thinThickLargeGap, thinThickMediumGap, thinThickSmallGap + const char* pVal = "none"; + if ( !pBorderLine->isEmpty( ) ) + { + switch ( pBorderLine->GetStyle( ) ) + { + case ::editeng::SOLID: + pVal = ( sal_Char* )"single"; + break; + case ::editeng::DOTTED: + pVal = ( sal_Char* )"dotted"; + break; + case ::editeng::DASHED: + pVal = ( sal_Char* )"dashed"; + break; + case ::editeng::DOUBLE: + pVal = ( sal_Char* )"double"; + break; + case ::editeng::THINTHICK_SMALLGAP: + pVal = ( sal_Char* )"thinThickSmallGap"; + break; + case ::editeng::THINTHICK_MEDIUMGAP: + pVal = ( sal_Char* )"thinThickMediumGap"; + break; + case ::editeng::THINTHICK_LARGEGAP: + pVal = ( sal_Char* )"thinThickLargeGap"; + break; + case ::editeng::THICKTHIN_SMALLGAP: + pVal = ( sal_Char* )"thickThinSmallGap"; + break; + case ::editeng::THICKTHIN_MEDIUMGAP: + pVal = ( sal_Char* )"thickThinMediumGap"; + break; + case ::editeng::THICKTHIN_LARGEGAP: + pVal = ( sal_Char* )"thickThinLargeGap"; + break; + case ::editeng::EMBOSSED: + pVal = ( sal_Char* )"threeDEmboss"; + break; + case ::editeng::ENGRAVED: + pVal = ( sal_Char* )"threeDEngrave"; + break; + case ::editeng::OUTSET: + pVal = ( sal_Char* )"outset"; + break; + case ::editeng::INSET: + pVal = ( sal_Char* )"inset"; + break; + case ::editeng::NO_STYLE: + default: + break; + } + } + + pAttr->add( FSNS( XML_w, XML_val ), OString( pVal ) ); + + if ( !pBorderLine->isEmpty() ) + { + // Compute the sz attribute + + // The unit is the 8th of point + sal_Int32 nWidth = sal_Int32( pBorderLine->GetWidth() / 2.5 ); + sal_uInt16 nMinWidth = 2; + sal_uInt16 nMaxWidth = 96; + + if ( nWidth > nMaxWidth ) + nWidth = nMaxWidth; + else if ( nWidth < nMinWidth ) + nWidth = nMinWidth; + + pAttr->add( FSNS( XML_w, XML_sz ), OString::valueOf( sal_Int32( nWidth ) ) ); + + // Get the distance (in pt) + pAttr->add( FSNS( XML_w, XML_space ), OString::valueOf( sal_Int32( nDist / 20 ) ) ); + + // Get the color code as an RRGGBB hex value + OString sColor( impl_ConvertColor( pBorderLine->GetColor( ) ) ); + pAttr->add( FSNS( XML_w, XML_color ), sColor ); + } + + XFastAttributeListRef xAttrs( pAttr ); + pSerializer->singleElementNS( XML_w, elementToken, xAttrs ); +} + +static void impl_pageBorders( FSHelperPtr pSerializer, const SvxBoxItem& rBox, bool bUseStartEnd = false ) +{ + static const sal_uInt16 aBorders[] = + { + BOX_LINE_TOP, BOX_LINE_LEFT, BOX_LINE_BOTTOM, BOX_LINE_RIGHT + }; + + const sal_Int32 aXmlElements[] = + { + XML_top, + bUseStartEnd ? XML_start : XML_left, + XML_bottom, + bUseStartEnd ? XML_end : XML_right + }; + const sal_uInt16* pBrd = aBorders; + for( int i = 0; i < 4; ++i, ++pBrd ) + { + const SvxBorderLine* pLn = rBox.GetLine( *pBrd ); + if ( pLn ) + impl_borderLine( pSerializer, aXmlElements[i], pLn, 0 ); + } +} + +void DocxAttributeOutput::TableCellProperties( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + m_pSerializer->startElementNS( XML_w, XML_tcPr, FSEND ); + + const SwTableBox *pTblBox = pTableTextNodeInfoInner->getTableBox( ); + + bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT; + + // Cell prefered width + SwTwips nWidth = GetGridCols( pTableTextNodeInfoInner )->at( pTableTextNodeInfoInner->getCell() ); + if ( pTableTextNodeInfoInner->getCell() ) + nWidth = nWidth - GetGridCols( pTableTextNodeInfoInner )->at( pTableTextNodeInfoInner->getCell() - 1 ); + m_pSerializer->singleElementNS( XML_w, XML_tcW, + FSNS( XML_w, XML_w ), OString::valueOf( sal_Int32( nWidth ) ).getStr( ), + FSNS( XML_w, XML_type ), "dxa", + FSEND ); + + // Horizontal spans + const SwWriteTableRows& aRows = m_pTableWrt->GetRows( ); + SwWriteTableRow *pRow = aRows[ pTableTextNodeInfoInner->getRow( ) ]; + SwWriteTableCell *pCell = pRow->GetCells( )[ pTableTextNodeInfoInner->getCell( ) ]; + + sal_uInt16 nColSpan = pCell->GetColSpan(); + if ( nColSpan > 1 ) + m_pSerializer->singleElementNS( XML_w, XML_gridSpan, + FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nColSpan ) ).getStr(), + FSEND ); + + // Vertical merges + long vSpan = pTblBox->getRowSpan( ); + if ( vSpan > 1 ) + { + m_pSerializer->singleElementNS( XML_w, XML_vMerge, + FSNS( XML_w, XML_val ), "restart", + FSEND ); + } + else if ( vSpan < 0 ) + { + m_pSerializer->singleElementNS( XML_w, XML_vMerge, + FSNS( XML_w, XML_val ), "continue", + FSEND ); + } + + // The cell borders + m_pSerializer->startElementNS( XML_w, XML_tcBorders, FSEND ); + SwFrmFmt *pFmt = pTblBox->GetFrmFmt( ); + impl_pageBorders( m_pSerializer, pFmt->GetBox( ), !bEcma ); + m_pSerializer->endElementNS( XML_w, XML_tcBorders ); + + TableBackgrounds( pTableTextNodeInfoInner ); + + // Cell margins + m_pSerializer->startElementNS( XML_w, XML_tcMar, FSEND ); + const SvxBoxItem& rBox = pFmt->GetBox( ); + static const sal_uInt16 aBorders[] = + { + BOX_LINE_TOP, BOX_LINE_LEFT, BOX_LINE_BOTTOM, BOX_LINE_RIGHT + }; + + const sal_Int32 aXmlElements[] = + { + XML_top, + bEcma ? XML_left : XML_start, + XML_bottom, + bEcma ? XML_right : XML_end + }; + const sal_uInt16* pBrd = aBorders; + for( int i = 0; i < 4; ++i, ++pBrd ) + { + sal_Int32 nDist = sal_Int32( rBox.GetDistance( *pBrd ) ); + m_pSerializer->singleElementNS( XML_w, aXmlElements[i], + FSNS( XML_w, XML_w ), OString::valueOf( nDist ).getStr( ), + FSNS( XML_w, XML_type ), "dxa", + FSEND ); + } + + m_pSerializer->endElementNS( XML_w, XML_tcMar ); + + TableVerticalCell( pTableTextNodeInfoInner ); + + m_pSerializer->endElementNS( XML_w, XML_tcPr ); +} + +void DocxAttributeOutput::InitTableHelper( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + sal_uInt32 nPageSize = 0; + bool bRelBoxSize = false; + + // Create the SwWriteTable instance to use col spans (and maybe other infos) + GetTablePageSize( pTableTextNodeInfoInner.get(), nPageSize, bRelBoxSize ); + + const SwTable* pTable = pTableTextNodeInfoInner->getTable( ); + const SwFrmFmt *pFmt = pTable->GetFrmFmt( ); + SwTwips nTblSz = pFmt->GetFrmSize( ).GetWidth( ); + + const SwHTMLTableLayout *pLayout = pTable->GetHTMLTableLayout(); + if( pLayout && pLayout->IsExportable() ) + m_pTableWrt = new SwWriteTable( pLayout ); + else + m_pTableWrt = new SwWriteTable( pTable->GetTabLines(), (sal_uInt16)nPageSize, + (sal_uInt16)nTblSz, false); +} + +void DocxAttributeOutput::StartTable( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + m_pSerializer->startElementNS( XML_w, XML_tbl, FSEND ); + + InitTableHelper( pTableTextNodeInfoInner ); + TableDefinition( pTableTextNodeInfoInner ); +} + +void DocxAttributeOutput::EndTable() +{ + m_pSerializer->endElementNS( XML_w, XML_tbl ); + + if ( m_nTableDepth > 0 ) + --m_nTableDepth; + + // We closed the table; if it is a nested table, the cell that contains it + // still continues + m_bTableCellOpen = true; + + // Cleans the table helper + delete m_pTableWrt, m_pTableWrt = NULL; +} + +void DocxAttributeOutput::StartTableRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + m_pSerializer->startElementNS( XML_w, XML_tr, FSEND ); + + // Output the row properties + m_pSerializer->startElementNS( XML_w, XML_trPr, FSEND ); + + // Header row: tblHeader + const SwTable *pTable = pTableTextNodeInfoInner->getTable( ); + if ( pTable->GetRowsToRepeat( ) > pTableTextNodeInfoInner->getRow( ) ) + m_pSerializer->singleElementNS( XML_w, XML_tblHeader, + FSNS( XML_w, XML_val ), "true", + FSEND ); + + TableHeight( pTableTextNodeInfoInner ); + TableCanSplit( pTableTextNodeInfoInner ); + + m_pSerializer->endElementNS( XML_w, XML_trPr ); +} + +void DocxAttributeOutput::EndTableRow( ) +{ + m_pSerializer->endElementNS( XML_w, XML_tr ); +} + +void DocxAttributeOutput::StartTableCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + if ( !m_pTableWrt ) + InitTableHelper( pTableTextNodeInfoInner ); + + m_pSerializer->startElementNS( XML_w, XML_tc, FSEND ); + + // Write the cell properties here + TableCellProperties( pTableTextNodeInfoInner ); + + m_bTableCellOpen = true; +} + +void DocxAttributeOutput::EndTableCell( ) +{ + m_pSerializer->endElementNS( XML_w, XML_tc ); + + m_bTableCellOpen = false; +} + +void DocxAttributeOutput::TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ ) +{ +} + +void DocxAttributeOutput::TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfo*/ ) +{ +} + +void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT; + + // Write the table properties + m_pSerializer->startElementNS( XML_w, XML_tblPr, FSEND ); + + sal_uInt32 nPageSize = 0; + bool bRelBoxSize = false; + + // Create the SwWriteTable instance to use col spans (and maybe other infos) + GetTablePageSize( pTableTextNodeInfoInner.get(), nPageSize, bRelBoxSize ); + + // Output the table prefered width + if ( nPageSize != 0 ) + m_pSerializer->singleElementNS( XML_w, XML_tblW, + FSNS( XML_w, XML_w ), OString::valueOf( sal_Int32( nPageSize ) ).getStr( ), + FSNS( XML_w, XML_type ), "dxa", + FSEND ); + + // Output the table alignement + const SwTable *pTable = pTableTextNodeInfoInner->getTable(); + SwFrmFmt *pTblFmt = pTable->GetFrmFmt( ); + const char* pJcVal; + sal_Int32 nIndent = 0; + switch ( pTblFmt->GetHoriOrient( ).GetHoriOrient( ) ) + { + case text::HoriOrientation::CENTER: + pJcVal = "center"; + break; + case text::HoriOrientation::RIGHT: + if ( bEcma ) + pJcVal = "right"; + else + pJcVal = "end"; + break; + default: + case text::HoriOrientation::NONE: + case text::HoriOrientation::LEFT_AND_WIDTH: + { + if ( bEcma ) + pJcVal = "left"; + else + pJcVal = "start"; + nIndent = sal_Int32( pTblFmt->GetLRSpace( ).GetLeft( ) ); + break; + } + } + m_pSerializer->singleElementNS( XML_w, XML_jc, + FSNS( XML_w, XML_val ), pJcVal, + FSEND ); + + // Output the table borders + TableDefaultBorders( pTableTextNodeInfoInner ); + TableBidi( pTableTextNodeInfoInner ); + + // Table indent + if ( nIndent != 0 ) + m_pSerializer->singleElementNS( XML_w, XML_tblInd, + FSNS( XML_w, XML_w ), OString::valueOf( nIndent ).getStr( ), + FSNS( XML_w, XML_type ), "dxa", + FSEND ); + + m_pSerializer->endElementNS( XML_w, XML_tblPr ); + + // Write the table grid infos + m_pSerializer->startElementNS( XML_w, XML_tblGrid, FSEND ); + sal_Int32 nPrv = 0; + ww8::GridColsPtr pGridCols = GetGridCols( pTableTextNodeInfoInner ); + for ( ww8::GridCols::const_iterator it = pGridCols->begin(); it != pGridCols->end(); ++it ) + { + sal_Int32 nWidth = sal_Int32( *it ) - nPrv; + m_pSerializer->singleElementNS( XML_w, XML_gridCol, + FSNS( XML_w, XML_w ), OString::valueOf( nWidth ).getStr( ), + FSEND ); + nPrv = sal_Int32( *it ); + } + + m_pSerializer->endElementNS( XML_w, XML_tblGrid ); +} + +void DocxAttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); + const SwFrmFmt * pFrmFmt = pTabBox->GetFrmFmt(); + + bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT; + + // the defaults of the table are taken from the top-left cell + m_pSerializer->startElementNS( XML_w, XML_tblBorders, FSEND ); + impl_pageBorders( m_pSerializer, pFrmFmt->GetBox( ), !bEcma ); + m_pSerializer->endElementNS( XML_w, XML_tblBorders ); +} + +void DocxAttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + const SwTableBox *pTblBox = pTableTextNodeInfoInner->getTableBox( ); + const SwFrmFmt *pFmt = pTblBox->GetFrmFmt( ); + const SfxPoolItem *pI = NULL; + + Color aColor; + if ( SFX_ITEM_ON == pFmt->GetAttrSet().GetItemState( RES_BACKGROUND, false, &pI ) ) + aColor = dynamic_cast<const SvxBrushItem *>(pI)->GetColor(); + else + aColor = COL_AUTO; + + OString sColor = impl_ConvertColor( aColor ); + m_pSerializer->singleElementNS( XML_w, XML_shd, + FSNS( XML_w, XML_fill ), sColor.getStr( ), + FSNS( XML_w, XML_val ), "clear", + FSEND ); +} + +void DocxAttributeOutput::TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); + const SwTableLine * pTabLine = pTabBox->GetUpper(); + const SwFrmFmt * pLineFmt = pTabLine->GetFrmFmt(); + + const SwFmtFrmSize& rLSz = pLineFmt->GetFrmSize(); + if ( ATT_VAR_SIZE != rLSz.GetHeightSizeType() && rLSz.GetHeight() ) + { + sal_Int32 nHeight = rLSz.GetHeight(); + const char *pRule = NULL; + + switch ( rLSz.GetHeightSizeType() ) + { + case ATT_FIX_SIZE: pRule = "exact"; break; + case ATT_MIN_SIZE: pRule = "atLeast"; break; + default: break; + } + + if ( pRule ) + m_pSerializer->singleElementNS( XML_w, XML_trHeight, + FSNS( XML_w, XML_val ), OString::valueOf( nHeight ).getStr( ), + FSNS( XML_w, XML_hRule ), pRule, + FSEND ); + } +} + +void DocxAttributeOutput::TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); + const SwTableLine * pTabLine = pTabBox->GetUpper(); + const SwFrmFmt * pLineFmt = pTabLine->GetFrmFmt(); + + const SwFmtRowSplit& rSplittable = pLineFmt->GetRowSplit( ); + const char* pCantSplit = ( !rSplittable.GetValue( ) ) ? "true" : "false"; + + m_pSerializer->singleElementNS( XML_w, XML_cantSplit, + FSNS( XML_w, XML_val ), pCantSplit, + FSEND ); +} + +void DocxAttributeOutput::TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + const SwTable * pTable = pTableTextNodeInfoInner->getTable(); + const SwFrmFmt * pFrmFmt = pTable->GetFrmFmt(); + + if ( m_rExport.TrueFrameDirection( *pFrmFmt ) == FRMDIR_HORI_RIGHT_TOP ) + { + m_pSerializer->singleElementNS( XML_w, XML_bidiVisual, + FSNS( XML_w, XML_val ), "true", + FSEND ); + } +} + +void DocxAttributeOutput::TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); + const SwFrmFmt *pFrmFmt = pTabBox->GetFrmFmt( ); + + if ( FRMDIR_VERT_TOP_RIGHT == m_rExport.TrueFrameDirection( *pFrmFmt ) ) + m_pSerializer->singleElementNS( XML_w, XML_textDirection, + FSNS( XML_w, XML_val ), "tbRl", + FSEND ); +} + +void DocxAttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t /*pNodeInfo*/ ) +{ + OSL_TRACE( "TODO: DocxAttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t pNodeInfo )\n" ); +} + +void DocxAttributeOutput::TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner ) +{ + // This is called when the nested table ends in a cell, and there's no + // paragraph benhind that; so we must check for the ends of cell, rows, + // tables + // ['true' to write an empty paragraph, MS Word insists on that] + FinishTableRowCell( pNodeInfoInner, true ); +} + +void DocxAttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ ) +{ + OSL_TRACE( "TODO: DocxAttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )\n" ); +} + +void DocxAttributeOutput::TableSpacing( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ ) +{ +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "TODO: DocxAttributeOutput::TableSpacing( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner )\n" ); +#endif +} + +void DocxAttributeOutput::TableRowEnd( sal_uInt32 /*nDepth*/ ) +{ + OSL_TRACE( "TODO: DocxAttributeOutput::TableRowEnd( sal_uInt32 nDepth = 1 )\n" ); +} + +void DocxAttributeOutput::StartStyles() +{ + m_pSerializer->startElementNS( XML_w, XML_styles, + FSNS( XML_xmlns, XML_w ), "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + FSEND ); +} + +void DocxAttributeOutput::EndStyles( sal_uInt16 /*nNumberOfStyles*/ ) +{ + m_pSerializer->endElementNS( XML_w, XML_styles ); +} + +void DocxAttributeOutput::DefaultStyle( sal_uInt16 nStyle ) +{ + // are these the values of enum ww::sti (see ../inc/wwstyles.hxx)? +#if OSL_DEBUG_LEVEL > 1 + OSL_TRACE( "TODO DocxAttributeOutput::DefaultStyle( sal_uInt16 nStyle )- %d\n", nStyle ); +#else + (void) nStyle; // to quiet the warning +#endif +} + +void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode& rGrfNode, const Size& rSize ) +{ + OSL_TRACE( "TODO DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode& rGrfNode, const Size& rSize ) - some stuff still missing\n" ); + // create the relation ID + OString aRelId; + sal_Int32 nImageType; + if ( rGrfNode.IsLinkedFile() ) + { + // linked image, just create the relation + String aFileName; + rGrfNode.GetFileFilterNms( &aFileName, 0 ); + + // TODO Convert the file name to relative for better interoperability + + aRelId = m_rExport.AddRelation( + S( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" ), + OUString( aFileName ), + S( "External" ) ); + + nImageType = XML_link; + } + else + { + // inline, we also have to write the image itself + Graphic& rGraphic = const_cast< Graphic& >( rGrfNode.GetGrf() ); + + m_rDrawingML.SetFS( m_pSerializer ); // to be sure that we write to the right stream + OUString aImageId = m_rDrawingML.WriteImage( rGraphic ); + + aRelId = OUStringToOString( aImageId, RTL_TEXTENCODING_UTF8 ); + + nImageType = XML_embed; + } + + if ( aRelId.getLength() == 0 ) + return; + + m_pSerializer->startElementNS( XML_w, XML_drawing, + FSEND ); + bool isAnchor = rGrfNode.GetFlyFmt()->GetAnchor().GetAnchorId() != FLY_AS_CHAR; + if( isAnchor ) + { + m_pSerializer->startElementNS( XML_wp, XML_anchor, + XML_distT, "0", XML_distB, "0", XML_distL, "0", XML_distR, "0", XML_simplePos, "0", + XML_relativeHeight, "0", // TODO + XML_behindDoc, rGrfNode.GetFlyFmt()->GetOpaque().GetValue() ? "0" : "1", + XML_locked, "0", XML_layoutInCell, "1", XML_allowOverlap, "1", // TODO + FSEND ); + m_pSerializer->singleElementNS( XML_wp, XML_simplePos, XML_x, "0", XML_y, "0", FSEND ); // required, unused + const char* relativeFromH; + const char* relativeFromV; + switch( rGrfNode.GetFlyFmt()->GetAnchor().GetAnchorId()) + { + case FLY_AT_PAGE: + relativeFromV = relativeFromH = "page"; + break; + case FLY_AT_PARA: + relativeFromH = "column"; + relativeFromV = "paragraph"; + break; + case FLY_AT_CHAR: + default: + relativeFromH = "character"; + relativeFromV = "line"; + break; + }; + Point pos( 0, 0 ); + if( SwFlyFrmFmt* flyfmt = dynamic_cast<SwFlyFrmFmt*>(rGrfNode.GetFlyFmt())) // TODO is always true? + pos = flyfmt->GetAnchoredObj()->GetCurrRelPos(); + OString x( OString::valueOf( TwipsToEMU( pos.X()))); + OString y( OString::valueOf( TwipsToEMU( pos.Y()))); + m_pSerializer->startElementNS( XML_wp, XML_positionH, XML_relativeFrom, relativeFromH, FSEND ); + m_pSerializer->startElementNS( XML_wp, XML_posOffset, FSEND ); + m_pSerializer->write( x ); + m_pSerializer->endElementNS( XML_wp, XML_posOffset ); + m_pSerializer->endElementNS( XML_wp, XML_positionH ); + m_pSerializer->startElementNS( XML_wp, XML_positionV, XML_relativeFrom, relativeFromV, FSEND ); + m_pSerializer->startElementNS( XML_wp, XML_posOffset, FSEND ); + m_pSerializer->write( y ); + m_pSerializer->endElementNS( XML_wp, XML_posOffset ); + m_pSerializer->endElementNS( XML_wp, XML_positionV ); + } + else + { + m_pSerializer->startElementNS( XML_wp, XML_inline, + XML_distT, "0", XML_distB, "0", XML_distL, "0", XML_distR, "0", + FSEND ); + } + // now the common parts + // extent of the image + OString aWidth( OString::valueOf( TwipsToEMU( rSize.Width() ) ) ); + OString aHeight( OString::valueOf( TwipsToEMU( rSize.Height() ) ) ); + m_pSerializer->singleElementNS( XML_wp, XML_extent, + XML_cx, aWidth.getStr(), + XML_cy, aHeight.getStr(), + FSEND ); + // TODO - the right effectExtent, extent including the effect + m_pSerializer->singleElementNS( XML_wp, XML_effectExtent, + XML_l, "0", XML_t, "0", XML_r, "0", XML_b, "0", + FSEND ); + + if( isAnchor ) + { + switch( rGrfNode.GetFlyFmt()->GetSurround().GetValue()) + { + case SURROUND_NONE: + m_pSerializer->singleElementNS( XML_wp, XML_wrapTopAndBottom, FSEND ); + break; + case SURROUND_THROUGHT: + m_pSerializer->singleElementNS( XML_wp, XML_wrapNone, FSEND ); + break; + case SURROUND_PARALLEL: + m_pSerializer->singleElementNS( XML_wp, XML_wrapSquare, + XML_wrapText, "bothSides", FSEND ); + break; + case SURROUND_IDEAL: + default: + m_pSerializer->singleElementNS( XML_wp, XML_wrapSquare, + XML_wrapText, "largest", FSEND ); + break; + } + } + // picture description + // TODO the right image description + m_pSerializer->startElementNS( XML_wp, XML_docPr, + XML_id, "1", + XML_name, "Picture", + XML_descr, "A description...", + FSEND ); + // TODO hyperlink + // m_pSerializer->singleElementNS( XML_a, XML_hlinkClick, + // FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main", + // FSNS( XML_r, XML_id ), "rId4", + // FSEND ); + m_pSerializer->endElementNS( XML_wp, XML_docPr ); + + m_pSerializer->startElementNS( XML_wp, XML_cNvGraphicFramePr, + FSEND ); + // TODO change aspect? + m_pSerializer->singleElementNS( XML_a, XML_graphicFrameLocks, + FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main", + XML_noChangeAspect, "1", + FSEND ); + m_pSerializer->endElementNS( XML_wp, XML_cNvGraphicFramePr ); + + m_pSerializer->startElementNS( XML_a, XML_graphic, + FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main", + FSEND ); + m_pSerializer->startElementNS( XML_a, XML_graphicData, + XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/picture", + FSEND ); + + m_pSerializer->startElementNS( XML_pic, XML_pic, + FSNS( XML_xmlns, XML_pic ), "http://schemas.openxmlformats.org/drawingml/2006/picture", + FSEND ); + + m_pSerializer->startElementNS( XML_pic, XML_nvPicPr, + FSEND ); + // TODO the right image description + m_pSerializer->startElementNS( XML_pic, XML_cNvPr, + XML_id, "0", + XML_name, "Picture", + XML_descr, "A description...", + FSEND ); + // TODO hyperlink + // m_pSerializer->singleElementNS( XML_a, XML_hlinkClick, + // FSNS( XML_r, XML_id ), "rId4", + // FSEND ); + m_pSerializer->endElementNS( XML_pic, XML_cNvPr ); + + m_pSerializer->startElementNS( XML_pic, XML_cNvPicPr, + FSEND ); + // TODO change aspect? + m_pSerializer->singleElementNS( XML_a, XML_picLocks, + XML_noChangeAspect, "1", XML_noChangeArrowheads, "1", + FSEND ); + m_pSerializer->endElementNS( XML_pic, XML_cNvPicPr ); + m_pSerializer->endElementNS( XML_pic, XML_nvPicPr ); + + // the actual picture + m_pSerializer->startElementNS( XML_pic, XML_blipFill, + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_blip, + FSNS( XML_r, nImageType ), aRelId.getStr(), + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_srcRect, + FSEND ); + m_pSerializer->startElementNS( XML_a, XML_stretch, + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_fillRect, + FSEND ); + m_pSerializer->endElementNS( XML_a, XML_stretch ); + m_pSerializer->endElementNS( XML_pic, XML_blipFill ); + + // TODO setup the right values below + m_pSerializer->startElementNS( XML_pic, XML_spPr, + XML_bwMode, "auto", + FSEND ); + m_pSerializer->startElementNS( XML_a, XML_xfrm, + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_off, + XML_x, "0", XML_y, "0", + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_ext, + XML_cx, aWidth.getStr(), + XML_cy, aHeight.getStr(), + FSEND ); + m_pSerializer->endElementNS( XML_a, XML_xfrm ); + m_pSerializer->startElementNS( XML_a, XML_prstGeom, + XML_prst, "rect", + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_avLst, + FSEND ); + m_pSerializer->endElementNS( XML_a, XML_prstGeom ); + m_pSerializer->singleElementNS( XML_a, XML_noFill, + FSEND ); + m_pSerializer->startElementNS( XML_a, XML_ln, + XML_w, "9525", + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_noFill, + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_miter, + XML_lim, "800000", + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_headEnd, + FSEND ); + m_pSerializer->singleElementNS( XML_a, XML_tailEnd, + FSEND ); + m_pSerializer->endElementNS( XML_a, XML_ln ); + m_pSerializer->endElementNS( XML_pic, XML_spPr ); + + m_pSerializer->endElementNS( XML_pic, XML_pic ); + + m_pSerializer->endElementNS( XML_a, XML_graphicData ); + m_pSerializer->endElementNS( XML_a, XML_graphic ); + m_pSerializer->endElementNS( XML_wp, isAnchor ? XML_anchor : XML_inline ); + + m_pSerializer->endElementNS( XML_w, XML_drawing ); +} + +void DocxAttributeOutput::WriteOLE2Obj( const SdrObject* pSdrObj, const Size& rSize ) +{ + uno::Reference< chart2::XChartDocument > xChartDoc; + uno::Reference< drawing::XShape > xShape( ((SdrObject*)pSdrObj)->getUnoShape(), uno::UNO_QUERY ); + if( xShape.is() ) + { + uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + xChartDoc.set( xPropSet->getPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Model")) ), uno::UNO_QUERY ); + } + + if( xChartDoc.is() ) + { + OSL_TRACE("DocxAttributeOutput::WriteOLE2Obj: export chart "); + m_pSerializer->startElementNS( XML_w, XML_drawing, + FSEND ); + m_pSerializer->startElementNS( XML_wp, XML_inline, + XML_distT, "0", XML_distB, "0", XML_distL, "0", XML_distR, "0", + FSEND ); + + OString aWidth( OString::valueOf( TwipsToEMU( rSize.Width() ) ) ); + OString aHeight( OString::valueOf( TwipsToEMU( rSize.Height() ) ) ); + m_pSerializer->singleElementNS( XML_wp, XML_extent, + XML_cx, aWidth.getStr(), + XML_cy, aHeight.getStr(), + FSEND ); + // TODO - the right effectExtent, extent including the effect + m_pSerializer->singleElementNS( XML_wp, XML_effectExtent, + XML_l, "0", XML_t, "0", XML_r, "0", XML_b, "0", + FSEND ); + + // should get the unique id + sal_Int32 nID = 1; + OUString sName(RTL_CONSTASCII_USTRINGPARAM("Object 1")); + uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY ); + if( xNamed.is() ) + sName = xNamed->getName(); + + m_pSerializer->singleElementNS( XML_wp, XML_docPr, + XML_id, I32S( nID ), + XML_name, USS( sName ), + FSEND ); + + m_pSerializer->singleElementNS( XML_wp, XML_cNvGraphicFramePr, + FSEND ); + + m_pSerializer->startElementNS( XML_a, XML_graphic, + FSNS( XML_xmlns, XML_a ), "http://schemas.openxmlformats.org/drawingml/2006/main", + FSEND ); + + m_pSerializer->startElementNS( XML_a, XML_graphicData, + XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/chart", + FSEND ); + + OString aRelId; + static sal_Int32 nChartCount = 0; + nChartCount++; + uno::Reference< frame::XModel > xModel( xChartDoc, uno::UNO_QUERY ); + aRelId = m_rExport.OutputChart( xModel, nChartCount ); + + m_pSerializer->singleElementNS( XML_c, XML_chart, + FSNS( XML_xmlns, XML_c ), "http://schemas.openxmlformats.org/drawingml/2006/chart", + FSNS( XML_xmlns, XML_r ), "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + FSNS( XML_r, XML_id ), aRelId.getStr(), + FSEND ); + + m_pSerializer->endElementNS( XML_a, XML_graphicData ); + m_pSerializer->endElementNS( XML_a, XML_graphic ); + m_pSerializer->endElementNS( XML_wp, XML_inline ); + m_pSerializer->endElementNS( XML_w, XML_drawing ); + } +} + +void DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame &rFrame, const Point& /*rNdTopLeft*/ ) +{ + m_pSerializer->mark(); + + switch ( rFrame.GetWriterType() ) + { + case sw::Frame::eGraphic: + { + const SwNode *pNode = rFrame.GetContent(); + const SwGrfNode *pGrfNode = pNode ? pNode->GetGrfNode() : 0; + if ( pGrfNode ) + FlyFrameGraphic( *pGrfNode, rFrame.GetLayoutSize() ); + } + break; + case sw::Frame::eDrawing: + { + const SdrObject* pSdrObj = rFrame.GetFrmFmt().FindRealSdrObject(); + if ( pSdrObj ) + { + bool bSwapInPage = false; + if ( !pSdrObj->GetPage() ) + { + if ( SdrModel* pModel = m_rExport.pDoc->GetDrawModel() ) + { + if ( SdrPage *pPage = pModel->GetPage( 0 ) ) + { + bSwapInPage = true; + const_cast< SdrObject* >( pSdrObj )->SetPage( pPage ); + } + } + } + + m_pSerializer->startElementNS( XML_w, XML_pict, + FSEND ); + + m_rExport.VMLExporter().AddSdrObject( *pSdrObj ); + + m_pSerializer->endElementNS( XML_w, XML_pict ); + + if ( bSwapInPage ) + const_cast< SdrObject* >( pSdrObj )->SetPage( 0 ); + } + } + break; + case sw::Frame::eTxtBox: + { + // The frame output is postponed at the end of the anchor paragraph + m_pParentFrame = &rFrame; + } + break; + case sw::Frame::eOle: + { + const SdrObject* pSdrObj = rFrame.GetFrmFmt().FindRealSdrObject(); + if ( pSdrObj ) + WriteOLE2Obj( pSdrObj, rFrame.GetLayoutSize() ); + } + break; + default: + OSL_TRACE( "TODO DocxAttributeOutput::OutputFlyFrame_Impl( const sw::Frame& rFrame, const Point& rNdTopLeft ) - frame type '%s'\n", + rFrame.GetWriterType() == sw::Frame::eTxtBox? "eTxtBox": + ( rFrame.GetWriterType() == sw::Frame::eOle? "eOle": + ( rFrame.GetWriterType() == sw::Frame::eFormControl? "eFormControl": "???" ) ) ); + break; + } + + m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_POSTPONE ); +} + +void DocxAttributeOutput::StartStyle( const String& rName, bool bPapFmt, + sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 /*nWwId*/, sal_uInt16 nId, bool bAutoUpdate ) +{ + OString aStyle( "style" ); + + m_pSerializer->startElementNS( XML_w, XML_style, + FSNS( XML_w, XML_type ), bPapFmt? "paragraph": "character", // FIXME is this correct? + FSNS( XML_w, XML_styleId ), ( aStyle + OString::valueOf( sal_Int32( nId ) ) ).getStr(), + FSEND ); + + m_pSerializer->singleElementNS( XML_w, XML_name, + FSNS( XML_w, XML_val ), OUStringToOString( OUString( rName ), RTL_TEXTENCODING_UTF8 ).getStr(), + FSEND ); + + if ( nBase != 0x0FFF ) + { + m_pSerializer->singleElementNS( XML_w, XML_basedOn, + FSNS( XML_w, XML_val ), ( aStyle + OString::valueOf( sal_Int32( nBase ) ) ).getStr(), + FSEND ); + } + + m_pSerializer->singleElementNS( XML_w, XML_next, + FSNS( XML_w, XML_val ), ( aStyle + OString::valueOf( sal_Int32( nNext ) ) ).getStr(), + FSEND ); + + if ( bAutoUpdate ) + m_pSerializer->singleElementNS( XML_w, XML_autoRedefine, FSEND ); +} + +void DocxAttributeOutput::EndStyle() +{ + m_pSerializer->endElementNS( XML_w, XML_style ); +} + +void DocxAttributeOutput::StartStyleProperties( bool bParProp, sal_uInt16 /*nStyle*/ ) +{ + if ( bParProp ) + { + m_pSerializer->startElementNS( XML_w, XML_pPr, FSEND ); + InitCollectedParagraphProperties(); + } + else + { + m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND ); + InitCollectedRunProperties(); + } +} + +void DocxAttributeOutput::EndStyleProperties( bool bParProp ) +{ + if ( bParProp ) + { + WriteCollectedParagraphProperties(); + m_pSerializer->endElementNS( XML_w, XML_pPr ); + } + else + { + WriteCollectedRunProperties(); + m_pSerializer->endElementNS( XML_w, XML_rPr ); + } +} + +void DocxAttributeOutput::OutlineNumbering( sal_uInt8 nLvl, const SwNumFmt& /*rNFmt*/, const SwFmt& /*rFmt*/ ) +{ + if ( nLvl >= WW8ListManager::nMaxLevel ) + nLvl = WW8ListManager::nMaxLevel - 1; + + m_pSerializer->singleElementNS( XML_w, XML_outlineLvl, + FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nLvl ) ).getStr( ), + FSEND ); +} + +void DocxAttributeOutput::PageBreakBefore( bool bBreak ) +{ + if ( bBreak ) + m_pSerializer->singleElementNS( XML_w, XML_pageBreakBefore, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_pageBreakBefore, + FSNS( XML_w, XML_val ), "false", + FSEND ); +} + +void DocxAttributeOutput::SectionBreak( sal_uInt8 nC, const WW8_SepInfo* pSectionInfo ) +{ + switch ( nC ) + { + case msword::ColumnBreak: + // The column break should be output in the next paragraph... + m_nColBreakStatus = COLBRK_POSTPONE; + break; + case msword::PageBreak: + if ( pSectionInfo ) + { + if ( !m_bParagraphOpened ) + { + // Create a dummy paragraph if needed + m_pSerializer->startElementNS( XML_w, XML_p, FSEND ); + m_pSerializer->startElementNS( XML_w, XML_pPr, FSEND ); + + m_rExport.SectionProperties( *pSectionInfo ); + + m_pSerializer->endElementNS( XML_w, XML_pPr ); + m_pSerializer->endElementNS( XML_w, XML_p ); + } + else + { + // postpone the output of this; it has to be done inside the + // paragraph properties, so remember it until then + m_pSectionInfo = pSectionInfo; + } + } + else + { + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_br, + FSNS( XML_w, XML_type ), "page", FSEND ); + m_pSerializer->endElementNS( XML_w, XML_r ); + } + break; + default: + OSL_TRACE( "Unknown section break to write: %d\n", nC ); + break; + } +} + +void DocxAttributeOutput::StartSection() +{ + m_pSerializer->startElementNS( XML_w, XML_sectPr, FSEND ); + m_bOpenedSectPr = true; + + // Write the elements in the spec order + static const sal_Int32 aOrder[] = + { + FSNS( XML_w, XML_headerReference ), + FSNS( XML_w, XML_footerReference ), + FSNS( XML_w, XML_footnotePr ), + FSNS( XML_w, XML_endnotePr ), + FSNS( XML_w, XML_type ), + FSNS( XML_w, XML_pgSz ), + FSNS( XML_w, XML_pgMar ), + FSNS( XML_w, XML_paperSrc ), + FSNS( XML_w, XML_pgBorders ), + FSNS( XML_w, XML_lnNumType ), + FSNS( XML_w, XML_pgNumType ), + FSNS( XML_w, XML_cols ), + FSNS( XML_w, XML_formProt ), + FSNS( XML_w, XML_vAlign ), + FSNS( XML_w, XML_noEndnote ), + FSNS( XML_w, XML_titlePg ), + FSNS( XML_w, XML_textDirection ), + FSNS( XML_w, XML_bidi ), + FSNS( XML_w, XML_rtlGutter ), + FSNS( XML_w, XML_docGrid ), + FSNS( XML_w, XML_printerSettings ), + FSNS( XML_w, XML_sectPrChange ) + }; + + // postpone the output so that we can later [in EndParagraphProperties()] + // prepend the properties before the run + sal_Int32 len = sizeof ( aOrder ) / sizeof( sal_Int32 ); + uno::Sequence< sal_Int32 > aSeqOrder( len ); + for ( sal_Int32 i = 0; i < len; i++ ) + aSeqOrder[i] = aOrder[i]; + + m_pSerializer->mark( aSeqOrder ); +} + +void DocxAttributeOutput::EndSection() +{ + // Write the section properties + if ( m_pSectionSpacingAttrList ) + { + XFastAttributeListRef xAttrList( m_pSectionSpacingAttrList ); + m_pSectionSpacingAttrList = NULL; + + m_pSerializer->singleElementNS( XML_w, XML_pgMar, xAttrList ); + } + + // Order the elements + m_pSerializer->mergeTopMarks( ); + + m_pSerializer->endElementNS( XML_w, XML_sectPr ); + m_bOpenedSectPr = false; +} + +void DocxAttributeOutput::SectionFormProtection( bool bProtected ) +{ + if ( bProtected ) + m_pSerializer->singleElementNS( XML_w, XML_formProt, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_formProt, + FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::SectionLineNumbering( sal_uLong nRestartNo, const SwLineNumberInfo& rLnNumInfo ) +{ + FastAttributeList* pAttr = m_pSerializer->createAttrList(); + pAttr->add( FSNS( XML_w, XML_countBy ), OString::valueOf(static_cast<sal_Int32>(rLnNumInfo.GetCountBy())).getStr()); + pAttr->add( FSNS( XML_w, XML_restart ), rLnNumInfo.IsRestartEachPage() ? "newPage" : "continuous" ); + if( rLnNumInfo.GetPosFromLeft()) + pAttr->add( FSNS( XML_w, XML_distance ), OString::valueOf(static_cast<sal_Int32>(rLnNumInfo.GetPosFromLeft())).getStr()); + if( nRestartNo ) + pAttr->add( FSNS( XML_w, XML_start ), OString::valueOf( long( nRestartNo )).getStr()); + XFastAttributeListRef xAttrs( pAttr ); + m_pSerializer->singleElementNS( XML_w, XML_lnNumType, xAttrs ); +} + +void DocxAttributeOutput::SectionTitlePage() +{ + m_pSerializer->singleElementNS( XML_w, XML_titlePg, FSEND ); +} + +void DocxAttributeOutput::SectionPageBorders( const SwFrmFmt* pFmt, const SwFrmFmt* /*pFirstPageFmt*/ ) +{ + // Output the margins + + const SvxBoxItem& rBox = pFmt->GetBox( ); + + const SvxBorderLine* pBottom = rBox.GetBottom( ); + const SvxBorderLine* pTop = rBox.GetTop( ); + const SvxBorderLine* pLeft = rBox.GetLeft( ); + const SvxBorderLine* pRight = rBox.GetRight( ); + + if ( pBottom || pTop || pLeft || pRight ) + { + // All distances are relative to the text margins + m_pSerializer->startElementNS( XML_w, XML_pgBorders, + FSNS( XML_w, XML_display ), "allPages", + FSNS( XML_w, XML_offsetFrom ), "text", + FSEND ); + + m_pSerializer->mark(); + + m_pSerializer->endElementNS( XML_w, XML_pgBorders ); + m_pSerializer->mark(); + } +} + +void DocxAttributeOutput::SectionBiDi( bool bBiDi ) +{ + if ( bBiDi ) + m_pSerializer->singleElementNS( XML_w, XML_bidi, FSEND ); +} + +static OString impl_NumberingType( sal_uInt16 nNumberingType ) +{ + OString aType; + + switch ( nNumberingType ) + { + case SVX_NUM_CHARS_UPPER_LETTER: + case SVX_NUM_CHARS_UPPER_LETTER_N: aType = "upperLetter"; break; + case SVX_NUM_CHARS_LOWER_LETTER: + case SVX_NUM_CHARS_LOWER_LETTER_N: aType = "lowerLetter"; break; + case SVX_NUM_ROMAN_UPPER: aType = "upperRoman"; break; + case SVX_NUM_ROMAN_LOWER: aType = "lowerRoman"; break; + + case SVX_NUM_ARABIC: aType = "decimal"; break; + + case SVX_NUM_BITMAP: + case SVX_NUM_CHAR_SPECIAL: aType = "bullet"; break; + + default: aType = "none"; break; + } + + return aType; +} + +void DocxAttributeOutput::SectionPageNumbering( sal_uInt16 nNumType, sal_uInt16 nPageRestartNumber ) +{ + // FIXME Not called properly with page styles like "First Page" + + FastAttributeList* pAttr = m_pSerializer->createAttrList(); + + // 0 means no restart: then don't output that attribute if 0 + if ( nPageRestartNumber > 0 ) + pAttr->add( FSNS( XML_w, XML_start ), OString::valueOf( sal_Int32( nPageRestartNumber ) ) ); + + // nNumType corresponds to w:fmt. See WW8Export::GetNumId() for more precisions + OString aFmt( impl_NumberingType( nNumType ) ); + if ( aFmt.getLength() ) + pAttr->add( FSNS( XML_w, XML_fmt ), aFmt.getStr() ); + + XFastAttributeListRef xAttrs( pAttr ); + m_pSerializer->singleElementNS( XML_w, XML_pgNumType, xAttrs ); + + // see 2.6.12 pgNumType (Page Numbering Settings) + OSL_TRACE( "TODO DocxAttributeOutput::SectionPageNumbering()\n" ); +} + +void DocxAttributeOutput::SectionType( sal_uInt8 nBreakCode ) +{ + /* break code: 0 No break, 1 New column + 2 New page, 3 Even page, 4 Odd page + */ + const char* pType = NULL; + switch ( nBreakCode ) + { + case 1: pType = "nextColumn"; break; + case 2: pType = "nextPage"; break; + case 3: pType = "evenPage"; break; + case 4: pType = "oddPage"; break; + default: pType = "continuous"; break; + } + + if ( pType ) + m_pSerializer->singleElementNS( XML_w, XML_type, + FSNS( XML_w, XML_val ), pType, + FSEND ); +} + +void DocxAttributeOutput::StartFont( const String& rFamilyName ) const +{ + m_pSerializer->startElementNS( XML_w, XML_font, + FSNS( XML_w, XML_name ), OUStringToOString( OUString( rFamilyName ), RTL_TEXTENCODING_UTF8 ).getStr(), + FSEND ); +} + +void DocxAttributeOutput::EndFont() const +{ + m_pSerializer->endElementNS( XML_w, XML_font ); +} + +void DocxAttributeOutput::FontAlternateName( const String& rName ) const +{ + m_pSerializer->singleElementNS( XML_w, XML_altName, + FSNS( XML_w, XML_val ), OUStringToOString( OUString( rName ), RTL_TEXTENCODING_UTF8 ).getStr(), + FSEND ); +} + +void DocxAttributeOutput::FontCharset( sal_uInt8 nCharSet, rtl_TextEncoding nEncoding ) const +{ + FastAttributeList* pAttr = m_pSerializer->createAttrList(); + + OString aCharSet( OString::valueOf( sal_Int32( nCharSet ), 16 ) ); + if ( aCharSet.getLength() == 1 ) + aCharSet = OString( "0" ) + aCharSet; + pAttr->add( FSNS( XML_w, XML_val ), aCharSet.getStr()); + + if( GetExport().GetFilter().getVersion( ) != oox::core::ECMA_DIALECT ) + { + if( const char* charset = rtl_getMimeCharsetFromTextEncoding( nEncoding )) + pAttr->add( FSNS( XML_w, XML_characterSet ), charset ); + } + + m_pSerializer->singleElementNS( XML_w, XML_charset, XFastAttributeListRef( pAttr )); +} + +void DocxAttributeOutput::FontFamilyType( FontFamily eFamily ) const +{ + const char *pFamily = NULL; + switch ( eFamily ) + { + case FAMILY_ROMAN: pFamily = "roman"; break; + case FAMILY_SWISS: pFamily = "swiss"; break; + case FAMILY_MODERN: pFamily = "modern"; break; + case FAMILY_SCRIPT: pFamily = "script"; break; + case FAMILY_DECORATIVE: pFamily = "decorative"; break; + default: pFamily = "auto"; break; // no font family + } + + if ( pFamily ) + m_pSerializer->singleElementNS( XML_w, XML_family, + FSNS( XML_w, XML_val ), pFamily, + FSEND ); +} + +void DocxAttributeOutput::FontPitchType( FontPitch ePitch ) const +{ + const char *pPitch = NULL; + switch ( ePitch ) + { + case PITCH_VARIABLE: pPitch = "variable"; break; + case PITCH_FIXED: pPitch = "fixed"; break; + default: pPitch = "default"; break; // no info about the pitch + } + + if ( pPitch ) + m_pSerializer->singleElementNS( XML_w, XML_pitch, + FSNS( XML_w, XML_val ), pPitch, + FSEND ); +} + +void DocxAttributeOutput::NumberingDefinition( sal_uInt16 nId, const SwNumRule &rRule ) +{ + // nId is the same both for abstract numbering definition as well as the + // numbering definition itself + // TODO check that this is actually true & fix if not ;-) + OString aId( OString::valueOf( sal_Int32( nId ) ) ); + + m_pSerializer->startElementNS( XML_w, XML_num, + FSNS( XML_w, XML_numId ), aId.getStr(), + FSEND ); + + m_pSerializer->singleElementNS( XML_w, XML_abstractNumId, + FSNS( XML_w, XML_val ), aId.getStr(), + FSEND ); + +#if OSL_DEBUG_LEVEL > 1 + // TODO ww8 version writes this, anything to do about it here? + if ( rRule.IsContinusNum() ) + OSL_TRACE( "TODO DocxAttributeOutput::NumberingDefinition()\n" ); +#else + (void) rRule; // to quiet the warning... +#endif + + m_pSerializer->endElementNS( XML_w, XML_num ); +} + +void DocxAttributeOutput::StartAbstractNumbering( sal_uInt16 nId ) +{ + m_pSerializer->startElementNS( XML_w, XML_abstractNum, + FSNS( XML_w, XML_abstractNumId ), OString::valueOf( sal_Int32( nId ) ).getStr(), + FSEND ); +} + +void DocxAttributeOutput::EndAbstractNumbering() +{ + m_pSerializer->endElementNS( XML_w, XML_abstractNum ); +} + +void DocxAttributeOutput::NumberingLevel( sal_uInt8 nLevel, + sal_uInt16 nStart, + sal_uInt16 nNumberingType, + SvxAdjust eAdjust, + const sal_uInt8 * /*pNumLvlPos*/, + sal_uInt8 nFollow, + const wwFont *pFont, + const SfxItemSet *pOutSet, + sal_Int16 nIndentAt, + sal_Int16 nFirstLineIndex, + sal_Int16 nListTabPos, + const String &rNumberingString ) +{ + m_pSerializer->startElementNS( XML_w, XML_lvl, + FSNS( XML_w, XML_ilvl ), OString::valueOf( sal_Int32( nLevel ) ).getStr(), + FSEND ); + + // start with the nStart value + m_pSerializer->singleElementNS( XML_w, XML_start, + FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nStart ) ).getStr(), + FSEND ); + + // format + OString aFmt( impl_NumberingType( nNumberingType ) ); + + if ( aFmt.getLength() ) + m_pSerializer->singleElementNS( XML_w, XML_numFmt, + FSNS( XML_w, XML_val ), aFmt.getStr(), + FSEND ); + + // suffix + const char *pSuffix = NULL; + switch ( nFollow ) + { + case 1: pSuffix = "space"; break; + case 2: pSuffix = "nothing"; break; + default: /*pSuffix = "tab";*/ break; + } + if ( pSuffix ) + m_pSerializer->singleElementNS( XML_w, XML_suff, + FSNS( XML_w, XML_val ), pSuffix, + FSEND ); + + // text + OUString aText( rNumberingString ); + OUStringBuffer aBuffer( aText.getLength() + WW8ListManager::nMaxLevel ); + + const sal_Unicode *pPrev = aText.getStr(); + const sal_Unicode *pIt = aText.getStr(); + while ( pIt < aText.getStr() + aText.getLength() ) + { + // convert the level values to %NUMBER form + // (we don't use pNumLvlPos at all) + // FIXME so far we support the ww8 limit of levels only + if ( *pIt < sal_Unicode( WW8ListManager::nMaxLevel ) ) + { + aBuffer.append( pPrev, pIt - pPrev ); + aBuffer.appendAscii( "%" ); + aBuffer.append( OUString::valueOf( sal_Int32( *pIt ) + 1 ) ); + + pPrev = pIt + 1; + } + ++pIt; + } + if ( pPrev < pIt ) + aBuffer.append( pPrev, pIt - pPrev ); + + m_pSerializer->singleElementNS( XML_w, XML_lvlText, + FSNS( XML_w, XML_val ), OUStringToOString( aBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 ).getStr(), + FSEND ); + + // justification + const char *pJc; + bool ecmaDialect = ( m_rExport.GetFilter().getVersion() == oox::core::ECMA_DIALECT ); + switch ( eAdjust ) + { + case SVX_ADJUST_CENTER: pJc = "center"; break; + case SVX_ADJUST_RIGHT: pJc = !ecmaDialect ? "end" : "right"; break; + default: pJc = !ecmaDialect ? "start" : "left"; break; + } + m_pSerializer->singleElementNS( XML_w, XML_lvlJc, + FSNS( XML_w, XML_val ), pJc, + FSEND ); + + // indentation + m_pSerializer->startElementNS( XML_w, XML_pPr, FSEND ); + if( nListTabPos != 0 ) + { + m_pSerializer->startElementNS( XML_w, XML_tabs, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_tab, + FSNS( XML_w, XML_val ), "num", + FSNS( XML_w, XML_pos ), OString::valueOf( static_cast<sal_Int32>(nListTabPos) ).getStr(), + FSEND ); + m_pSerializer->endElementNS( XML_w, XML_tabs ); + } + + sal_Int32 nToken = ecmaDialect ? XML_left : XML_start; + m_pSerializer->singleElementNS( XML_w, XML_ind, + FSNS( XML_w, nToken ), OString::valueOf( sal_Int32( nIndentAt ) ).getStr(), + FSNS( XML_w, XML_hanging ), OString::valueOf( sal_Int32( -nFirstLineIndex ) ).getStr(), + FSEND ); + m_pSerializer->endElementNS( XML_w, XML_pPr ); + + // font + if ( pOutSet ) + { + m_pSerializer->startElementNS( XML_w, XML_rPr, FSEND ); + + if ( pFont ) + { + GetExport().GetId( *pFont ); // ensure font info is written to fontTable.xml + OString aFamilyName( OUStringToOString( OUString( pFont->GetFamilyName() ), RTL_TEXTENCODING_UTF8 ) ); + m_pSerializer->singleElementNS( XML_w, XML_rFonts, + FSNS( XML_w, XML_ascii ), aFamilyName.getStr(), + FSNS( XML_w, XML_hAnsi ), aFamilyName.getStr(), + FSNS( XML_w, XML_cs ), aFamilyName.getStr(), + FSNS( XML_w, XML_hint ), "default", + FSEND ); + } + m_rExport.OutputItemSet( *pOutSet, false, true, i18n::ScriptType::LATIN, m_rExport.mbExportModeRTF ); + + m_pSerializer->endElementNS( XML_w, XML_rPr ); + } + + // TODO anything to do about nListTabPos? + + m_pSerializer->endElementNS( XML_w, XML_lvl ); +} + +void DocxAttributeOutput::CharCaseMap( const SvxCaseMapItem& rCaseMap ) +{ + switch ( rCaseMap.GetValue() ) + { + case SVX_CASEMAP_KAPITAELCHEN: + m_pSerializer->singleElementNS( XML_w, XML_smallCaps, FSEND ); + break; + case SVX_CASEMAP_VERSALIEN: + m_pSerializer->singleElementNS( XML_w, XML_caps, FSEND ); + break; + default: // Something that ooxml does not support + m_pSerializer->singleElementNS( XML_w, XML_smallCaps, FSNS( XML_w, XML_val ), "false", FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_caps, FSNS( XML_w, XML_val ), "false", FSEND ); + break; + } +} + +void DocxAttributeOutput::CharColor( const SvxColorItem& rColor ) +{ + const Color aColor( rColor.GetValue() ); + OString aColorString; + + aColorString = impl_ConvertColor( aColor ); + + m_pSerializer->singleElementNS( XML_w, XML_color, + FSNS( XML_w, XML_val ), aColorString.getStr(), FSEND ); +} + +void DocxAttributeOutput::CharContour( const SvxContourItem& rContour ) +{ + if ( rContour.GetValue() ) + m_pSerializer->singleElementNS( XML_w, XML_outline, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_outline, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::CharCrossedOut( const SvxCrossedOutItem& rCrossedOut ) +{ + switch ( rCrossedOut.GetStrikeout() ) + { + case STRIKEOUT_DOUBLE: + m_pSerializer->singleElementNS( XML_w, XML_dstrike, FSEND ); + break; + case STRIKEOUT_NONE: + m_pSerializer->singleElementNS( XML_w, XML_dstrike, FSNS( XML_w, XML_val ), "false", FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_strike, FSNS( XML_w, XML_val ), "false", FSEND ); + break; + default: + m_pSerializer->singleElementNS( XML_w, XML_strike, FSEND ); + break; + } +} + +void DocxAttributeOutput::CharEscapement( const SvxEscapementItem& rEscapement ) +{ + OString sIss; + short nEsc = rEscapement.GetEsc(), nProp = rEscapement.GetProp(); + if ( !nEsc ) + { + sIss = OString( "baseline" ); + nEsc = 0; + nProp = 100; + } + else if ( DFLT_ESC_PROP == nProp ) + { + if ( DFLT_ESC_SUB == nEsc || DFLT_ESC_AUTO_SUB == nEsc ) + sIss = OString( "subscript" ); + else if ( DFLT_ESC_SUPER == nEsc || DFLT_ESC_AUTO_SUPER == nEsc ) + sIss = OString( "superscript" ); + } + + if ( sIss.getLength( ) > 0 ) + m_pSerializer->singleElementNS( XML_w, XML_vertAlign, + FSNS( XML_w, XML_val ), sIss.getStr(), FSEND ); + + if ( sIss.getLength() == 0 || sIss.match( OString( "baseline" ) ) ) + { + long nHeight = ((SvxFontHeightItem&)m_rExport.GetItem( + RES_CHRATR_FONTSIZE )).GetHeight(); + OString sPos = OString::valueOf( ( nHeight * nEsc + 500 ) / 1000 ); + m_pSerializer->singleElementNS( XML_w, XML_position, + FSNS( XML_w, XML_val ), sPos.getStr( ), FSEND ); + + if( 100 != nProp || sIss.match( OString( "baseline" ) ) ) + { + OString sSize = OString::valueOf( ( nHeight * nProp + 500 ) / 1000 ); + m_pSerializer->singleElementNS( XML_w, XML_sz, + FSNS( XML_w, XML_val ), sSize.getStr( ), FSEND ); + } + } +} + +void DocxAttributeOutput::CharFont( const SvxFontItem& rFont) +{ + if (!m_pFontsAttrList) + m_pFontsAttrList = m_pSerializer->createAttrList(); + OUString sFontName(rFont.GetFamilyName()); + OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8); + m_pFontsAttrList->add(FSNS(XML_w, XML_ascii), sFontNameUtf8); + m_pFontsAttrList->add(FSNS(XML_w, XML_hAnsi), sFontNameUtf8); +} + +void DocxAttributeOutput::CharFontSize( const SvxFontHeightItem& rFontSize) +{ + OString fontSize = OString::valueOf( sal_Int32( ( rFontSize.GetHeight() + 5 ) / 10 ) ); + + switch ( rFontSize.Which() ) + { + case RES_CHRATR_FONTSIZE: + case RES_CHRATR_CJK_FONTSIZE: + m_pSerializer->singleElementNS( XML_w, XML_sz, FSNS( XML_w, XML_val ), fontSize.getStr(), FSEND ); + break; + case RES_CHRATR_CTL_FONTSIZE: + m_pSerializer->singleElementNS( XML_w, XML_szCs, FSNS( XML_w, XML_val ), fontSize.getStr(), FSEND ); + break; + } +} + +void DocxAttributeOutput::CharKerning( const SvxKerningItem& rKerning ) +{ + OString aKerning = OString::valueOf( ( sal_Int32 ) rKerning.GetValue() ); + m_pSerializer->singleElementNS( XML_w, XML_spacing, FSNS(XML_w, XML_val), aKerning.getStr(), FSEND ); +} + +void DocxAttributeOutput::CharLanguage( const SvxLanguageItem& rLanguage ) +{ + if (!m_pCharLangAttrList) + m_pCharLangAttrList = m_pSerializer->createAttrList(); + + ::com::sun::star::lang::Locale xLocale= MsLangId::convertLanguageToLocale( rLanguage.GetLanguage( ) ); + OString sLanguage = OUStringToOString(xLocale.Language, RTL_TEXTENCODING_UTF8); + OString sCountry = OUStringToOString(xLocale.Country, RTL_TEXTENCODING_UTF8); + + OString aLanguageCode = sLanguage + "-" + sCountry; + + switch ( rLanguage.Which() ) + { + case RES_CHRATR_LANGUAGE: + m_pCharLangAttrList->add(FSNS(XML_w, XML_val), aLanguageCode); + break; + case RES_CHRATR_CJK_LANGUAGE: + m_pCharLangAttrList->add(FSNS(XML_w, XML_eastAsia), aLanguageCode); + break; + case RES_CHRATR_CTL_LANGUAGE: + m_pCharLangAttrList->add(FSNS(XML_w, XML_bidi), aLanguageCode); + break; + } +} + +void DocxAttributeOutput::CharPosture( const SvxPostureItem& rPosture ) +{ + if ( rPosture.GetPosture() != ITALIC_NONE ) + m_pSerializer->singleElementNS( XML_w, XML_i, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_i, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::CharShadow( const SvxShadowedItem& rShadow ) +{ + if ( rShadow.GetValue() ) + m_pSerializer->singleElementNS( XML_w, XML_shadow, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_shadow, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::CharUnderline( const SvxUnderlineItem& rUnderline ) +{ + const char *pUnderline; + + switch ( rUnderline.GetLineStyle() ) + { + case UNDERLINE_SINGLE: pUnderline = "single"; break; + case UNDERLINE_BOLD: pUnderline = "thick"; break; + case UNDERLINE_DOUBLE: pUnderline = "double"; break; + case UNDERLINE_DOTTED: pUnderline = "dotted"; break; + case UNDERLINE_DASH: pUnderline = "dash"; break; + case UNDERLINE_DASHDOT: pUnderline = "dotDash"; break; + case UNDERLINE_DASHDOTDOT: pUnderline = "dotDotDash"; break; + case UNDERLINE_WAVE: pUnderline = "wave"; break; + case UNDERLINE_BOLDDOTTED: pUnderline = "dottedHeavy"; break; + case UNDERLINE_BOLDDASH: pUnderline = "dashedHeavy"; break; + case UNDERLINE_LONGDASH: pUnderline = "dashLongHeavy"; break; + case UNDERLINE_BOLDLONGDASH: pUnderline = "dashLongHeavy"; break; + case UNDERLINE_BOLDDASHDOT: pUnderline = "dashDotHeavy"; break; + case UNDERLINE_BOLDDASHDOTDOT: pUnderline = "dashDotDotHeavy"; break; + case UNDERLINE_BOLDWAVE: pUnderline = "wavyHeavy"; break; + case UNDERLINE_DOUBLEWAVE: pUnderline = "wavyDouble"; break; + case UNDERLINE_NONE: // fall through + default: pUnderline = "none"; break; + } + + m_pSerializer->singleElementNS( XML_w, XML_u, FSNS( XML_w, XML_val ), pUnderline, FSEND ); +} + +void DocxAttributeOutput::CharWeight( const SvxWeightItem& rWeight ) +{ + if ( rWeight.GetWeight() == WEIGHT_BOLD ) + m_pSerializer->singleElementNS( XML_w, XML_b, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_b, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::CharAutoKern( const SvxAutoKernItem& ) +{ + OSL_TRACE( "TODO DocxAttributeOutput::CharAutoKern()\n" ); +} + +void DocxAttributeOutput::CharAnimatedText( const SvxBlinkItem& rBlink ) +{ + if ( rBlink.GetValue() ) + m_pSerializer->singleElementNS(XML_w, XML_effect, FSNS( XML_w, XML_val ), "blinkBackground", FSEND ); + else + m_pSerializer->singleElementNS(XML_w, XML_effect, FSNS( XML_w, XML_val ), "none", FSEND ); +} + +void DocxAttributeOutput::CharBackground( const SvxBrushItem& rBrush ) +{ + m_pSerializer->singleElementNS( XML_w, XML_shd, + FSNS( XML_w, XML_fill ), impl_ConvertColor( rBrush.GetColor() ).getStr(), + FSNS( XML_w, XML_val ), "clear", + FSEND ); +} + +void DocxAttributeOutput::CharFontCJK( const SvxFontItem& rFont ) +{ + if (!m_pFontsAttrList) + m_pFontsAttrList = m_pSerializer->createAttrList(); + OUString sFontName(rFont.GetFamilyName()); + OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8); + m_pFontsAttrList->add(FSNS(XML_w, XML_eastAsia), sFontNameUtf8); +} + +void DocxAttributeOutput::CharPostureCJK( const SvxPostureItem& rPosture ) +{ + if ( rPosture.GetPosture() != ITALIC_NONE ) + m_pSerializer->singleElementNS( XML_w, XML_i, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_i, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::CharWeightCJK( const SvxWeightItem& rWeight ) +{ + if ( rWeight.GetWeight() == WEIGHT_BOLD ) + m_pSerializer->singleElementNS( XML_w, XML_b, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_b, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::CharFontCTL( const SvxFontItem& rFont ) +{ + if (!m_pFontsAttrList) + m_pFontsAttrList = m_pSerializer->createAttrList(); + OUString sFontName(rFont.GetFamilyName()); + OString sFontNameUtf8 = OUStringToOString(sFontName, RTL_TEXTENCODING_UTF8); + m_pFontsAttrList->add(FSNS(XML_w, XML_cs), sFontNameUtf8); + +} + +void DocxAttributeOutput::CharPostureCTL( const SvxPostureItem& rPosture) +{ + if ( rPosture.GetPosture() != ITALIC_NONE ) + m_pSerializer->singleElementNS( XML_w, XML_iCs, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_iCs, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::CharWeightCTL( const SvxWeightItem& rWeight ) +{ + if ( rWeight.GetWeight() == WEIGHT_BOLD ) + m_pSerializer->singleElementNS( XML_w, XML_bCs, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_bCs, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::CharRotate( const SvxCharRotateItem& rRotate) +{ + if ( !rRotate.GetValue() ) + return; + + if (!m_pEastAsianLayoutAttrList) + m_pEastAsianLayoutAttrList = m_pSerializer->createAttrList(); + OString sTrue((sal_Char *)"true"); + m_pEastAsianLayoutAttrList->add(FSNS(XML_w, XML_vert), sTrue); + + if (rRotate.IsFitToLine()) + m_pEastAsianLayoutAttrList->add(FSNS(XML_w, XML_vertCompress), sTrue); +} + +void DocxAttributeOutput::CharEmphasisMark( const SvxEmphasisMarkItem& rEmphasisMark ) +{ + const char *pEmphasis; + + switch ( rEmphasisMark.GetValue() ) + { + case EMPHASISMARK_NONE: pEmphasis = "none"; break; + case EMPHASISMARK_SIDE_DOTS: pEmphasis = "dot"; break; + case EMPHASISMARK_CIRCLE_ABOVE: pEmphasis = "circle"; break; + case EMPHASISMARK_DOTS_BELOW: pEmphasis = "underDot"; break; + default: pEmphasis = "comma"; break; + } + + m_pSerializer->singleElementNS( XML_w, XML_em, FSNS( XML_w, XML_val ), pEmphasis, FSEND ); +} + +void DocxAttributeOutput::CharTwoLines( const SvxTwoLinesItem& rTwoLines ) +{ + if ( !rTwoLines.GetValue() ) + return; + + if (!m_pEastAsianLayoutAttrList) + m_pEastAsianLayoutAttrList = m_pSerializer->createAttrList(); + OString sTrue((sal_Char *)"true"); + m_pEastAsianLayoutAttrList->add(FSNS(XML_w, XML_combine), sTrue); + + sal_Unicode cStart = rTwoLines.GetStartBracket(); + sal_Unicode cEnd = rTwoLines.GetEndBracket(); + + if (!cStart && !cEnd) + return; + + OString sBracket; + if ((cStart == '{') || (cEnd == '}')) + sBracket = (sal_Char *)"curly"; + else if ((cStart == '<') || (cEnd == '>')) + sBracket = (sal_Char *)"angle"; + else if ((cStart == '[') || (cEnd == ']')) + sBracket = (sal_Char *)"square"; + else + sBracket = (sal_Char *)"round"; + m_pEastAsianLayoutAttrList->add(FSNS(XML_w, XML_combineBrackets), sBracket); +} + +void DocxAttributeOutput::CharScaleWidth( const SvxCharScaleWidthItem& rScaleWidth ) +{ + m_pSerializer->singleElementNS( XML_w, XML_w, + FSNS( XML_w, XML_val ), rtl::OString::valueOf( sal_Int32( rScaleWidth.GetValue() ) ).getStr(), FSEND ); +} + +void DocxAttributeOutput::CharRelief( const SvxCharReliefItem& rRelief ) +{ + switch ( rRelief.GetValue() ) + { + case RELIEF_EMBOSSED: + m_pSerializer->singleElementNS( XML_w, XML_emboss, FSEND ); + break; + case RELIEF_ENGRAVED: + m_pSerializer->singleElementNS( XML_w, XML_imprint, FSEND ); + break; + default: + m_pSerializer->singleElementNS( XML_w, XML_emboss, FSNS( XML_w, XML_val ), "false", FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_imprint, FSNS( XML_w, XML_val ), "false", FSEND ); + break; + } +} + +void DocxAttributeOutput::CharHidden( const SvxCharHiddenItem& rHidden ) +{ + if ( rHidden.GetValue() ) + m_pSerializer->singleElementNS( XML_w, XML_vanish, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_vanish, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +void DocxAttributeOutput::TextINetFormat( const SwFmtINetFmt& rLink ) +{ + const SwTxtINetFmt* pINetFmt = rLink.GetTxtINetFmt(); + const SwCharFmt* pCharFmt = pINetFmt->GetCharFmt(); + + OString aStyleId( "style" ); + aStyleId += OString::valueOf( sal_Int32( m_rExport.GetId( *pCharFmt ) ) ); + + m_pSerializer->singleElementNS( XML_w, XML_rStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND ); +} + +void DocxAttributeOutput::TextCharFormat( const SwFmtCharFmt& rCharFmt ) +{ + OString aStyleId( "style" ); + aStyleId += OString::valueOf( sal_Int32( m_rExport.GetId( *rCharFmt.GetCharFmt() ) ) ); + + m_pSerializer->singleElementNS( XML_w, XML_rStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND ); +} + +void DocxAttributeOutput::RefField( const SwField& rFld, const String& rRef ) +{ + sal_uInt16 nType = rFld.GetTyp( )->Which( ); + if ( nType == RES_GETEXPFLD ) + { + String sCmd = FieldString( ww::eREF ); + sCmd.APPEND_CONST_ASC( "\"" ); + sCmd += rRef; + sCmd.APPEND_CONST_ASC( "\" " ); + + m_rExport.OutputField( &rFld, ww::eREF, sCmd ); + } + + // There is nothing to do here for the set fields +} + +void DocxAttributeOutput::HiddenField( const SwField& /*rFld*/ ) +{ + OSL_TRACE( "TODO DocxAttributeOutput::HiddenField()\n" ); +} + +void DocxAttributeOutput::PostitField( const SwField* /* pFld*/ ) +{ + OSL_TRACE( "TODO DocxAttributeOutput::PostitField()\n" ); +} + +bool DocxAttributeOutput::DropdownField( const SwField* pFld ) +{ + bool bExpand = false; + + ww::eField eType = ww::eFORMDROPDOWN; + String sCmd = FieldString( eType ); + GetExport( ).OutputField( pFld, eType, sCmd ); + + return bExpand; +} + +void DocxAttributeOutput::SetField( const SwField& rFld, ww::eField eType, const String& rCmd ) +{ + // field bookmarks are handled in the EndRun method + GetExport().OutputField(&rFld, eType, rCmd ); +} + +void DocxAttributeOutput::WriteExpand( const SwField* pFld ) +{ + // Will be written in the next End Run + String sCmd; + m_rExport.OutputField( pFld, ww::eUNKNOWN, sCmd ); +} + +void DocxAttributeOutput::WriteField_Impl( const SwField* pFld, ww::eField eType, const String& rFldCmd, sal_uInt8 nMode ) +{ + struct FieldInfos infos; + infos.pField = pFld; + infos.sCmd = rFldCmd; + infos.eType = eType; + infos.bClose = WRITEFIELD_CLOSE & nMode; + infos.bOpen = WRITEFIELD_START & nMode; + m_Fields.push_back( infos ); + + if ( pFld ) + { + sal_uInt16 nType = pFld->GetTyp( )->Which( ); + sal_uInt16 nSubType = pFld->GetSubType(); + + // TODO Any other field types here ? + if ( ( nType == RES_SETEXPFLD ) && ( nSubType & nsSwGetSetExpType::GSE_STRING ) ) + { + const SwSetExpField *pSet = ( const SwSetExpField* )( pFld ); + m_sFieldBkm = pSet->GetPar1( ); + } + else if ( nType == RES_DROPDOWN ) + { + const SwDropDownField* pDropDown = ( const SwDropDownField* )( pFld ); + m_sFieldBkm = pDropDown->GetName( ); + } + } +} + +void DocxAttributeOutput::WriteFormData_Impl( const ::sw::mark::IFieldmark& rFieldmark ) +{ + if ( !m_Fields.empty() ) + m_Fields.begin()->pFieldmark = &rFieldmark; +} + +void DocxAttributeOutput::WriteBookmarks_Impl( std::vector< OUString >& rStarts, + std::vector< OUString >& rEnds ) +{ + for ( std::vector< OUString >::const_iterator it = rStarts.begin(), end = rStarts.end(); it < end; ++it ) + { + OString rName = OUStringToOString( *it, RTL_TEXTENCODING_UTF8 ).getStr( ); + m_rMarksStart.push_back( rName ); + } + rStarts.clear(); + + for ( std::vector< OUString >::const_iterator it = rEnds.begin(), end = rEnds.end(); it < end; ++it ) + { + OString rName = OUStringToOString( *it, RTL_TEXTENCODING_UTF8 ).getStr( ); + m_rMarksEnd.push_back( rName ); + } + rEnds.clear(); +} + +void DocxAttributeOutput::TextFootnote_Impl( const SwFmtFtn& rFootnote ) +{ + const SwEndNoteInfo& rInfo = rFootnote.IsEndNote()? + m_rExport.pDoc->GetEndNoteInfo(): m_rExport.pDoc->GetFtnInfo(); + + // footnote/endnote run properties + const SwCharFmt* pCharFmt = rInfo.GetAnchorCharFmt( *m_rExport.pDoc ); + + OString aStyleId( "style" ); + aStyleId += OString::valueOf( sal_Int32( m_rExport.GetId( *pCharFmt ) ) ); + + m_pSerializer->singleElementNS( XML_w, XML_rStyle, FSNS( XML_w, XML_val ), aStyleId.getStr(), FSEND ); + + // remember the footnote/endnote to + // 1) write the footnoteReference/endnoteReference in EndRunProperties() + // 2) be able to dump them all to footnotes.xml/endnotes.xml + if ( !rFootnote.IsEndNote() ) + m_pFootnotesList->add( rFootnote ); + else + m_pEndnotesList->add( rFootnote ); +} + +void DocxAttributeOutput::FootnoteEndnoteReference() +{ + sal_Int32 nId; + const SwFmtFtn *pFootnote = m_pFootnotesList->getCurrent( nId ); + + // both cannot be set at the same time - if they are, it's a bug + if ( !pFootnote ) + pFootnote = m_pEndnotesList->getCurrent( nId ); + + if ( !pFootnote ) + return; + + sal_Int32 nToken = pFootnote->IsEndNote()? XML_endnoteReference: XML_footnoteReference; + + // write it + if ( pFootnote->GetNumStr().Len() == 0 ) + { + // autonumbered + m_pSerializer->singleElementNS( XML_w, nToken, + FSNS( XML_w, XML_id ), ::rtl::OString::valueOf( nId ).getStr(), + FSEND ); + } + else + { + // not autonumbered + m_pSerializer->singleElementNS( XML_w, nToken, + FSNS( XML_w, XML_customMarkFollows ), "1", + FSNS( XML_w, XML_id ), ::rtl::OString::valueOf( nId ).getStr(), + FSEND ); + + RunText( pFootnote->GetNumStr() ); + } +} + +void DocxAttributeOutput::FootnotesEndnotes( bool bFootnotes ) +{ + const FootnotesVector& rVector = bFootnotes? m_pFootnotesList->getVector(): m_pEndnotesList->getVector(); + + sal_Int32 nBody = bFootnotes? XML_footnotes: XML_endnotes; + sal_Int32 nItem = bFootnotes? XML_footnote: XML_endnote; + + m_pSerializer->startElementNS( XML_w, nBody, + FSNS( XML_xmlns, XML_w ), "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + FSEND ); + + sal_Int32 nIndex = 0; + + // separator + m_pSerializer->startElementNS( XML_w, nItem, + FSNS( XML_w, XML_id ), OString::valueOf( nIndex++ ).getStr(), + FSNS( XML_w, XML_type ), "separator", + FSEND ); + m_pSerializer->startElementNS( XML_w, XML_p, FSEND ); + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_separator, FSEND ); + m_pSerializer->endElementNS( XML_w, XML_r ); + m_pSerializer->endElementNS( XML_w, XML_p ); + m_pSerializer->endElementNS( XML_w, nItem ); + + // separator + m_pSerializer->startElementNS( XML_w, nItem, + FSNS( XML_w, XML_id ), OString::valueOf( nIndex++ ).getStr(), + FSNS( XML_w, XML_type ), "continuationSeparator", + FSEND ); + m_pSerializer->startElementNS( XML_w, XML_p, FSEND ); + m_pSerializer->startElementNS( XML_w, XML_r, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_continuationSeparator, FSEND ); + m_pSerializer->endElementNS( XML_w, XML_r ); + m_pSerializer->endElementNS( XML_w, XML_p ); + m_pSerializer->endElementNS( XML_w, nItem ); + + // footnotes/endnotes themselves + for ( FootnotesVector::const_iterator i = rVector.begin(); i != rVector.end(); ++i, ++nIndex ) + { + m_pSerializer->startElementNS( XML_w, nItem, + FSNS( XML_w, XML_id ), OString::valueOf( nIndex ).getStr(), + FSEND ); + + const SwNodeIndex* pIndex = (*i)->GetTxtFtn()->GetStartNode(); + // tag required at the start of each footnote/endnote + m_footnoteEndnoteRefTag = bFootnotes ? XML_footnoteRef : XML_endnoteRef; + + m_rExport.WriteSpecialText( pIndex->GetIndex() + 1, + pIndex->GetNode().EndOfSectionIndex(), + bFootnotes? TXT_FTN: TXT_EDN ); + + m_pSerializer->endElementNS( XML_w, nItem ); + } + + m_pSerializer->endElementNS( XML_w, nBody ); + +} + +void DocxAttributeOutput::ParaLineSpacing_Impl( short nSpace, short nMulti ) +{ + if ( !m_pParagraphSpacingAttrList ) + m_pParagraphSpacingAttrList = m_pSerializer->createAttrList(); + + if ( nSpace < 0 ) + { + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_lineRule ), "exact" ); + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_line ), OString::valueOf( sal_Int32( -nSpace ) ) ); + } + else if( nMulti ) + { + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_lineRule ), "auto" ); + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_line ), OString::valueOf( sal_Int32( nSpace ) ) ); + } + else if ( nSpace > 0 ) + { + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_lineRule ), "atLeast" ); + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_line ), OString::valueOf( sal_Int32( nSpace ) ) ); + } + else + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_lineRule ), "auto" ); +} + +void DocxAttributeOutput::ParaAdjust( const SvxAdjustItem& rAdjust ) +{ + const char *pAdjustString; + + bool bEcma = GetExport().GetFilter().getVersion( ) == oox::core::ECMA_DIALECT; + + const SfxItemSet* pItems = GetExport().GetCurItemSet(); + const SvxFrameDirectionItem* rFrameDir = static_cast< const SvxFrameDirectionItem* >( pItems->GetItem( RES_FRAMEDIR ) ); + + bool bRtl = false; + short nDir = rFrameDir->GetValue(); + bRtl = ( nDir == FRMDIR_HORI_RIGHT_TOP ); + + if ( nDir == FRMDIR_ENVIRONMENT ) + nDir = GetExport( ).GetDefaultFrameDirection( ); + + switch ( rAdjust.GetAdjust() ) + { + case SVX_ADJUST_LEFT: + if ( bEcma ) + pAdjustString = "left"; + else if ( bRtl ) + pAdjustString = "end"; + else + pAdjustString = "start"; + break; + case SVX_ADJUST_RIGHT: + if ( bEcma ) + pAdjustString = "right"; + else if ( bRtl ) + pAdjustString = "start"; + else + pAdjustString = "end"; + break; + case SVX_ADJUST_BLOCKLINE: + case SVX_ADJUST_BLOCK: + pAdjustString = "both"; + break; + case SVX_ADJUST_CENTER: + pAdjustString = "center"; + break; + default: + return; // not supported attribute + } + m_pSerializer->singleElementNS( XML_w, XML_jc, FSNS( XML_w, XML_val ), pAdjustString, FSEND ); +} + +void DocxAttributeOutput::ParaSplit( const SvxFmtSplitItem& rSplit ) +{ + if (rSplit.GetValue()) + m_pSerializer->singleElementNS( XML_w, XML_keepLines, FSNS( XML_w, XML_val ), "false", FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_keepLines, FSEND ); +} + +void DocxAttributeOutput::ParaWidows( const SvxWidowsItem& rWidows ) +{ + if (rWidows.GetValue()) + m_pSerializer->singleElementNS( XML_w, XML_widowControl, FSEND ); + else + m_pSerializer->singleElementNS( XML_w, XML_widowControl, FSNS( XML_w, XML_val ), "false", FSEND ); +} + +static void impl_WriteTabElement( FSHelperPtr pSerializer, + const SvxTabStop& rTab, long nCurrentLeft ) +{ + FastAttributeList *pTabElementAttrList = pSerializer->createAttrList(); + + switch (rTab.GetAdjustment()) + { + case SVX_TAB_ADJUST_RIGHT: + pTabElementAttrList->add( FSNS( XML_w, XML_val ), OString( (sal_Char *)"right") ); + break; + case SVX_TAB_ADJUST_DECIMAL: + pTabElementAttrList->add( FSNS( XML_w, XML_val ), OString( (sal_Char *)"decimal") ); + break; + case SVX_TAB_ADJUST_CENTER: + pTabElementAttrList->add( FSNS( XML_w, XML_val ), OString( (sal_Char *)"center") ); + break; + case SVX_TAB_ADJUST_DEFAULT: + case SVX_TAB_ADJUST_LEFT: + default: + pTabElementAttrList->add( FSNS( XML_w, XML_val ), OString( (sal_Char *)"left") ); + break; + } + + pTabElementAttrList->add( FSNS( XML_w, XML_pos ), OString::valueOf( rTab.GetTabPos() + nCurrentLeft ) ); + + sal_Unicode cFillChar = rTab.GetFill(); + + if (sal_Unicode('.') == cFillChar ) + pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "dot" ) ); + else if ( sal_Unicode('-') == cFillChar ) + pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "hyphen" ) ); + else if ( sal_Unicode(0xB7) == cFillChar ) // middle dot + pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "middleDot" ) ); + else if ( sal_Unicode('_') == cFillChar ) + pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "underscore" ) ); + else + pTabElementAttrList->add( FSNS( XML_w, XML_leader ), OString( (sal_Char *) "none" ) ); + + pSerializer->singleElementNS( XML_w, XML_tab, pTabElementAttrList ); +} + +void DocxAttributeOutput::ParaTabStop( const SvxTabStopItem& rTabStop ) +{ + const SfxPoolItem* pLR = m_rExport.HasItem( RES_LR_SPACE ); + long nCurrentLeft = pLR ? ((const SvxLRSpaceItem*)pLR)->GetTxtLeft() : 0; + + m_pSerializer->startElementNS( XML_w, XML_tabs, FSEND ); + + sal_uInt16 nCount = rTabStop.Count(); + for (sal_uInt16 i = 0; i < nCount; i++ ) + impl_WriteTabElement( m_pSerializer, rTabStop[i], nCurrentLeft ); + + m_pSerializer->endElementNS( XML_w, XML_tabs ); +} + +void DocxAttributeOutput::ParaHyphenZone( const SvxHyphenZoneItem& rHyphenZone ) +{ + m_pSerializer->singleElementNS( XML_w, XML_suppressAutoHyphens, + FSNS( XML_w, XML_val ), rHyphenZone.IsHyphen( ) ? "false" : "true" , + FSEND ); +} + +void DocxAttributeOutput::ParaNumRule_Impl( const SwTxtNode* /*pTxtNd*/, sal_Int32 nLvl, sal_Int32 nNumId ) +{ + if ( USHRT_MAX != nNumId && 0 != nNumId ) + { + m_pSerializer->startElementNS( XML_w, XML_numPr, FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_ilvl, FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nLvl )).getStr(), FSEND ); + m_pSerializer->singleElementNS( XML_w, XML_numId, FSNS( XML_w, XML_val ), OString::valueOf( sal_Int32( nNumId )).getStr(), FSEND ); + m_pSerializer->endElementNS( XML_w, XML_numPr ); + } +} + +void DocxAttributeOutput::ParaScriptSpace( const SfxBoolItem& rScriptSpace ) +{ + sal_uInt16 nXmlElement = 0; + + switch ( rScriptSpace.Which( ) ) + { + case RES_PARATR_SCRIPTSPACE: + nXmlElement = XML_autoSpaceDE; + break; + case RES_PARATR_HANGINGPUNCTUATION: + nXmlElement = XML_overflowPunct; + break; + case RES_PARATR_FORBIDDEN_RULES: + nXmlElement = XML_kinsoku; + break; + } + + if ( nXmlElement ) + { + m_pSerializer->singleElementNS( XML_w, nXmlElement, + FSNS( XML_w, XML_val ), rScriptSpace.GetValue( ) ? "true": "false", + FSEND ); + } +} + +void DocxAttributeOutput::ParaVerticalAlign( const SvxParaVertAlignItem& rAlign ) +{ + const char *pAlignString; + + switch ( rAlign.GetValue() ) + { + case SvxParaVertAlignItem::BASELINE: + pAlignString = "baseline"; + break; + case SvxParaVertAlignItem::TOP: + pAlignString = "top"; + break; + case SvxParaVertAlignItem::CENTER: + pAlignString = "center"; + break; + case SvxParaVertAlignItem::BOTTOM: + pAlignString = "bottom"; + break; + case SvxParaVertAlignItem::AUTOMATIC: + pAlignString = "auto"; + break; + default: + return; // not supported attribute + } + m_pSerializer->singleElementNS( XML_w, XML_textAlignment, FSNS( XML_w, XML_val ), pAlignString, FSEND ); +} + +void DocxAttributeOutput::ParaSnapToGrid( const SvxParaGridItem& rGrid ) +{ + m_pSerializer->singleElementNS( XML_w, XML_snapToGrid, + FSNS( XML_w, XML_val ), rGrid.GetValue( ) ? "true": "false", + FSEND ); +} + +void DocxAttributeOutput::FormatFrameSize( const SwFmtFrmSize& rSize ) +{ + if ( m_rExport.bOutFlyFrmAttrs ) + { + if ( !m_pFlyAttrList ) + m_pFlyAttrList = m_pSerializer->createAttrList( ); + + if ( rSize.GetWidth() && rSize.GetWidthSizeType() == ATT_FIX_SIZE ) + { + m_pFlyAttrList->add( FSNS( XML_w, XML_w ), OString::valueOf( rSize.GetWidth( ) ) ); + } + + if ( rSize.GetHeight() ) + { + OString sRule( "exact" ); + if ( rSize.GetHeightSizeType() == ATT_MIN_SIZE ) + sRule = OString( "atLeast" ); + m_pFlyAttrList->add( FSNS( XML_w, XML_hRule ), sRule ); + m_pFlyAttrList->add( FSNS( XML_w, XML_h ), OString::valueOf( rSize.GetHeight( ) ) ); + } + } + else if ( m_rExport.bOutPageDescs ) + { + FastAttributeList *attrList = m_pSerializer->createAttrList( ); + if ( m_rExport.pAktPageDesc->GetLandscape( ) ) + attrList->add( FSNS( XML_w, XML_orient ), "landscape" ); + + attrList->add( FSNS( XML_w, XML_w ), OString::valueOf( rSize.GetWidth( ) ) ); + attrList->add( FSNS( XML_w, XML_h ), OString::valueOf( rSize.GetHeight( ) ) ); + + XFastAttributeListRef xAttrList( attrList ); + attrList = NULL; + + m_pSerializer->singleElementNS( XML_w, XML_pgSz, xAttrList ); + } +} + +void DocxAttributeOutput::FormatPaperBin( const SvxPaperBinItem& ) +{ + OSL_TRACE( "TODO DocxAttributeOutput::FormatPaperBin()\n" ); +} + +void DocxAttributeOutput::FormatLRSpace( const SvxLRSpaceItem& rLRSpace ) +{ + bool bEcma = m_rExport.GetFilter().getVersion( ) == oox::core::ECMA_DIALECT; + + if ( m_rExport.bOutFlyFrmAttrs ) + { + if ( !m_pFlyAttrList ) + m_pFlyAttrList = m_pSerializer->createAttrList(); + + m_pFlyAttrList->add( FSNS( XML_w, XML_hSpace ), + OString::valueOf( + sal_Int32( ( rLRSpace.GetLeft() + rLRSpace.GetRight() ) / 2 ) ) ); + } + else if ( m_rExport.bOutPageDescs ) + { + if ( !m_pSectionSpacingAttrList ) + m_pSectionSpacingAttrList = m_pSerializer->createAttrList(); + + sal_uInt16 nLDist, nRDist; + const SfxPoolItem* pItem = m_rExport.HasItem( RES_BOX ); + if ( pItem ) + { + nRDist = ((SvxBoxItem*)pItem)->CalcLineSpace( BOX_LINE_LEFT ); + nLDist = ((SvxBoxItem*)pItem)->CalcLineSpace( BOX_LINE_RIGHT ); + } + else + nLDist = nRDist = 0; + nLDist = nLDist + (sal_uInt16)rLRSpace.GetLeft(); + nRDist = nRDist + (sal_uInt16)rLRSpace.GetRight(); + + m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_left ), OString::valueOf( sal_Int32( nLDist ) ) ); + m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_right ), OString::valueOf( sal_Int32( nRDist ) ) ); + } + else + { + FastAttributeList *pLRSpaceAttrList = m_pSerializer->createAttrList(); + + pLRSpaceAttrList->add( FSNS( XML_w, ( bEcma ? XML_left : XML_start ) ), OString::valueOf( (sal_Int32) rLRSpace.GetTxtLeft() ) ); + pLRSpaceAttrList->add( FSNS( XML_w, ( bEcma ? XML_right : XML_end ) ), OString::valueOf( (sal_Int32) rLRSpace.GetRight() ) ); + + sal_Int32 nFirstLineAdjustment = rLRSpace.GetTxtFirstLineOfst(); + if (nFirstLineAdjustment > 0) + pLRSpaceAttrList->add( FSNS( XML_w, XML_firstLine ), OString::valueOf( nFirstLineAdjustment ) ); + else + pLRSpaceAttrList->add( FSNS( XML_w, XML_hanging ), OString::valueOf( - nFirstLineAdjustment ) ); + m_pSerializer->singleElementNS( XML_w, XML_ind, pLRSpaceAttrList ); + } +} + +void DocxAttributeOutput::FormatULSpace( const SvxULSpaceItem& rULSpace ) +{ + + if ( m_rExport.bOutFlyFrmAttrs ) + { + if ( !m_pFlyAttrList ) + m_pFlyAttrList = m_pSerializer->createAttrList(); + + m_pFlyAttrList->add( FSNS( XML_w, XML_vSpace ), + OString::valueOf( + sal_Int32( ( rULSpace.GetLower() + rULSpace.GetUpper() ) / 2 ) ) ); + } + else if (m_rExport.bOutPageDescs ) + { + OSL_ENSURE( m_rExport.GetCurItemSet(), "Impossible" ); + if ( !m_rExport.GetCurItemSet() ) + return; + + if ( !m_pSectionSpacingAttrList ) + m_pSectionSpacingAttrList = m_pSerializer->createAttrList(); + + HdFtDistanceGlue aDistances( *m_rExport.GetCurItemSet() ); + + sal_Int32 nHeader = 0; + if ( aDistances.HasHeader() ) + nHeader = sal_Int32( aDistances.dyaHdrTop ); + m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_header ), OString::valueOf( nHeader ) ); + + // Page top + m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_top ), + OString::valueOf( sal_Int32( aDistances.dyaTop ) ) ); + + sal_Int32 nFooter = 0; + if ( aDistances.HasFooter() ) + nFooter = sal_Int32( aDistances.dyaHdrBottom ); + m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_footer ), OString::valueOf( nFooter ) ); + + // Page Bottom + m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_bottom ), + OString::valueOf( sal_Int32( aDistances.dyaBottom ) ) ); + + // FIXME Page Gutter is not handled ATM, setting to 0 as it's mandatory for OOXML + m_pSectionSpacingAttrList->add( FSNS( XML_w, XML_gutter ), + OString::valueOf( sal_Int32( 0 ) ) ); + + } + else + { + if ( !m_pParagraphSpacingAttrList ) + m_pParagraphSpacingAttrList = m_pSerializer->createAttrList(); + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_before ), + OString::valueOf( (sal_Int32)rULSpace.GetUpper() ) ); + m_pParagraphSpacingAttrList->add( FSNS( XML_w, XML_after ), + OString::valueOf( (sal_Int32)rULSpace.GetLower() ) ); + } +} + +void DocxAttributeOutput::FormatSurround( const SwFmtSurround& rSurround ) +{ + if ( m_rExport.bOutFlyFrmAttrs ) + { + if ( !m_pFlyAttrList ) + m_pFlyAttrList = m_pSerializer->createAttrList(); + + OString sWrap( "auto" ); + switch ( rSurround.GetSurround( ) ) + { + case SURROUND_NONE: + sWrap = OString( "none" ); + break; + case SURROUND_THROUGHT: + sWrap = OString( "through" ); + break; + case SURROUND_IDEAL: + case SURROUND_PARALLEL: + case SURROUND_LEFT: + case SURROUND_RIGHT: + default: + sWrap = OString( "around" ); + } + + m_pFlyAttrList->add( FSNS( XML_w, XML_wrap ), sWrap ); + } +} + +void DocxAttributeOutput::FormatVertOrientation( const SwFmtVertOrient& rFlyVert ) +{ + if ( m_rExport.bOutFlyFrmAttrs ) + { + if ( !m_pFlyAttrList ) + m_pFlyAttrList = m_pSerializer->createAttrList(); + + OString sAlign; + switch( rFlyVert.GetVertOrient() ) + { + case text::VertOrientation::NONE: + break; + case text::VertOrientation::CENTER: + case text::VertOrientation::LINE_CENTER: + sAlign = OString( "center" ); + break; + case text::VertOrientation::BOTTOM: + case text::VertOrientation::LINE_BOTTOM: + sAlign = OString( "bottom" ); + break; + case text::VertOrientation::TOP: + case text::VertOrientation::LINE_TOP: + default: + sAlign = OString( "top" ); + break; + } + + if ( sAlign.getLength() > 0 ) + m_pFlyAttrList->add( FSNS( XML_w, XML_yAlign ), sAlign ); + else + m_pFlyAttrList->add( FSNS( XML_w, XML_y ), + OString::valueOf( sal_Int32( rFlyVert.GetPos() ) ) ); + + OString sVAnchor( "page" ); + switch ( rFlyVert.GetRelationOrient( ) ) + { + case text::RelOrientation::CHAR: + case text::RelOrientation::PRINT_AREA: + case text::RelOrientation::TEXT_LINE: + sVAnchor = OString( "column" ); + break; + case text::RelOrientation::FRAME: + case text::RelOrientation::PAGE_LEFT: + case text::RelOrientation::PAGE_RIGHT: + case text::RelOrientation::FRAME_LEFT: + case text::RelOrientation::FRAME_RIGHT: + sVAnchor = OString( "margin" ); + break; + case text::RelOrientation::PAGE_FRAME: + case text::RelOrientation::PAGE_PRINT_AREA: + default: + break; + } + + m_pFlyAttrList->add( FSNS( XML_w, XML_vAnchor ), sVAnchor ); + } +} + +void DocxAttributeOutput::FormatHorizOrientation( const SwFmtHoriOrient& rFlyHori ) +{ + if ( m_rExport.bOutFlyFrmAttrs ) + { + if ( !m_pFlyAttrList ) + m_pFlyAttrList = m_pSerializer->createAttrList(); + + OString sAlign; + switch( rFlyHori.GetHoriOrient() ) + { + case text::HoriOrientation::NONE: + break; + case text::HoriOrientation::LEFT: + sAlign = OString( rFlyHori.IsPosToggle( ) ? "inside" : "left" ); + break; + case text::HoriOrientation::RIGHT: + sAlign = OString( rFlyHori.IsPosToggle( ) ? "outside" : "right" ); + break; + case text::HoriOrientation::CENTER: + case text::HoriOrientation::FULL: // FULL only for tables + default: + sAlign = OString( "center" ); + break; + } + + if ( sAlign.getLength() > 0 ) + m_pFlyAttrList->add( FSNS( XML_w, XML_xAlign ), sAlign ); + else + m_pFlyAttrList->add( FSNS( XML_w, XML_x ), + OString::valueOf( sal_Int32( rFlyHori.GetPos() ) ) ); + + OString sHAnchor( "page" ); + switch ( rFlyHori.GetRelationOrient( ) ) + { + case text::RelOrientation::CHAR: + case text::RelOrientation::PRINT_AREA: + sHAnchor = OString( "text" ); + break; + case text::RelOrientation::FRAME: + case text::RelOrientation::PAGE_LEFT: + case text::RelOrientation::PAGE_RIGHT: + case text::RelOrientation::FRAME_LEFT: + case text::RelOrientation::FRAME_RIGHT: + sHAnchor = OString( "margin" ); + break; + case text::RelOrientation::PAGE_FRAME: + case text::RelOrientation::PAGE_PRINT_AREA: + default: + break; + } + + m_pFlyAttrList->add( FSNS( XML_w, XML_hAnchor ), sHAnchor ); + } +} + +void DocxAttributeOutput::FormatAnchor( const SwFmtAnchor& ) +{ + // Fly frames: anchors here aren't matching the anchors in docx +} + +void DocxAttributeOutput::FormatBackground( const SvxBrushItem& rBrush ) +{ + if ( !m_rExport.bOutPageDescs ) + { + OString sColor = impl_ConvertColor( rBrush.GetColor( ) ); + m_pSerializer->singleElementNS( XML_w, XML_shd, + FSNS( XML_w, XML_fill ), sColor.getStr( ), + FSNS( XML_w, XML_val ), "clear", + FSEND ); + } +} + +void DocxAttributeOutput::FormatBox( const SvxBoxItem& rBox ) +{ + + if ( !m_bOpenedSectPr ) + { + // Normally open the borders tag for paragraphs + m_pSerializer->startElementNS( XML_w, XML_pBdr, FSEND ); + } + + impl_pageBorders( m_pSerializer, rBox ); + + if ( m_bOpenedSectPr ) + { + // Special handling for pgBorder + m_pSerializer->mergeTopMarks( sax_fastparser::MERGE_MARKS_PREPEND ); + m_pSerializer->mergeTopMarks( ); + } + else + { + // Normally close the borders tag for paragraphs + m_pSerializer->endElementNS( XML_w, XML_pBdr ); + } +} + +void DocxAttributeOutput::FormatColumns_Impl( sal_uInt16 nCols, const SwFmtCol& rCol, bool bEven, SwTwips nPageSize ) +{ + // Get the columns attributes + FastAttributeList *pColsAttrList = m_pSerializer->createAttrList(); + + pColsAttrList->add( FSNS( XML_w, XML_num ), + OString::valueOf( sal_Int32( nCols ) ). getStr( ) ); + + const char* pEquals = "false"; + if ( bEven ) + { + sal_uInt16 nWidth = rCol.GetGutterWidth( true ); + pColsAttrList->add( FSNS( XML_w, XML_space ), + OString::valueOf( sal_Int32( nWidth ) ).getStr( ) ); + + pEquals = "true"; + } + + pColsAttrList->add( FSNS( XML_w, XML_equalWidth ), pEquals ); + + bool bHasSep = COLADJ_NONE == rCol.GetLineAdj( ); + pColsAttrList->add( FSNS( XML_w, XML_sep ), bHasSep ? "true" : "false" ); + + // Write the element + m_pSerializer->startElementNS( XML_w, XML_cols, pColsAttrList ); + + // Write the columns width if non-equals + const SwColumns & rColumns = rCol.GetColumns( ); + if ( !bEven ) + { + for ( sal_uInt16 n = 0; n < nCols; ++n ) + { + FastAttributeList *pColAttrList = m_pSerializer->createAttrList(); + sal_uInt16 nWidth = rCol.CalcPrtColWidth( n, ( sal_uInt16 ) nPageSize ); + pColAttrList->add( FSNS( XML_w, XML_w ), + OString::valueOf( sal_Int32( nWidth ) ).getStr( ) ); + + if ( n + 1 != nCols ) + { + sal_uInt16 nSpacing = rColumns[n]->GetRight( ) + rColumns[n + 1]->GetLeft( ); + pColAttrList->add( FSNS( XML_w, XML_space ), + OString::valueOf( sal_Int32( nSpacing ) ).getStr( ) ); + } + + m_pSerializer->singleElementNS( XML_w, XML_col, pColAttrList ); + } + } + + m_pSerializer->endElementNS( XML_w, XML_cols ); +} + +void DocxAttributeOutput::FormatKeep( const SvxFmtKeepItem& ) +{ + m_pSerializer->singleElementNS( XML_w, XML_keepNext, FSEND ); +} + +void DocxAttributeOutput::FormatTextGrid( const SwTextGridItem& rGrid ) +{ + FastAttributeList *pGridAttrList = m_pSerializer->createAttrList(); + + OString sGridType; + switch ( rGrid.GetGridType( ) ) + { + default: + case GRID_NONE: + sGridType = OString( "default" ); + break; + case GRID_LINES_ONLY: + sGridType = OString( "lines" ); + break; + case GRID_LINES_CHARS: + if ( rGrid.IsSnapToChars( ) ) + sGridType = OString( "snapToChars" ); + else + sGridType = OString( "linesAndChars" ); + break; + } + pGridAttrList->add( FSNS( XML_w, XML_type ), sGridType.getStr( ) ); + + sal_uInt16 nHeight = rGrid.GetBaseHeight() + rGrid.GetRubyHeight(); + pGridAttrList->add( FSNS( XML_w, XML_linePitch ), + OString::valueOf( sal_Int32( nHeight ) ).getStr( ) ); + + MSWordStyles * pStyles = m_rExport.pStyles; + SwFmt * pSwFmt = pStyles->GetSwFmt(); + + sal_uInt32 nPageCharSize = 0; + + if (pSwFmt != NULL) + { + nPageCharSize = ItemGet<SvxFontHeightItem> + (*pSwFmt, RES_CHRATR_FONTSIZE).GetHeight(); + } + + sal_uInt16 nPitch = rGrid.IsSquaredMode() ? rGrid.GetBaseHeight() : + rGrid.GetBaseWidth( ); + sal_Int32 nCharSpace = ( nPitch - nPageCharSize ) * 4096 / 20; + + pGridAttrList->add( FSNS( XML_w, XML_charSpace ), + OString::valueOf( sal_Int32( nCharSpace ) ).getStr( ) ); + + m_pSerializer->singleElementNS( XML_w, XML_docGrid, pGridAttrList ); +} + +void DocxAttributeOutput::FormatLineNumbering( const SwFmtLineNumber& rNumbering ) +{ + if ( !rNumbering.IsCount( ) ) + m_pSerializer->singleElementNS( XML_w, XML_suppressLineNumbers, FSEND ); +} + +void DocxAttributeOutput::FormatFrameDirection( const SvxFrameDirectionItem& rDirection ) +{ + OString sTextFlow; + bool bBiDi = false; + short nDir = rDirection.GetValue(); + + if ( nDir == FRMDIR_ENVIRONMENT ) + nDir = GetExport( ).GetDefaultFrameDirection( ); + + switch ( nDir ) + { + default: + case FRMDIR_HORI_LEFT_TOP: + sTextFlow = OString( "lrTb" ); + break; + case FRMDIR_HORI_RIGHT_TOP: + sTextFlow = OString( "lrTb" ); + bBiDi = true; + break; + case FRMDIR_VERT_TOP_LEFT: // many things but not this one + case FRMDIR_VERT_TOP_RIGHT: + sTextFlow = OString( "tbRl" ); + break; + } + + if ( m_rExport.bOutPageDescs ) + { + m_pSerializer->singleElementNS( XML_w, XML_textDirection, + FSNS( XML_w, XML_val ), sTextFlow.getStr( ), + FSEND ); + if ( bBiDi ) + m_pSerializer->singleElementNS( XML_w, XML_bidi, FSEND ); + } + else if ( !m_rExport.bOutFlyFrmAttrs ) + { + if ( bBiDi ) + m_pSerializer->singleElementNS( XML_w, XML_bidi, FSEND ); + } +} + +DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, FSHelperPtr pSerializer, oox::drawingml::DrawingML* pDrawingML ) + : m_rExport( rExport ), + m_pSerializer( pSerializer ), + m_rDrawingML( *pDrawingML ), + m_pFontsAttrList( NULL ), + m_pEastAsianLayoutAttrList( NULL ), + m_pCharLangAttrList( NULL ), + m_pSectionSpacingAttrList( NULL ), + m_pParagraphSpacingAttrList( NULL ), + m_pHyperlinkAttrList( NULL ), + m_pFlyAttrList( NULL ), + m_pFootnotesList( new ::docx::FootnotesList() ), + m_pEndnotesList( new ::docx::FootnotesList() ), + m_footnoteEndnoteRefTag( 0 ), + m_pSectionInfo( NULL ), + m_pRedlineData( NULL ), + m_nRedlineId( 0 ), + m_bOpenedSectPr( false ), + m_sFieldBkm( ), + m_nNextMarkId( 0 ), + m_pTableWrt( NULL ), + m_bTableCellOpen( false ), + m_nTableDepth( 0 ), + m_bParagraphOpened( false ), + m_nColBreakStatus( COLBRK_NONE ), + m_pParentFrame( NULL ) +{ +} + +DocxAttributeOutput::~DocxAttributeOutput() +{ + delete m_pFontsAttrList, m_pFontsAttrList = NULL; + delete m_pEastAsianLayoutAttrList, m_pEastAsianLayoutAttrList = NULL; + delete m_pCharLangAttrList, m_pCharLangAttrList = NULL; + delete m_pSectionSpacingAttrList, m_pSectionSpacingAttrList = NULL; + delete m_pParagraphSpacingAttrList, m_pParagraphSpacingAttrList = NULL; + delete m_pHyperlinkAttrList, m_pHyperlinkAttrList = NULL; + delete m_pFlyAttrList, m_pFlyAttrList = NULL; + + delete m_pFootnotesList, m_pFootnotesList = NULL; + delete m_pEndnotesList, m_pEndnotesList = NULL; + + delete m_pTableWrt, m_pTableWrt = NULL; + m_pParentFrame = NULL; +} + +DocxExport& DocxAttributeOutput::GetExport() +{ + return m_rExport; +} + +bool DocxAttributeOutput::HasFootnotes() +{ + return !m_pFootnotesList->isEmpty(); +} + +bool DocxAttributeOutput::HasEndnotes() +{ + return !m_pEndnotesList->isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |