diff options
Diffstat (limited to 'sw/source/filter/ww8/wrtw8nds.cxx')
-rw-r--r-- | sw/source/filter/ww8/wrtw8nds.cxx | 2722 |
1 files changed, 2722 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx new file mode 100644 index 000000000000..76ad1dc354ea --- /dev/null +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -0,0 +1,2722 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ + +#include <vector> +#include <list> +#include <utility> +#include <algorithm> +#include <functional> +#include <iostream> +#if OSL_DEBUG_LEVEL > 0 +# include <cstdio> +#endif + +#include <hintids.hxx> +#include <tools/urlobj.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/svxfont.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/tstpitem.hxx> +#include "svl/urihelper.hxx" +#include <svl/whiter.hxx> +#include <fmtpdsc.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> +#include <fmtlsplt.hxx> +#include <fmtflcnt.hxx> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <frmatr.hxx> +#include <paratr.hxx> +#include <txatbase.hxx> +#include <fmtinfmt.hxx> +#include <fmtrfmrk.hxx> +#include <fchrfmt.hxx> +#include <fmtautofmt.hxx> +#include <charfmt.hxx> +#include <tox.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <swtable.hxx> +#include <section.hxx> +#include <pagedesc.hxx> +#include <swrect.hxx> +#include <reffld.hxx> +#include <redline.hxx> +#include <wrtswtbl.hxx> +#include <htmltbl.hxx> +#include <txttxmrk.hxx> +#include <fmtline.hxx> +#include <fmtruby.hxx> +#include <breakit.hxx> +#include <txtatr.hxx> +#include <fmtsrnd.hxx> +#include <fmtrowsplt.hxx> +#include <com/sun/star/i18n/ScriptType.hdl> +#include <com/sun/star/i18n/WordType.hpp> + +#include <writerfilter/doctok/sprmids.hxx> + +#include "writerhelper.hxx" +#include "writerwordglue.hxx" +#include <numrule.hxx> +#include "wrtww8.hxx" +#include "ww8par.hxx" +#include <IMark.hxx> +#include "ww8attributeoutput.hxx" + +#include <ndgrf.hxx> +#include <ndole.hxx> +#include <cstdio> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::i18n; +using namespace sw::util; +using namespace sw::types; +using namespace sw::mark; +using namespace nsFieldFlags; + + +static String lcl_getFieldCode( const IFieldmark* pFieldmark ) { + ASSERT(pFieldmark!=NULL, "where is my fieldmark???"); + if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) ) { + return String::CreateFromAscii(" FORMTEXT "); + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) { + return String::CreateFromAscii(" FORMDROPDOWN "); + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) { + return String::CreateFromAscii(" FORMCHECKBOX "); + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_TOC ) ) { + return String::CreateFromAscii(" TOC "); + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) ) { + return String::CreateFromAscii(" HYPERLINK "); + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_PAGEREF ) ) { + return String::CreateFromAscii(" PAGEREF "); + } else { + return pFieldmark->GetFieldname(); + } +} + +ww::eField lcl_getFieldId( const IFieldmark* pFieldmark ) { + ASSERT(pFieldmark!=NULL, "where is my fieldmark???"); + if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) ) { + return ww::eFORMTEXT; + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) ) { + return ww::eFORMDROPDOWN; + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ) ) { + return ww::eFORMCHECKBOX; + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_TOC ) ) { + return ww::eTOC; + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) ) { + return ww::eHYPERLINK; + } else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_PAGEREF ) ) { + return ww::ePAGEREF; + } else { + return ww::eUNKNOWN; + } +} + +/* */ + +MSWordAttrIter::MSWordAttrIter( MSWordExportBase& rExport ) + : pOld( rExport.pChpIter ), m_rExport( rExport ) +{ + m_rExport.pChpIter = this; +} + +MSWordAttrIter::~MSWordAttrIter() +{ + m_rExport.pChpIter = pOld; +} + +// Die Klasse SwAttrIter ist eine Hilfe zum Aufbauen der Fkp.chpx. +// Dabei werden nur Zeichen-Attribute beachtet; Absatz-Attribute brauchen +// diese Behandlung nicht. +// Die Absatz- und Textattribute des Writers kommen rein, und es wird +// mit Where() die naechste Position geliefert, an der sich die Attribute +// aendern. IsTxtAtr() sagt, ob sich an der mit Where() gelieferten Position +// ein Attribut ohne Ende und mit \xff im Text befindet. +// Mit OutAttr() werden die Attribute an der angegebenen SwPos +// ausgegeben. + +class SwAttrIter : public MSWordAttrIter +{ +private: + const SwTxtNode& rNd; + + CharRuns maCharRuns; + cCharRunIter maCharRunIter; + + rtl_TextEncoding meChrSet; + sal_uInt16 mnScript; + bool mbCharIsRTL; + + const SwRedline* pCurRedline; + xub_StrLen nAktSwPos; + USHORT nCurRedlinePos; + + bool mbParaIsRTL; + + const SwFmtDrop &mrSwFmtDrop; + + sw::Frames maFlyFrms; // #i2916# + sw::FrameIter maFlyIter; + + xub_StrLen SearchNext( xub_StrLen nStartPos ); + void FieldVanish( const String& rTxt ); + + void OutSwFmtRefMark(const SwFmtRefMark& rAttr, bool bStart); + + void IterToCurrent(); + + //No copying + SwAttrIter(const SwAttrIter&); + SwAttrIter& operator=(const SwAttrIter&); +public: + SwAttrIter( MSWordExportBase& rWr, const SwTxtNode& rNd ); + + bool IsTxtAttr( xub_StrLen nSwPos ); + bool IsRedlineAtEnd( xub_StrLen nPos ) const; + bool IsDropCap( int nSwPos ); + bool RequiresImplicitBookmark(); + + void NextPos() { nAktSwPos = SearchNext( nAktSwPos + 1 ); } + + void OutAttr( xub_StrLen nSwPos ); + virtual const SfxPoolItem* HasTextItem( USHORT nWhich ) const; + virtual const SfxPoolItem& GetItem( USHORT nWhich ) const; + int OutAttrWithRange(xub_StrLen nPos); + const SwRedlineData* GetRedline( xub_StrLen nPos ); + void OutFlys(xub_StrLen nSwPos); + + xub_StrLen WhereNext() const { return nAktSwPos; } + sal_uInt16 GetScript() const { return mnScript; } + bool IsCharRTL() const { return mbCharIsRTL; } + bool IsParaRTL() const { return mbParaIsRTL; } + rtl_TextEncoding GetCharSet() const { return meChrSet; } + String GetSnippet(const String &rStr, xub_StrLen nAktPos, + xub_StrLen nLen) const; + const SwFmtDrop& GetSwFmtDrop() const { return mrSwFmtDrop; } +}; + +class sortswflys : + public std::binary_function<const sw::Frame&, const sw::Frame&, bool> +{ +public: + bool operator()(const sw::Frame &rOne, const sw::Frame &rTwo) const + { + return rOne.GetPosition() < rTwo.GetPosition(); + } +}; + +void SwAttrIter::IterToCurrent() +{ + ASSERT(maCharRuns.begin() != maCharRuns.end(), "Impossible"); + mnScript = maCharRunIter->mnScript; + meChrSet = maCharRunIter->meCharSet; + mbCharIsRTL = maCharRunIter->mbRTL; +} + +SwAttrIter::SwAttrIter(MSWordExportBase& rWr, const SwTxtNode& rTxtNd) : + MSWordAttrIter(rWr), + rNd(rTxtNd), + maCharRuns(GetPseudoCharRuns(rTxtNd, 0, !rWr.HackIsWW8OrHigher())), + pCurRedline(0), + nAktSwPos(0), + nCurRedlinePos(USHRT_MAX), + mrSwFmtDrop(rTxtNd.GetSwAttrSet().GetDrop()) +{ + + SwPosition aPos(rTxtNd); + if (FRMDIR_HORI_RIGHT_TOP == rWr.pDoc->GetTextDirection(aPos)) + mbParaIsRTL = true; + else + mbParaIsRTL = false; + + maCharRunIter = maCharRuns.begin(); + IterToCurrent(); + + /* + #i2916# + Get list of any graphics which may be anchored from this paragraph. + */ + maFlyFrms = GetFramesInNode(rWr.maFrames, rNd); + std::sort(maFlyFrms.begin(), maFlyFrms.end(), sortswflys()); + + /* + #i18480# + If we are inside a frame then anything anchored inside this frame can + only be supported by word anchored inline ("as character"), so force + this in the supportable case. + */ + if (rWr.HackIsWW8OrHigher() && rWr.bInWriteEscher) + { + std::for_each(maFlyFrms.begin(), maFlyFrms.end(), + std::mem_fun_ref(&sw::Frame::ForceTreatAsInline)); + } + + maFlyIter = maFlyFrms.begin(); + + if ( m_rExport.pDoc->GetRedlineTbl().Count() ) + { + SwPosition aPosition( rNd, SwIndex( (SwTxtNode*)&rNd ) ); + pCurRedline = m_rExport.pDoc->GetRedline( aPosition, &nCurRedlinePos ); + } + + nAktSwPos = SearchNext(1); +} + +xub_StrLen lcl_getMinPos( xub_StrLen pos1, xub_StrLen pos2 ) +{ + xub_StrLen min = STRING_NOTFOUND; + if ( pos1 == STRING_NOTFOUND && pos2 != STRING_NOTFOUND ) + min = pos2; + else if ( pos2 == STRING_NOTFOUND && pos1 != STRING_NOTFOUND ) + min = pos1; + else if ( pos2 != STRING_NOTFOUND && pos2 != STRING_NOTFOUND ) + { + if ( pos1 < pos2 ) + min = pos1; + else + min = pos2; + } + + return min; +} + +xub_StrLen SwAttrIter::SearchNext( xub_StrLen nStartPos ) +{ + xub_StrLen nPos; + xub_StrLen nMinPos = STRING_MAXLEN; + xub_StrLen i=0; + + const String aTxt = rNd.GetTxt(); + xub_StrLen fieldEndPos = aTxt.Search(CH_TXT_ATR_FIELDEND, nStartPos); + xub_StrLen fieldStartPos = aTxt.Search(CH_TXT_ATR_FIELDSTART, nStartPos); + xub_StrLen formElementPos = aTxt.Search(CH_TXT_ATR_FORMELEMENT, nStartPos); + + xub_StrLen pos = lcl_getMinPos( fieldEndPos, fieldStartPos ); + pos = lcl_getMinPos( pos, formElementPos ); + + if (pos!=STRING_NOTFOUND) + nMinPos=pos; + + // first the redline, then the attributes + if( pCurRedline ) + { + const SwPosition* pEnd = pCurRedline->End(); + if (pEnd->nNode == rNd && ((i = pEnd->nContent.GetIndex()) >= nStartPos) && i < nMinPos ) + nMinPos = i; + } + + if ( nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().Count() ) + { + // nCurRedlinePos point to the next redline + nPos = nCurRedlinePos; + if( pCurRedline ) + ++nPos; + + for ( ; nPos < m_rExport.pDoc->GetRedlineTbl().Count(); ++nPos ) + { + const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nPos ]; + + const SwPosition* pStt = pRedl->Start(); + const SwPosition* pEnd = pStt == pRedl->GetPoint() + ? pRedl->GetMark() + : pRedl->GetPoint(); + + if( pStt->nNode == rNd ) + { + if( ( i = pStt->nContent.GetIndex() ) >= nStartPos && + i < nMinPos ) + nMinPos = i; + } + else + break; + + if( pEnd->nNode == rNd && + ( i = pEnd->nContent.GetIndex() ) < nMinPos && + i >= nStartPos ) + nMinPos = i; + } + } + + + if (mrSwFmtDrop.GetWholeWord() && nStartPos <= rNd.GetDropLen(0)) + nMinPos = rNd.GetDropLen(0); + else if(nStartPos <= mrSwFmtDrop.GetChars()) + nMinPos = mrSwFmtDrop.GetChars(); + + if(const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) + { + +// kann noch optimiert werden, wenn ausgenutzt wird, dass die TxtAttrs +// nach der Anfangsposition geordnet sind. Dann muessten +// allerdings noch 2 Indices gemerkt werden + for( i = 0; i < pTxtAttrs->Count(); i++ ) + { + const SwTxtAttr* pHt = (*pTxtAttrs)[i]; + nPos = *pHt->GetStart(); // gibt erstes Attr-Zeichen + if( nPos >= nStartPos && nPos <= nMinPos ) + nMinPos = nPos; + + if( pHt->GetEnd() ) // Attr mit Ende + { + nPos = *pHt->GetEnd(); // gibt letztes Attr-Zeichen + 1 + if( nPos >= nStartPos && nPos <= nMinPos ) + nMinPos = nPos; + } + if (pHt->HasDummyChar()) + { + // pos + 1 because of CH_TXTATR in Text + nPos = *pHt->GetStart() + 1; + if( nPos >= nStartPos && nPos <= nMinPos ) + nMinPos = nPos; + } + } + } + + if (maCharRunIter != maCharRuns.end()) + { + if (maCharRunIter->mnEndPos < nMinPos) + nMinPos = maCharRunIter->mnEndPos; + IterToCurrent(); + } + + /* + #i2916# + Check to see if there are any graphics anchored to characters in this + paragraph's text. Set nMinPos to 1 past the placement for anchored to + character because anchors in Word appear after the character they are + anchored to. + */ + if (maFlyIter != maFlyFrms.end()) + { + const SwPosition &rAnchor = maFlyIter->GetPosition(); + + nPos = rAnchor.nContent.GetIndex(); + if (nPos >= nStartPos && nPos <= nMinPos) + nMinPos = nPos; + + if (maFlyIter->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AT_CHAR) + { + ++nPos; + if (nPos >= nStartPos && nPos <= nMinPos) + nMinPos = nPos; + } + } + + //nMinPos found and not going to change at this point + + if (maCharRunIter != maCharRuns.end()) + { + if (maCharRunIter->mnEndPos == nMinPos) + ++maCharRunIter; + } + + return nMinPos; +} + +void SwAttrIter::OutAttr( xub_StrLen nSwPos ) +{ + m_rExport.AttrOutput().RTLAndCJKState( IsCharRTL(), GetScript() ); + + /* + Depending on whether text is in CTL/CJK or Western, get the id of that + script, the idea is that the font that is actually in use to render this + range of text ends up in pFont + */ + sal_uInt16 nFontId = GetWhichOfScript( RES_CHRATR_FONT, GetScript() ); + + const SvxFontItem &rParentFont = ItemGet<SvxFontItem>( + (const SwTxtFmtColl&)rNd.GetAnyFmtColl(), nFontId); + const SvxFontItem *pFont = &rParentFont; + + SfxItemSet aExportSet(*rNd.GetSwAttrSet().GetPool(), + RES_CHRATR_BEGIN, RES_TXTATR_END - 1); + + //The hard formatting properties that affect the entire paragraph + if (rNd.HasSwAttrSet()) + { + BOOL bDeep = FALSE; + // only copy hard attributes - bDeep = false + aExportSet.Set(rNd.GetSwAttrSet(), bDeep); + // get the current font item. Use rNd.GetSwAttrSet instead of aExportSet: + const SvxFontItem &rNdFont = ItemGet<SvxFontItem>(rNd.GetSwAttrSet(), nFontId); + pFont = &rNdFont; + aExportSet.ClearItem(nFontId); + } + + //The additional hard formatting properties that affect this range in the + //paragraph + sw::PoolItems aRangeItems; + if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) + { + for (xub_StrLen i = 0; i < pTxtAttrs->Count(); ++i) + { + const SwTxtAttr* pHt = (*pTxtAttrs)[i]; + const xub_StrLen* pEnd = pHt->GetEnd(); + + if (pEnd ? ( nSwPos >= *pHt->GetStart() && nSwPos < *pEnd) + : nSwPos == *pHt->GetStart() ) + { + sal_uInt16 nWhich = pHt->GetAttr().Which(); + if (nWhich == nFontId) + pFont = &(item_cast<SvxFontItem>(pHt->GetAttr())); + else if( nWhich == RES_TXTATR_AUTOFMT ) + { + const SwFmtAutoFmt& rAutoFmt = static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()); + const boost::shared_ptr<SfxItemSet> pSet = rAutoFmt.GetStyleHandle(); + SfxWhichIter aIter( *pSet ); + const SfxPoolItem* pItem; + sal_uInt16 nWhichId = aIter.FirstWhich(); + while( nWhichId ) + { + if( SFX_ITEM_SET == pSet->GetItemState( nWhichId, FALSE, &pItem )) + { + if (nWhichId == nFontId) + pFont = &(item_cast<SvxFontItem>(*pItem)); + else + aRangeItems[nWhichId] = pItem; + } + nWhichId = aIter.NextWhich(); + } + } + else + aRangeItems[nWhich] = (&(pHt->GetAttr())); + } + else if (nSwPos < *pHt->GetStart()) + break; + } + } + + /* + For #i24291# we need to explictly remove any properties from the + aExportSet which a SwCharFmt would override, we can't rely on word doing + this for us like writer does + */ + const SwFmtCharFmt *pCharFmtItem = + HasItem< SwFmtCharFmt >( aRangeItems, RES_TXTATR_CHARFMT ); + if ( pCharFmtItem ) + ClearOverridesFromSet( *pCharFmtItem, aExportSet ); + + sw::PoolItems aExportItems; + GetPoolItems( aExportSet, aExportItems ); + + sw::cPoolItemIter aEnd = aRangeItems.end(); + for ( sw::cPoolItemIter aI = aRangeItems.begin(); aI != aEnd; ++aI ) + aExportItems[aI->first] = aI->second; + + if ( !aExportItems.empty() ) + { + const SwModify* pOldMod = m_rExport.pOutFmtNode; + m_rExport.pOutFmtNode = &rNd; + m_rExport.m_aCurrentCharPropStarts.push( nSwPos ); + + m_rExport.ExportPoolItemsToCHP( aExportItems, GetScript() ); + + // HasTextItem nur in dem obigen Bereich erlaubt + m_rExport.m_aCurrentCharPropStarts.pop(); + m_rExport.pOutFmtNode = pOldMod; + } + + ASSERT( pFont, "must be *some* font associated with this txtnode" ); + if ( pFont ) + { + SvxFontItem aFont( *pFont ); + + /* + If we are a nonunicode aware format then we set the charset we want to + use for export of this range. If necessary this will generate a pseudo + font to use for this range. + + So now we are guaranteed to have a font with the correct charset set + for WW6/95 which will match the script we have exported this range in, + this makes older nonunicode aware versions of word display the correct + characters. + */ + if ( !m_rExport.HackIsWW8OrHigher() ) + aFont.GetCharSet() = GetCharSet(); + + if ( rParentFont != aFont ) + m_rExport.AttrOutput().OutputItem( aFont ); + } +} + +void SwAttrIter::OutFlys(xub_StrLen nSwPos) +{ + /* + #i2916# + May have an anchored graphic to be placed, loop through sorted array + and output all at this position + */ + while ( maFlyIter != maFlyFrms.end() ) + { + const SwPosition &rAnchor = maFlyIter->GetPosition(); + xub_StrLen nPos = rAnchor.nContent.GetIndex(); + + if ( nPos != nSwPos ) + break; + else + { + m_rExport.AttrOutput().OutputFlyFrame( *maFlyIter ); + ++maFlyIter; + } + } +} + +bool SwAttrIter::IsTxtAttr( xub_StrLen nSwPos ) +{ + // search for attrs with CH_TXTATR + if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) + { + for (USHORT i = 0; i < pTxtAttrs->Count(); ++i) + { + const SwTxtAttr* pHt = (*pTxtAttrs)[i]; + if ( pHt->HasDummyChar() && (*pHt->GetStart() == nSwPos) ) + return true; + } + } + + return false; +} + +bool SwAttrIter::IsDropCap( int nSwPos ) +{ + // see if the current position falls on a DropCap + int nDropChars = mrSwFmtDrop.GetChars(); + bool bWholeWord = mrSwFmtDrop.GetWholeWord(); + if (bWholeWord) + { + short nWordLen = rNd.GetDropLen(0); + if(nSwPos == nWordLen && nSwPos != 0) + return true; + } + else + { + if (nSwPos == nDropChars && nSwPos != 0) + return true; + } + return false; +} + +bool SwAttrIter::RequiresImplicitBookmark() +{ + SwImplBookmarksIter bkmkIterEnd = m_rExport.maImplicitBookmarks.end(); + for ( SwImplBookmarksIter aIter = m_rExport.maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter ) + { + ULONG sample = aIter->second; + + if ( sample == rNd.GetIndex() ) + return true; + } + return false; +} + +// HasItem ist fuer die Zusammenfassung des Doppel-Attributes Underline +// und WordLineMode als TextItems. OutAttr() ruft die Ausgabefunktion, +// die dann ueber HasItem() nach anderen Items an der +// Attribut-Anfangposition fragen kann. +// Es koennen nur Attribute mit Ende abgefragt werden. +// Es wird mit bDeep gesucht +const SfxPoolItem* SwAttrIter::HasTextItem( USHORT nWhich ) const +{ + const SfxPoolItem* pRet = 0; + const SwpHints* pTxtAttrs = rNd.GetpSwpHints(); + xub_StrLen nTmpSwPos = m_rExport.m_aCurrentCharPropStarts.top(); + if (pTxtAttrs) + { + for (USHORT i = 0; i < pTxtAttrs->Count(); ++i) + { + const SwTxtAttr* pHt = (*pTxtAttrs)[i]; + const SfxPoolItem* pItem = &pHt->GetAttr(); + const xub_StrLen* pAtrEnd = 0; + if( 0 != ( pAtrEnd = pHt->GetEnd() ) && // nur Attr mit Ende + nWhich == pItem->Which() && // + nTmpSwPos >= *pHt->GetStart() && nTmpSwPos < *pAtrEnd ) + { + pRet = pItem; // gefunden + break; + } + else if (nTmpSwPos < *pHt->GetStart()) + break; // dann kommt da nichts mehr + } + } + return pRet; +} + +void WW8Export::GetCurrentItems(WW8Bytes& rItems) const +{ + USHORT nEnd = pO ? pO->Count() : 0; + for (USHORT nI = 0; nI < nEnd; ++nI) + rItems.Insert((*pO)[nI], rItems.Count()); +} + +const SfxPoolItem& SwAttrIter::GetItem(USHORT nWhich) const +{ + const SfxPoolItem* pRet = HasTextItem(nWhich); + return pRet ? *pRet : rNd.SwCntntNode::GetAttr(nWhich); +} + +void WW8AttributeOutput::StartRuby( const SwTxtNode& rNode, const SwFmtRuby& rRuby ) +{ + String aStr( FieldString( ww::eEQ ) ); + aStr.APPEND_CONST_ASC( "\\* jc" ); + sal_Int32 nJC = 0; + sal_Char cDirective = 0; + switch ( rRuby.GetAdjustment() ) + { + case 0: + nJC = 3; + cDirective = 'l'; + break; + case 1: + //defaults to 0 + break; + case 2: + nJC = 4; + cDirective = 'r'; + break; + case 3: + nJC = 1; + cDirective = 'd'; + break; + case 4: + nJC = 2; + cDirective = 'd'; + break; + default: + ASSERT( !this,"Unhandled Ruby justication code" ); + break; + } + aStr += String::CreateFromInt32( nJC ); + + /* + MS needs to know the name and size of the font used in the ruby item, + but we coud have written it in a mixture of asian and western + scripts, and each of these can be a different font and size than the + other, so we make a guess based upon the first character of the text, + defaulting to asian. + */ + USHORT nRubyScript; + if( pBreakIt->GetBreakIter().is() ) + nRubyScript = pBreakIt->GetBreakIter()->getScriptType( rRuby.GetText(), 0); + else + nRubyScript = i18n::ScriptType::ASIAN; + + const SwTxtRuby* pRubyTxt = rRuby.GetTxtRuby(); + const SwCharFmt* pFmt = pRubyTxt ? pRubyTxt->GetCharFmt() : 0; + String sFamilyName; + long nHeight; + if ( pFmt ) + { + const SvxFontItem &rFont = ItemGet< SvxFontItem >( *pFmt, + GetWhichOfScript(RES_CHRATR_FONT,nRubyScript) ); + sFamilyName = rFont.GetFamilyName(); + + const SvxFontHeightItem &rHeight = ItemGet< SvxFontHeightItem >( *pFmt, + GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) ); + nHeight = rHeight.GetHeight(); + } + else + { + /*Get defaults if no formatting on ruby text*/ + + const SfxItemPool *pPool = rNode.GetSwAttrSet().GetPool(); + const SfxItemPool &rPool = pPool ? *pPool : m_rWW8Export.pDoc->GetAttrPool(); + + const SvxFontItem &rFont = DefaultItemGet< SvxFontItem >( rPool, + GetWhichOfScript( RES_CHRATR_FONT,nRubyScript ) ); + sFamilyName = rFont.GetFamilyName(); + + const SvxFontHeightItem &rHeight = DefaultItemGet< SvxFontHeightItem > + ( rPool, GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) ); + nHeight = rHeight.GetHeight(); + } + nHeight = (nHeight + 5)/10; + + aStr.APPEND_CONST_ASC( " \\* \"Font:" ); + aStr.Append( sFamilyName ); + aStr.APPEND_CONST_ASC( "\" \\* hps" ); + aStr += String::CreateFromInt32( nHeight ); + aStr.APPEND_CONST_ASC( " \\o" ); + if ( cDirective ) + { + aStr.APPEND_CONST_ASC( "\\a" ); + aStr.Append( cDirective ); + } + aStr.APPEND_CONST_ASC( "(\\s\\up " ); + + + if ( pBreakIt->GetBreakIter().is() ) + nRubyScript = pBreakIt->GetBreakIter()->getScriptType( rNode.GetTxt(), + *( pRubyTxt->GetStart() ) ); + else + nRubyScript = i18n::ScriptType::ASIAN; + + const SwAttrSet& rSet = rNode.GetSwAttrSet(); + const SvxFontHeightItem &rHeightItem = + ( const SvxFontHeightItem& )rSet.Get( + GetWhichOfScript( RES_CHRATR_FONTSIZE, nRubyScript ) ); + nHeight = (rHeightItem.GetHeight() + 10)/20-1; + aStr += String::CreateFromInt32(nHeight); + aStr += '('; + aStr += rRuby.GetText(); + aStr.APPEND_CONST_ASC( ");" ); + m_rWW8Export.OutputField( 0, ww::eEQ, aStr, + WRITEFIELD_START | WRITEFIELD_CMD_START ); +} + +void WW8AttributeOutput::EndRuby() +{ + m_rWW8Export.WriteChar( ')' ); + m_rWW8Export.OutputField( 0, ww::eEQ, aEmptyStr, WRITEFIELD_END | WRITEFIELD_CLOSE ); +} + +/*#i15387# Better ideas welcome*/ +String &TruncateBookmark( String &rRet ) +{ + if ( rRet.Len() > 40 ) + rRet.Erase( 40 ); + ASSERT( rRet.Len() <= 40, "Word cannot have bookmarks longer than 40 chars" ); + return rRet; +} + +bool AttributeOutputBase::AnalyzeURL( const String& rUrl, const String& /*rTarget*/, String* pLinkURL, String* pMark ) +{ + bool bBookMarkOnly = false; + + INetURLObject aURL( rUrl ); + String sMark; + String sURL; + + if ( rUrl.Len() > 1 && rUrl.GetChar(0) == INET_MARK_TOKEN ) + { + sMark = BookmarkToWriter( rUrl.Copy(1) ); + + xub_StrLen nPos = sMark.SearchBackward( cMarkSeperator ); + + String sRefType( sMark.Copy( nPos+1 ) ); + sRefType.EraseAllChars(); + + // i21465 Only interested in outline references + if ( sRefType.EqualsAscii( pMarkToOutline ) ) + { + String sLink = sMark.Copy(0, nPos); + SwImplBookmarksIter bkmkIterEnd = GetExport().maImplicitBookmarks.end(); + for ( SwImplBookmarksIter aIter = GetExport().maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter ) + { + String bkmkName = aIter->first; + + if ( bkmkName == sLink ) + { + sMark = String( RTL_CONSTASCII_STRINGPARAM( "_toc" ) ); + sMark += String::CreateFromInt32( aIter->second ); + } + } + } + } + else + { + sURL = aURL.GetURLNoMark( INetURLObject::DECODE_UNAMBIGUOUS ); + sMark = aURL.GetMark( INetURLObject::DECODE_UNAMBIGUOUS ); + + } + + if ( sMark.Len() && !sURL.Len() ) + bBookMarkOnly = true; + + + + *pMark = sMark; + *pLinkURL = sURL; + return bBookMarkOnly; +} + +bool WW8AttributeOutput::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; + + if ( sURL.Len() ) + sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL ); + + 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 WW8AttributeOutput::StartURL( const String &rUrl, const String &rTarget ) +{ + // hyperlinks only in WW8 + if ( !m_rWW8Export.bWrtWW8 ) + return false; + + INetURLObject aURL( rUrl ); + String sURL; + String sMark; + + bool bBookMarkOnly = AnalyzeURL( rUrl, rTarget, &sURL, &sMark ); + + + m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_START | WRITEFIELD_CMD_START ); + + // write the refence to the "picture" structure + ULONG nDataStt = m_rWW8Export.pDataStrm->Tell(); + m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell() ); + +// WinWord 2000 doesn't write this - so its a temp solution by W97 ? + m_rWW8Export.WriteChar( 0x01 ); + + static BYTE aArr1[] = { + 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation + + 0x06, 0x08, 0x01, // sprmCFData + 0x55, 0x08, 0x01, // sprmCFSpec + 0x02, 0x08, 0x01 // sprmCFFldVanish + }; + BYTE* pDataAdr = aArr1 + 2; + Set_UInt32( pDataAdr, nDataStt ); + + m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), sizeof( aArr1 ), aArr1 ); + + m_rWW8Export.OutputField( 0, ww::eHYPERLINK, sURL, WRITEFIELD_CMD_END ); + + // now write the picture structur + sURL = aURL.GetURLNoMark(); + + //all links end up in the data stream as absolute references. + bool bAbsolute = !bBookMarkOnly; + + static BYTE __READONLY_DATA aURLData1[] = { + 0,0,0,0, // len of struct + 0x44,0, // the start of "next" data + 0,0,0,0,0,0,0,0,0,0, // PIC-Structure! + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // | + 0,0,0,0, // / + }; + static BYTE __READONLY_DATA MAGIC_A[] = { + // start of "next" data + 0xD0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11, + 0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B + }; + + m_rWW8Export.pDataStrm->Write( aURLData1, sizeof( aURLData1 ) ); + BYTE nAnchor = 0x00; + if ( sMark.Len() ) + nAnchor = 0x08; + m_rWW8Export.pDataStrm->Write( &nAnchor, 1 ); + m_rWW8Export.pDataStrm->Write( MAGIC_A, sizeof(MAGIC_A) ); + SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 0x00000002); + UINT32 nFlag = bBookMarkOnly ? 0 : 0x01; + if ( bAbsolute ) + nFlag |= 0x02; + if ( sMark.Len() ) + nFlag |= 0x08; + SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nFlag ); + + INetProtocol eProto = aURL.GetProtocol(); + if ( eProto == INET_PROT_FILE ) + { + // version 1 (for a document) + + static BYTE __READONLY_DATA MAGIC_C[] = { + 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x00, 0x00 + }; + + static BYTE __READONLY_DATA MAGIC_D[] = { + 0xFF, 0xFF, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + // save the links to files as relative + sURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), sURL ); + if ( sURL.EqualsAscii( "/", 0, 1 ) ) + sURL = aURL.PathToFileName(); + + // special case for the absolute windows names + // (convert '/c:/foo/bar.doc' into 'c:\foo\bar.doc') + sal_Unicode aDrive = ( sURL.Len() > 1 )? sURL.GetChar( 1 ): 0; + if ( sURL.EqualsAscii( "/", 0, 1 ) && + ( ( aDrive >= 'A' && aDrive <= 'Z' ) || ( aDrive >= 'a' && aDrive <= 'z' ) ) && + sURL.EqualsAscii( ":", 2, 1 ) ) + { + sURL.Erase( 0, 1 ); + sURL.SearchAndReplaceAll( '/', '\\' ); + } + + m_rWW8Export.pDataStrm->Write( MAGIC_C, sizeof(MAGIC_C) ); + SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sURL.Len()+1 ); + SwWW8Writer::WriteString8( *m_rWW8Export.pDataStrm, sURL, true, + RTL_TEXTENCODING_MS_1252 ); + m_rWW8Export.pDataStrm->Write( MAGIC_D, sizeof( MAGIC_D ) ); + + SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() + 6 ); + SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2*sURL.Len() ); + SwWW8Writer::WriteShort( *m_rWW8Export.pDataStrm, 3 ); + SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, false ); + } + else if ( eProto != INET_PROT_NOT_VALID ) + { + // version 2 (simple url) + // an write some data to the data stream, but dont ask + // what the data mean, except for the URL. + // The First piece is the WW8_PIC structure. + // + static BYTE __READONLY_DATA MAGIC_B[] = { + 0xE0,0xC9,0xEA,0x79,0xF9,0xBA,0xCE,0x11, + 0x8C,0x82,0x00,0xAA,0x00,0x4B,0xA9,0x0B + }; + + m_rWW8Export.pDataStrm->Write( MAGIC_B, sizeof(MAGIC_B) ); + SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 2 * ( sURL.Len() + 1 ) ); + SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sURL, true ); + } + + if ( sMark.Len() ) + { + SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, sMark.Len()+1 ); + SwWW8Writer::WriteString16( *m_rWW8Export.pDataStrm, sMark, true ); + } + SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, nDataStt, + m_rWW8Export.pDataStrm->Tell() - nDataStt ); + + return true; +} + +bool WW8AttributeOutput::EndURL() +{ + // hyperlinks only in WW8 + if ( !m_rWW8Export.bWrtWW8 ) + return false; + + m_rWW8Export.OutputField( 0, ww::eHYPERLINK, aEmptyStr, WRITEFIELD_CLOSE ); + + return true; +} + +String BookmarkToWord(const String &rBookmark) +{ + String sRet(INetURLObject::encode(rBookmark, + INetURLObject::PART_REL_SEGMENT_EXTRA, '%', + INetURLObject::ENCODE_ALL, RTL_TEXTENCODING_ASCII_US)); + return TruncateBookmark(sRet); +} + +String BookmarkToWriter(const String &rBookmark) +{ + return INetURLObject::decode(rBookmark, '%', + INetURLObject::DECODE_UNAMBIGUOUS, RTL_TEXTENCODING_ASCII_US); +} + +void SwAttrIter::OutSwFmtRefMark(const SwFmtRefMark& rAttr, bool) +{ + if ( m_rExport.HasRefToObject( REF_SETREFATTR, &rAttr.GetRefName(), 0 ) ) + m_rExport.AppendBookmark( m_rExport.GetBookmarkName( REF_SETREFATTR, + &rAttr.GetRefName(), 0 )); +} + +void WW8AttributeOutput::FieldVanish( const String& rTxt, ww::eField /*eType*/ ) +{ + WW8Bytes aItems; + m_rWW8Export.GetCurrentItems( aItems ); + + // sprmCFFldVanish + if ( m_rWW8Export.bWrtWW8 ) + SwWW8Writer::InsUInt16( aItems, NS_sprm::LN_CFFldVanish ); + else + aItems.Insert( 67, aItems.Count() ); + aItems.Insert( 1, aItems.Count() ); + + USHORT nStt_sprmCFSpec = aItems.Count(); + + // sprmCFSpec -- fSpec-Attribut true + if ( m_rWW8Export.bWrtWW8 ) + SwWW8Writer::InsUInt16( aItems, 0x855 ); + else + aItems.Insert( 117, aItems.Count() ); + aItems.Insert( 1, aItems.Count() ); + + m_rWW8Export.WriteChar( '\x13' ); + m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.Count(), + aItems.GetData() ); + m_rWW8Export.OutSwString( rTxt, 0, rTxt.Len(), m_rWW8Export.IsUnicode(), + RTL_TEXTENCODING_MS_1252 ); + m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), nStt_sprmCFSpec, + aItems.GetData() ); + m_rWW8Export.WriteChar( '\x15' ); + m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), aItems.Count(), + aItems.GetData() ); +} + +void AttributeOutputBase::TOXMark( const SwTxtNode& rNode, const SwTOXMark& rAttr ) +{ + // its a field; so get the Text form the Node and build the field + String sTxt; + ww::eField eType = ww::eNONE; + + const SwTxtTOXMark& rTxtTOXMark = *rAttr.GetTxtTOXMark(); + const xub_StrLen* pTxtEnd = rTxtTOXMark.GetEnd(); + if ( pTxtEnd ) // has range? + { + sTxt = rNode.GetExpandTxt( *rTxtTOXMark.GetStart(), + *pTxtEnd - *rTxtTOXMark.GetStart() ); + } + else + sTxt = rAttr.GetAlternativeText(); + + switch ( rAttr.GetTOXType()->GetType() ) + { + case TOX_INDEX: + eType = ww::eXE; + if ( rAttr.GetPrimaryKey().Len() ) + { + if ( rAttr.GetSecondaryKey().Len() ) + { + sTxt.Insert( ':', 0 ); + sTxt.Insert( rAttr.GetSecondaryKey(), 0 ); + } + + sTxt.Insert( ':', 0 ); + sTxt.Insert( rAttr.GetPrimaryKey(), 0 ); + } + sTxt.InsertAscii( " XE \"", 0 ); + sTxt.InsertAscii( "\" " ); + break; + + case TOX_USER: + ( sTxt.APPEND_CONST_ASC( "\" \\f \"" ) ) + += (sal_Char)( 'A' + GetExport( ).GetId( *rAttr.GetTOXType() ) ); + // fall through - no break; + case TOX_CONTENT: + { + eType = ww::eTC; + sTxt.InsertAscii( " TC \"", 0 ); + USHORT nLvl = rAttr.GetLevel(); + if (nLvl > WW8ListManager::nMaxLevel) + nLvl = WW8ListManager::nMaxLevel; + + ((sTxt.APPEND_CONST_ASC( "\" \\l " )) + += String::CreateFromInt32( nLvl )) += ' '; + } + break; + default: + ASSERT( !this, "Unhandled option for toc export" ); + break; + } + + if ( sTxt.Len() ) + FieldVanish( sTxt, eType ); +} + +int SwAttrIter::OutAttrWithRange(xub_StrLen nPos) +{ + int nRet = 0; + if ( const SwpHints* pTxtAttrs = rNd.GetpSwpHints() ) + { + m_rExport.m_aCurrentCharPropStarts.push( nPos ); + const xub_StrLen* pEnd; + for ( USHORT i = 0; i < pTxtAttrs->Count(); ++i ) + { + const SwTxtAttr* pHt = (*pTxtAttrs)[i]; + const SfxPoolItem* pItem = &pHt->GetAttr(); + switch ( pItem->Which() ) + { + case RES_TXTATR_INETFMT: + if ( nPos == *pHt->GetStart() ) + { + const SwFmtINetFmt *rINet = static_cast< const SwFmtINetFmt* >( pItem ); + if ( m_rExport.AttrOutput().StartURL( rINet->GetValue(), rINet->GetTargetFrame() ) ) + ++nRet; + } + if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd ) + { + if ( m_rExport.AttrOutput().EndURL() ) + --nRet; + } + break; + case RES_TXTATR_REFMARK: + if ( nPos == *pHt->GetStart() ) + { + OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), true ); + ++nRet; + } + if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd ) + { + OutSwFmtRefMark( *static_cast< const SwFmtRefMark* >( pItem ), false ); + --nRet; + } + break; + case RES_TXTATR_TOXMARK: + if ( nPos == *pHt->GetStart() ) + m_rExport.AttrOutput().TOXMark( rNd, *static_cast< const SwTOXMark* >( pItem ) ); + break; + case RES_TXTATR_CJK_RUBY: + if ( nPos == *pHt->GetStart() ) + { + m_rExport.AttrOutput().StartRuby( rNd, *static_cast< const SwFmtRuby* >( pItem ) ); + ++nRet; + } + if ( 0 != ( pEnd = pHt->GetEnd() ) && nPos == *pEnd ) + { + m_rExport.AttrOutput().EndRuby(); + --nRet; + } + break; + } + } + m_rExport.m_aCurrentCharPropStarts.pop(); // HasTextItem nur in dem obigen Bereich erlaubt + } + return nRet; +} + +bool SwAttrIter::IsRedlineAtEnd( xub_StrLen nEnd ) const +{ + bool bRet = false; + // search next Redline + for( USHORT nPos = nCurRedlinePos; + nPos < m_rExport.pDoc->GetRedlineTbl().Count(); ++nPos ) + { + const SwPosition* pEnd = m_rExport.pDoc->GetRedlineTbl()[ nPos ]->End(); + if( pEnd->nNode == rNd ) + { + if( pEnd->nContent.GetIndex() == nEnd ) + { + bRet = true; + break; + } + } + else + break; + } + return bRet; +} + +const SwRedlineData* SwAttrIter::GetRedline( xub_StrLen nPos ) +{ + if( pCurRedline ) + { + const SwPosition* pEnd = pCurRedline->End(); + if( pEnd->nNode == rNd && + pEnd->nContent.GetIndex() <= nPos ) + { + pCurRedline = 0; + ++nCurRedlinePos; + } + else + { + // write data of current redline + return &( pCurRedline->GetRedlineData() ); + } + } + + if( !pCurRedline ) + { + // search next Redline + for( ; nCurRedlinePos < m_rExport.pDoc->GetRedlineTbl().Count(); + ++nCurRedlinePos ) + { + const SwRedline* pRedl = m_rExport.pDoc->GetRedlineTbl()[ nCurRedlinePos ]; + + const SwPosition* pStt = pRedl->Start(); + const SwPosition* pEnd = pStt == pRedl->GetPoint() + ? pRedl->GetMark() + : pRedl->GetPoint(); + + if( pStt->nNode == rNd ) + { + if( pStt->nContent.GetIndex() >= nPos ) + { + if( pStt->nContent.GetIndex() == nPos ) + { + // write data of this redline + pCurRedline = pRedl; + return &( pCurRedline->GetRedlineData() ); + } + break; + } + } + else + break; + + if( pEnd->nNode == rNd && + pEnd->nContent.GetIndex() < nPos ) + { + pCurRedline = pRedl; + break; + } + } + } + return NULL; +} + +/* */ + +short MSWordExportBase::GetCurrentPageDirection() const +{ + const SwFrmFmt &rFmt = pAktPageDesc + ? pAktPageDesc->GetMaster() + : const_cast<const SwDoc *>( pDoc )->GetPageDesc( 0 ).GetMaster(); + return rFmt.GetFrmDir().GetValue(); +} + +short MSWordExportBase::GetDefaultFrameDirection( ) const +{ + short nDir = FRMDIR_ENVIRONMENT; + + if ( bOutPageDescs ) + nDir = GetCurrentPageDirection( ); + else if ( pOutFmtNode ) + { + if ( bOutFlyFrmAttrs ) //frame + { + nDir = TrueFrameDirection( *( const SwFrmFmt * ) pOutFmtNode ); + } + else if ( pOutFmtNode->ISA( SwCntntNode ) ) //pagagraph + { + const SwCntntNode *pNd = ( const SwCntntNode * ) pOutFmtNode; + SwPosition aPos( *pNd ); + nDir = pDoc->GetTextDirection( aPos ); + } + else if ( pOutFmtNode->ISA( SwTxtFmtColl ) ) + nDir = FRMDIR_HORI_LEFT_TOP; //what else can we do :-( + } + + if ( nDir == FRMDIR_ENVIRONMENT ) + nDir = FRMDIR_HORI_LEFT_TOP; //Set something + + return nDir; +} + +short MSWordExportBase::TrueFrameDirection( const SwFrmFmt &rFlyFmt ) const +{ + const SwFrmFmt *pFlyFmt = &rFlyFmt; + const SvxFrameDirectionItem* pItem = 0; + while ( pFlyFmt ) + { + pItem = &pFlyFmt->GetFrmDir(); + if ( FRMDIR_ENVIRONMENT == pItem->GetValue() ) + { + pItem = 0; + const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor(); + if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) && + pAnchor->GetCntntAnchor() ) + { + pFlyFmt = pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt(); + } + else + pFlyFmt = 0; + } + else + pFlyFmt = 0; + } + + short nRet; + if ( pItem ) + nRet = pItem->GetValue(); + else + nRet = GetCurrentPageDirection(); + + ASSERT( nRet != FRMDIR_ENVIRONMENT, "leaving with environment direction" ); + return nRet; +} + +const SvxBrushItem* WW8Export::GetCurrentPageBgBrush() const +{ + const SwFrmFmt &rFmt = pAktPageDesc + ? pAktPageDesc->GetMaster() + : const_cast<const SwDoc *>(pDoc)->GetPageDesc(0).GetMaster(); + + const SfxPoolItem* pItem = 0; + //If not set, or "no fill", get real bg + SfxItemState eState = rFmt.GetItemState(RES_BACKGROUND, true, &pItem); + + const SvxBrushItem* pRet = (const SvxBrushItem*)pItem; + if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() && + pRet->GetColor() == COL_TRANSPARENT)) + { + pRet = &(DefaultItemGet<SvxBrushItem>(*pDoc,RES_BACKGROUND)); + } + return pRet; +} + +SvxBrushItem WW8Export::TrueFrameBgBrush(const SwFrmFmt &rFlyFmt) const +{ + const SwFrmFmt *pFlyFmt = &rFlyFmt; + const SvxBrushItem* pRet = 0; + + while (pFlyFmt) + { + //If not set, or "no fill", get real bg + const SfxPoolItem* pItem = 0; + SfxItemState eState = + pFlyFmt->GetItemState(RES_BACKGROUND, true, &pItem); + pRet = (const SvxBrushItem*)pItem; + if (SFX_ITEM_SET != eState || (!pRet->GetGraphic() && + pRet->GetColor() == COL_TRANSPARENT)) + { + pRet = 0; + const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor(); + if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) && + pAnchor->GetCntntAnchor()) + { + pFlyFmt = + pAnchor->GetCntntAnchor()->nNode.GetNode().GetFlyFmt(); + } + else + pFlyFmt = 0; + } + else + pFlyFmt = 0; + } + + if (!pRet) + pRet = GetCurrentPageBgBrush(); + + const Color aTmpColor( COL_WHITE ); + SvxBrushItem aRet( aTmpColor, RES_BACKGROUND ); + if (pRet && (pRet->GetGraphic() ||( pRet->GetColor() != COL_TRANSPARENT))) + aRet = *pRet; + + return aRet; +} + + +/* +Convert characters that need to be converted, the basic replacements and the +ridicously complicated title case attribute mapping to hardcoded upper case +because word doesn't have the feature +*/ +String SwAttrIter::GetSnippet(const String &rStr, xub_StrLen nAktPos, + xub_StrLen nLen) const +{ + String aSnippet(rStr, nAktPos, nLen); + if (!nLen) + return aSnippet; + + // 0x0a ( Hard Line Break ) -> 0x0b + // 0xad ( soft hyphen ) -> 0x1f + // 0x2011 ( hard hyphen ) -> 0x1e + aSnippet.SearchAndReplaceAll(0x0A, 0x0B); + aSnippet.SearchAndReplaceAll(CHAR_HARDHYPHEN, 0x1e); + aSnippet.SearchAndReplaceAll(CHAR_SOFTHYPHEN, 0x1f); + + m_rExport.m_aCurrentCharPropStarts.push( nAktPos ); + const SfxPoolItem &rItem = GetItem(RES_CHRATR_CASEMAP); + + if (SVX_CASEMAP_TITEL == ((const SvxCaseMapItem&)rItem).GetValue()) + { + sal_uInt16 nScriptType = i18n::ScriptType::LATIN; + if (pBreakIt->GetBreakIter().is()) + nScriptType = pBreakIt->GetBreakIter()->getScriptType(aSnippet, 0); + + LanguageType nLanguage; + switch (nScriptType) + { + case i18n::ScriptType::ASIAN: + nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CJK_LANGUAGE)).GetLanguage(); + break; + case i18n::ScriptType::COMPLEX: + nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_CTL_LANGUAGE)).GetLanguage(); + break; + case i18n::ScriptType::LATIN: + default: + nLanguage = ((const SvxLanguageItem&)GetItem(RES_CHRATR_LANGUAGE)).GetLanguage(); + break; + } + + SvxFont aFontHelper; + aFontHelper.SetCaseMap(SVX_CASEMAP_TITEL); + aFontHelper.SetLanguage(nLanguage); + aSnippet = aFontHelper.CalcCaseMap(aSnippet); + + //If we weren't at the begin of a word undo the case change. + //not done before doing the casemap because the sequence might start + //with whitespace + if (pBreakIt->GetBreakIter().is() && !pBreakIt->GetBreakIter()->isBeginWord( + rStr, nAktPos, pBreakIt->GetLocale(nLanguage), + i18n::WordType::ANYWORD_IGNOREWHITESPACES ) ) + { + aSnippet.SetChar(0, rStr.GetChar(nAktPos)); + } + } + m_rExport.m_aCurrentCharPropStarts.pop(); + + return aSnippet; +} + +/** Delivers the right paragraph style + + Because of the different style handling for delete operations, + the track changes have to be analysed. A deletion, starting in paragraph A + with style A, ending in paragraph B with style B, needs a hack. +*/ +static SwTxtFmtColl& lcl_getFormatCollection( MSWordExportBase& rExport, const SwTxtNode* pTxtNode ) +{ + USHORT nPos = 0; + USHORT nMax = rExport.pDoc->GetRedlineTbl().Count(); + while( nPos < nMax ) + { + const SwRedline* pRedl = rExport.pDoc->GetRedlineTbl()[ nPos++ ]; + const SwPosition* pStt = pRedl->Start(); + const SwPosition* pEnd = pStt == pRedl->GetPoint() + ? pRedl->GetMark() + : pRedl->GetPoint(); + // Looking for deletions, which ends in current pTxtNode + if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetRedlineData().GetType() && + pEnd->nNode == *pTxtNode && pStt->nNode != *pTxtNode && + pStt->nNode.GetNode().IsTxtNode() ) + { + pTxtNode = pStt->nNode.GetNode().GetTxtNode(); + nMax = nPos; + nPos = 0; + } + } + return static_cast<SwTxtFmtColl&>( pTxtNode->GetAnyFmtColl() ); +} + +void WW8AttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop &rSwFmtDrop, USHORT nStyle, + ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo, ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner ) +{ + short nDropLines = rSwFmtDrop.GetLines(); + short nDistance = rSwFmtDrop.GetDistance(); + int rFontHeight, rDropHeight, rDropDescent; + + SVBT16 nSty; + ShortToSVBT16( nStyle, nSty ); + m_rWW8Export.pO->Insert( (BYTE*)&nSty, 2, m_rWW8Export.pO->Count() ); // Style # + + if ( m_rWW8Export.bWrtWW8 ) + { + m_rWW8Export.InsUInt16( NS_sprm::LN_PPc ); // Alignment (sprmPPc) + m_rWW8Export.pO->Insert( 0x20, m_rWW8Export.pO->Count() ); + + m_rWW8Export.InsUInt16( NS_sprm::LN_PWr ); // Wrapping (sprmPWr) + m_rWW8Export.pO->Insert( 0x02, m_rWW8Export.pO->Count() ); + + m_rWW8Export.InsUInt16( NS_sprm::LN_PDcs ); // Dropcap (sprmPDcs) + int nDCS = ( nDropLines << 3 ) | 0x01; + m_rWW8Export.InsUInt16( static_cast< UINT16 >( nDCS ) ); + + m_rWW8Export.InsUInt16( NS_sprm::LN_PDxaFromText ); // Distance from text (sprmPDxaFromText) + m_rWW8Export.InsUInt16( nDistance ); + + if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) ) + { + m_rWW8Export.InsUInt16( NS_sprm::LN_PDyaLine ); // Line spacing + m_rWW8Export.InsUInt16( static_cast< UINT16 >( -rDropHeight ) ); + m_rWW8Export.InsUInt16( 0 ); + } + } + else + { + m_rWW8Export.pO->Insert( 29, m_rWW8Export.pO->Count() ); // Alignment (sprmPPc) + m_rWW8Export.pO->Insert( 0x20, m_rWW8Export.pO->Count() ); + + m_rWW8Export.pO->Insert( 37, m_rWW8Export.pO->Count() ); // Wrapping (sprmPWr) + m_rWW8Export.pO->Insert( 0x02, m_rWW8Export.pO->Count() ); + + m_rWW8Export.pO->Insert( 46, m_rWW8Export.pO->Count() ); // Dropcap (sprmPDcs) + int nDCS = ( nDropLines << 3 ) | 0x01; + m_rWW8Export.InsUInt16( static_cast< UINT16 >( nDCS ) ); + + m_rWW8Export.pO->Insert( 49, m_rWW8Export.pO->Count() ); // Distance from text (sprmPDxaFromText) + m_rWW8Export.InsUInt16( nDistance ); + + if (rNode.GetDropSize(rFontHeight, rDropHeight, rDropDescent)) + { + m_rWW8Export.pO->Insert( 20, m_rWW8Export.pO->Count() ); // Line spacing + m_rWW8Export.InsUInt16( static_cast< UINT16 >( -rDropHeight ) ); + m_rWW8Export.InsUInt16( 0 ); + } + } + + m_rWW8Export.WriteCR( pTextNodeInfoInner ); + + if ( pTextNodeInfo.get() != NULL ) + { +#ifdef DEBUG + ::std::clog << pTextNodeInfo->toString() << ::std::endl; +#endif + + TableInfoCell( pTextNodeInfoInner ); + } + + m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() ); + m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); + + if ( rNode.GetDropSize( rFontHeight, rDropHeight, rDropDescent ) ) + { + if ( m_rWW8Export.bWrtWW8 ) + { + const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt(); + if ( pSwCharFmt ) + { + m_rWW8Export.InsUInt16( NS_sprm::LN_CIstd ); + m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) ); + } + + m_rWW8Export.InsUInt16( NS_sprm::LN_CHpsPos ); // Lower the chars + m_rWW8Export.InsUInt16( static_cast< UINT16 >( -((nDropLines - 1)*rDropDescent) / 10 ) ); + + m_rWW8Export.InsUInt16( NS_sprm::LN_CHps ); // Font Size + m_rWW8Export.InsUInt16( static_cast< UINT16 >( rFontHeight / 10 ) ); + } + else + { + const SwCharFmt *pSwCharFmt = rSwFmtDrop.GetCharFmt(); + if ( pSwCharFmt ) + { + m_rWW8Export.InsUInt16( 80 ); + m_rWW8Export.InsUInt16( m_rWW8Export.GetId( *pSwCharFmt ) ); + } + + m_rWW8Export.pO->Insert( 101, m_rWW8Export.pO->Count() ); // Lower the chars + m_rWW8Export.InsUInt16( static_cast< UINT16 >( -((nDropLines - 1)*rDropDescent) / 10 ) ); + + m_rWW8Export.pO->Insert( 99, m_rWW8Export.pO->Count() ); // Font Size + m_rWW8Export.InsUInt16( static_cast< UINT16 >( rFontHeight / 10 ) ); + } + } + + m_rWW8Export.pChpPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() ); + m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); +} + +xub_StrLen MSWordExportBase::GetNextPos( SwAttrIter* aAttrIter, const SwTxtNode& /*rNode*/, xub_StrLen /*nAktPos*/ ) +{ + return aAttrIter->WhereNext(); +} + +void MSWordExportBase::UpdatePosition( SwAttrIter* aAttrIter, xub_StrLen /*nAktPos*/, xub_StrLen /*nEnd*/ ) +{ + aAttrIter->NextPos(); +} + +void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) +{ +#ifdef DEBUG + ::std::clog << "<OutWW8_SwTxtNode>" << ::std::endl; +#endif + + ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo( mpTableInfo->getTableNodeInfo( &rNode ) ); + + AttrOutput().StartParagraph( pTextNodeInfo ); + + bool bFlyInTable = mpParentFrame && bIsInTable; + + if ( !bFlyInTable ) + nStyleBeforeFly = GetId( lcl_getFormatCollection( *this, &rNode ) ); + + // nStyleBeforeFly may change when we recurse into another node, so we + // have to remember it in nStyle + USHORT nStyle = nStyleBeforeFly; + + SwAttrIter aAttrIter( *this, rNode ); + rtl_TextEncoding eChrSet = aAttrIter.GetCharSet(); + + if ( bStartTOX ) + { + // ignore TOX header section + const SwSectionNode* pSectNd = rNode.FindSectionNode(); + if ( pSectNd && TOX_CONTENT_SECTION == pSectNd->GetSection().GetType() ) + { + AttrOutput().StartTOX( pSectNd->GetSection() ); + m_aCurrentCharPropStarts.push( 0 ); + } + } + + const SwSection* pTOXSect = 0; + if( bInWriteTOX ) + { + // check for end of TOX + SwNodeIndex aIdx( rNode, 1 ); + if( !aIdx.GetNode().IsTxtNode() ) + { + const SwSectionNode* pTOXSectNd = rNode.FindSectionNode(); + pTOXSect = &pTOXSectNd->GetSection(); + + const SwNode* pNxt = rNode.GetNodes().GoNext( &aIdx ); + if( pNxt && pNxt->FindSectionNode() == pTOXSectNd ) + pTOXSect = 0; + } + } + + if ( aAttrIter.RequiresImplicitBookmark() ) + { + String sBkmkName = String( RTL_CONSTASCII_STRINGPARAM( "_toc" ) ); + sBkmkName += String::CreateFromInt32( rNode.GetIndex() ); + AppendWordBookmark( sBkmkName ); + } + + //Would need to move into WW8Export, probably not worth it + //ASSERT( pO->Count(), " pO ist am Zeilenanfang nicht leer" ); + + String aStr( rNode.GetTxt() ); + + xub_StrLen nAktPos = 0; + xub_StrLen nEnd = aStr.Len(); + bool bRedlineAtEnd = false; + int nOpenAttrWithRange = 0; + + ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner; + if ( pTextNodeInfo.get() != NULL ) + pTextNodeInfoInner = pTextNodeInfo->getFirstInner(); + + do { + const SwRedlineData* pRedlineData = aAttrIter.GetRedline( nAktPos ); + + AttrOutput().StartRun( pRedlineData ); + + xub_StrLen nNextAttr = GetNextPos( &aAttrIter, rNode, nAktPos ); + + if( nNextAttr > nEnd ) + nNextAttr = nEnd; + + aAttrIter.OutFlys( nAktPos ); + //Append bookmarks in this range after flys, exclusive of final + //position of this range + AppendBookmarks( rNode, nAktPos, nNextAttr - nAktPos ); + bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos ); + nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nAktPos); + + xub_StrLen nLen = nNextAttr - nAktPos; + if ( !bTxtAtr && nLen ) + { + sal_Unicode ch = aStr.GetChar( nAktPos ); + int ofs = ( ch == CH_TXT_ATR_FIELDSTART || ch == CH_TXT_ATR_FIELDEND || ch == CH_TXT_ATR_FORMELEMENT? 1: 0 ); + + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + if ( ch == CH_TXT_ATR_FIELDSTART ) + { + SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos + 1 ) ); + ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition ); + OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" ); + + if ( pFieldmark->GetFieldname().equalsAscii( ODF_FORMTEXT ) ) + AppendBookmark( pFieldmark->GetName(), false ); + OutputField( NULL, lcl_getFieldId( pFieldmark ), lcl_getFieldCode( pFieldmark ), WRITEFIELD_START | WRITEFIELD_CMD_START ); + if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMTEXT ) ) + WriteFormData( *pFieldmark ); + else if ( pFieldmark->GetFieldname( ).equalsAscii( ODF_HYPERLINK ) ) + WriteHyperlinkData( *pFieldmark ); + OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CMD_END ); + } + else if ( ch == CH_TXT_ATR_FIELDEND ) + { + SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) ); + ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition ); + OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" ); + + OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE ); + if ( pFieldmark->GetFieldname().equalsAscii( ODF_FORMTEXT ) ) + AppendBookmark( pFieldmark->GetName(), false ); + } + else if ( ch == CH_TXT_ATR_FORMELEMENT ) + { + SwPosition aPosition( rNode, SwIndex( const_cast< SwTxtNode* >( &rNode ), nAktPos ) ); + ::sw::mark::IFieldmark const * const pFieldmark = pMarkAccess->getFieldmarkFor( aPosition ); + OSL_ENSURE( pFieldmark, "Looks like this doc is broken...; where is the Fieldmark for the FIELDSTART??" ); + + bool isDropdownOrCheckbox = pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMDROPDOWN ) || + pFieldmark->GetFieldname( ).equalsAscii( ODF_FORMCHECKBOX ); + + if ( isDropdownOrCheckbox ) + AppendBookmark( pFieldmark->GetName(), 0 ); + OutputField( NULL, lcl_getFieldId( pFieldmark ), + lcl_getFieldCode( pFieldmark ), + WRITEFIELD_START | WRITEFIELD_CMD_START ); + if ( isDropdownOrCheckbox ) + WriteFormData( *pFieldmark ); + OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CLOSE ); + if ( isDropdownOrCheckbox ) + AppendBookmark( pFieldmark->GetName(), false ); + } + nLen -= static_cast< USHORT >( ofs ); + + String aSnippet( aAttrIter.GetSnippet( aStr, nAktPos + static_cast< USHORT >( ofs ), nLen ) ); + if ( ( nTxtTyp == TXT_EDN || nTxtTyp == TXT_FTN ) && nAktPos == 0 && nLen > 0 ) + { + // Insert tab for aesthetic puposes #i24762# + if ( aSnippet.GetChar( 0 ) != 0x09 ) + aSnippet.Insert( 0x09, 0 ); + } + AttrOutput().RunText( aSnippet, eChrSet ); + } + + if ( aAttrIter.IsDropCap( nNextAttr ) ) + AttrOutput().FormatDrop( rNode, aAttrIter.GetSwFmtDrop(), nStyle, pTextNodeInfo, pTextNodeInfoInner ); + + // At the end of line, output the attributes until the CR. + // Exception: footnotes at the end of line + if ( nNextAttr == nEnd ) + { + ASSERT( nOpenAttrWithRange >= 0, "odd to see this happening, expected >= 0" ); + if ( !bTxtAtr && nOpenAttrWithRange <= 0 ) + { + if ( aAttrIter.IsRedlineAtEnd( nEnd ) ) + bRedlineAtEnd = true; + else + { + // insert final graphic anchors if any before CR + aAttrIter.OutFlys( nEnd ); + // insert final bookmarks if any before CR and after flys + AppendBookmarks( rNode, nEnd, 1 ); + if ( pTOXSect ) + { + m_aCurrentCharPropStarts.pop(); + AttrOutput().EndTOX( *pTOXSect ); + } + WriteCR( pTextNodeInfoInner ); + } + } + } + + // Output the character attributes + AttrOutput().StartRunProperties(); + aAttrIter.OutAttr( nAktPos ); // nAktPos - 1 ?? + AttrOutput().EndRunProperties( pRedlineData ); + + // Exception: footnotes at the end of line + if ( nNextAttr == nEnd ) + { + ASSERT(nOpenAttrWithRange >= 0, + "odd to see this happening, expected >= 0"); + bool bAttrWithRange = (nOpenAttrWithRange > 0); + if ( nAktPos != nEnd ) + { + nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nEnd); + ASSERT(nOpenAttrWithRange == 0, + "odd to see this happening, expected 0"); + } + + AttrOutput().OutputFKP(); + + if ( bTxtAtr || bAttrWithRange || bRedlineAtEnd ) + { + // insert final graphic anchors if any before CR + aAttrIter.OutFlys( nEnd ); + // insert final bookmarks if any before CR and after flys + AppendBookmarks( rNode, nEnd, 1 ); + + if ( pTOXSect ) + { + m_aCurrentCharPropStarts.pop(); + AttrOutput().EndTOX( *pTOXSect ); + } + + WriteCR( pTextNodeInfoInner ); + + if ( bRedlineAtEnd ) + { + AttrOutput().Redline( aAttrIter.GetRedline( nEnd ) ); + AttrOutput().OutputFKP(); + } + } + } + + AttrOutput().EndRun(); + + nAktPos = nNextAttr; + UpdatePosition( &aAttrIter, nAktPos, nEnd ); + eChrSet = aAttrIter.GetCharSet(); + } + while ( nAktPos < nEnd ); + + AttrOutput().StartParagraphProperties( rNode ); + + AttrOutput().ParagraphStyle( nStyle ); + + if ( mpParentFrame && !bIsInTable ) // Fly-Attrs + OutputFormat( mpParentFrame->GetFrmFmt(), false, false, true ); + + if ( pTextNodeInfo.get() != NULL ) + { +#ifdef DEBUG + ::std::clog << pTextNodeInfo->toString() << ::std::endl; +#endif + + AttrOutput().TableInfoCell( pTextNodeInfoInner ); + } + + if ( !bFlyInTable ) + { + SfxItemSet* pTmpSet = 0; + const BYTE nPrvNxtNd = rNode.HasPrevNextLayNode(); + + if( (ND_HAS_PREV_LAYNODE|ND_HAS_NEXT_LAYNODE ) != nPrvNxtNd ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState( + RES_UL_SPACE, true, &pItem ) && + ( ( !( ND_HAS_PREV_LAYNODE & nPrvNxtNd ) && + ((SvxULSpaceItem*)pItem)->GetUpper()) || + ( !( ND_HAS_NEXT_LAYNODE & nPrvNxtNd ) && + ((SvxULSpaceItem*)pItem)->GetLower()) )) + { + pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() ); + SvxULSpaceItem aUL( *(SvxULSpaceItem*)pItem ); + // OD, MMAHER 2004-03-01 #i25901#- consider compatibility option + if (!pDoc->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES)) + { + if( !(ND_HAS_PREV_LAYNODE & nPrvNxtNd )) + aUL.SetUpper( 0 ); + } + // OD, MMAHER 2004-03-01 #i25901# - consider compatibility option + if (!pDoc->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS)) + { + if( !(ND_HAS_NEXT_LAYNODE & nPrvNxtNd )) + aUL.SetLower( 0 ); + } + pTmpSet->Put( aUL ); + } + } + + BOOL bParaRTL = FALSE; + const SvxFrameDirectionItem* pItem = (const SvxFrameDirectionItem*) + rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR); + if ( aAttrIter.IsParaRTL()) + bParaRTL = TRUE; + + if( rNode.IsNumbered()) + { + const SwNumRule* pRule = rNode.GetNumRule(); + BYTE nLvl = static_cast< BYTE >( rNode.GetActualListLevel() ); + const SwNumFmt* pFmt = pRule->GetNumFmt( nLvl ); + if( !pFmt ) + pFmt = &pRule->Get( nLvl ); + + if( !pTmpSet ) + pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() ); + + SvxLRSpaceItem aLR(ItemGet<SvxLRSpaceItem>(*pTmpSet, RES_LR_SPACE)); + // --> OD 2008-06-03 #i86652# + if ( pFmt->GetPositionAndSpaceMode() == + SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aLR.SetTxtLeft( aLR.GetTxtLeft() + pFmt->GetAbsLSpace() ); + } + // <-- + + if( rNode.IsNumbered() && rNode.IsCountedInList() ) + { + // --> OD 2008-06-03 #i86652# + if ( pFmt->GetPositionAndSpaceMode() == + SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + if (bParaRTL) + aLR.SetTxtFirstLineOfstValue(pFmt->GetAbsLSpace() - pFmt->GetFirstLineOffset()); + else + aLR.SetTxtFirstLineOfst(GetWordFirstLineOffset(*pFmt)); + } + // <-- + + // --> OD 2009-03-09 #100020# + // correct fix for issue i94187 + if (SFX_ITEM_SET != + pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) ) + { + // List style set via paragraph style - then put it into the itemset. + // This is needed to get list level and list id exported for + // the paragraph. + pTmpSet->Put( SwNumRuleItem( pRule->GetName() )); + + // Put indent values into the itemset in case that the list + // style is applied via paragraph style and the list level + // indent values are not applicable. + if ( pFmt->GetPositionAndSpaceMode() == + SvxNumberFormat::LABEL_ALIGNMENT && + !rNode.AreListLevelIndentsApplicable() ) + { + pTmpSet->Put( aLR ); + } + } + } + else + pTmpSet->ClearItem(RES_PARATR_NUMRULE); + + // --> OD 2008-06-03 #i86652# + if ( pFmt->GetPositionAndSpaceMode() == + SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + pTmpSet->Put(aLR); + + //#i21847# + SvxTabStopItem aItem( + ItemGet<SvxTabStopItem>(*pTmpSet, RES_PARATR_TABSTOP)); + SvxTabStop aTabStop(pFmt->GetAbsLSpace()); + aItem.Insert(aTabStop); + pTmpSet->Put(aItem); + + MSWordExportBase::CorrectTabStopInSet(*pTmpSet, pFmt->GetAbsLSpace()); + } + } + + /* + If a given para is using the FRMDIR_ENVIRONMENT direction we + cannot export that, its its ltr then that's ok as thats word's + default. Otherwise we must add a RTL attribute to our export list + */ + pItem = (const SvxFrameDirectionItem*) + rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR); + if ( + (!pItem || pItem->GetValue() == FRMDIR_ENVIRONMENT) && + aAttrIter.IsParaRTL() + ) + { + if ( !pTmpSet ) + pTmpSet = new SfxItemSet(rNode.GetSwAttrSet()); + + pTmpSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_RIGHT_TOP, RES_FRAMEDIR)); + } + // --> OD 2005-10-18 #126238# - move code for handling of numbered, + // but not counted paragraphs to this place. Otherwise, the paragraph + // isn't exported as numbered, but not counted, if no other attribute + // is found in <pTmpSet> + // #i44815# adjust numbering/indents for numbered paragraphs + // without number (NO_NUMLEVEL) + // #i47013# need to check rNode.GetNumRule()!=NULL as well. + if ( ! rNode.IsCountedInList() && rNode.GetNumRule()!=NULL ) + { + // WW8 does not know numbered paragraphs without number + // (NO_NUMLEVEL). In WW8AttributeOutput::ParaNumRule(), we will export + // the RES_PARATR_NUMRULE as list-id 0, which in WW8 means + // no numbering. Here, we will adjust the indents to match + // visually. + + if ( !pTmpSet ) + pTmpSet = new SfxItemSet(rNode.GetSwAttrSet()); + + // create new LRSpace item, based on the current (if present) + const SfxPoolItem* pPoolItem = NULL; + pTmpSet->GetItemState(RES_LR_SPACE, TRUE, &pPoolItem); + SvxLRSpaceItem aLRSpace( + ( pPoolItem == NULL ) + ? SvxLRSpaceItem(0, 0, 0, 0, RES_LR_SPACE) + : *static_cast<const SvxLRSpaceItem*>( pPoolItem ) ); + + // new left margin = old left + label space + const SwNumRule* pRule = rNode.GetNumRule(); + const SwNumFmt& rNumFmt = pRule->Get( static_cast< USHORT >(rNode.GetActualListLevel()) ); + // --> OD 2008-06-03 #i86652# + if ( rNumFmt.GetPositionAndSpaceMode() == + SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aLRSpace.SetTxtLeft( aLRSpace.GetLeft() + rNumFmt.GetAbsLSpace() ); + + // new first line indent = 0 + // (first line indent is ignored for NO_NUMLEVEL) + if (!bParaRTL) + aLRSpace.SetTxtFirstLineOfst( 0 ); + + // put back the new item + pTmpSet->Put( aLRSpace ); + } + // <-- + + // assure that numbering rule is in <pTmpSet> + if (SFX_ITEM_SET != pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) ) + { + pTmpSet->Put( SwNumRuleItem( pRule->GetName() )); + } + } + + // --> OD 2007-04-24 #i75457# + // Export page break after attribute from paragraph style. + // If page break attribute at the text node exist, an existing page + // break after at the paragraph style hasn't got to be considered. + if ( !rNode.GetpSwAttrSet() || + SFX_ITEM_SET != rNode.GetpSwAttrSet()->GetItemState(RES_BREAK, false) ) + { + const SvxFmtBreakItem* pBreakAtParaStyle = + &(ItemGet<SvxFmtBreakItem>(rNode.GetSwAttrSet(), RES_BREAK)); + if ( pBreakAtParaStyle && + pBreakAtParaStyle->GetBreak() == SVX_BREAK_PAGE_AFTER ) + { + if ( !pTmpSet ) + { + pTmpSet = new SfxItemSet(rNode.GetSwAttrSet()); + } + pTmpSet->Put( *pBreakAtParaStyle ); + } + else if( pTmpSet ) + { // Even a pagedesc item is set, the break item can be set 'NONE', + // this has to be overruled. + const SwFmtPageDesc& rPageDescAtParaStyle = + ItemGet<SwFmtPageDesc>( rNode, RES_PAGEDESC ); + if( rPageDescAtParaStyle.GetRegisteredIn() ) + pTmpSet->ClearItem( RES_BREAK ); + } + } + + // --> FME 2007-05-30 #i76520# Emulate non-splitting tables + if ( bOutTable ) + { + const SwTableNode* pTableNode = rNode.FindTableNode(); + + if ( pTableNode ) + { + const SwTable& rTable = pTableNode->GetTable(); + const SvxFmtKeepItem& rKeep = rTable.GetFrmFmt()->GetKeep(); + const bool bKeep = rKeep.GetValue(); + const bool bDontSplit = !bKeep ? + !rTable.GetFrmFmt()->GetLayoutSplit().GetValue() : + false; + + if ( bKeep || bDontSplit ) + { + // bKeep: set keep at first paragraphs in all lines + // bDontSplit : set keep at first paragraphs in all lines except from last line + // but only for non-complex tables + const SwTableBox* pBox = rNode.GetTblBox(); + const SwTableLine* pLine = pBox ? pBox->GetUpper() : 0; + + if ( pLine && !pLine->GetUpper() ) + { + // check if box is first in that line: + if ( 0 == pLine->GetTabBoxes().GetPos( pBox ) && pBox->GetSttNd() ) + { + // check if paragraph is first in that line: + if ( 1 == ( rNode.GetIndex() - pBox->GetSttNd()->GetIndex() ) ) + { + bool bSetAtPara = false; + if ( bKeep ) + bSetAtPara = true; + else if ( bDontSplit ) + { + // check if pLine isn't last line in table + if ( rTable.GetTabLines().Count() - rTable.GetTabLines().GetPos( pLine ) != 1 ) + bSetAtPara = true; + } + + if ( bSetAtPara ) + { + if ( !pTmpSet ) + pTmpSet = new SfxItemSet(rNode.GetSwAttrSet()); + + const SvxFmtKeepItem aKeepItem( TRUE, RES_KEEP ); + pTmpSet->Put( aKeepItem ); + } + } + } + } + } + } + } + // <-- + + const SfxItemSet* pNewSet = pTmpSet ? pTmpSet : rNode.GetpSwAttrSet(); + if( pNewSet ) + { // Para-Attrs + pStyAttr = &rNode.GetAnyFmtColl().GetAttrSet(); + + const SwModify* pOldMod = pOutFmtNode; + pOutFmtNode = &rNode; + + // Pap-Attrs, so script is not necessary + OutputItemSet( *pNewSet, true, false, i18n::ScriptType::LATIN); + + pStyAttr = 0; + pOutFmtNode = pOldMod; + + if( pNewSet != rNode.GetpSwAttrSet() ) + delete pNewSet; + } + } + + AttrOutput().EndParagraphProperties(); + + AttrOutput().EndParagraph( pTextNodeInfoInner ); + +#ifdef DEBUG + ::std::clog << "</OutWW8_SwTxtNode>" << ::std::endl; +#endif +} + +void WW8AttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t pNodeInfo ) +{ + SVBT16 nSty; + ShortToSVBT16( GetExport().nStyleBeforeFly, nSty ); + + ww8::WW8TableNodeInfo::Inners_t::const_iterator aIt( pNodeInfo->getInners().begin() ); + ww8::WW8TableNodeInfo::Inners_t::const_iterator aItEnd( pNodeInfo->getInners().end() ); + + while (aIt != aItEnd) + { + ww8::WW8TableNodeInfoInner::Pointer_t pInner = aIt->second; + if ( pInner->isEndOfCell() ) + { + TableRowEnd( pInner->getDepth() ); + + m_rWW8Export.pO->Insert( (BYTE*)&nSty, 2, m_rWW8Export.pO->Count() ); // Style # + TableInfoRow( pInner ); + m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), + m_rWW8Export.pO->GetData() ); + m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); // leeren + } + + if ( pInner->isEndOfLine() ) + { + } + + aIt++; + } +} + +#if 0 +/* */ + +USHORT WW8Export::StartTableFromFrmFmt( WW8Bytes &rAt, const SwFrmFmt *pFmt ) +{ + // Tell the undocumented table hack that everything between here and + // the last table position is nontable text + if ( WW8_CP nPos = Fc2Cp( Strm().Tell() ) ) + pMagicTable->Append(nPos,0); + + // sprmPDxaFromText10 + if( bWrtWW8 ) + { + static BYTE __READONLY_DATA aTabLineAttr[] = { + 0, 0, // Sty # 0 + 0x16, 0x24, 1, // sprmPFInTable + 0x17, 0x24, 1 }; // sprmPFTtp + rAt.Insert( aTabLineAttr, sizeof( aTabLineAttr ), rAt.Count() ); + } + else + { + static BYTE __READONLY_DATA aTabLineAttr[] = { + 0, 0, // Sty # 0 + 24, 1, // sprmPFInTable + 25, 1 }; // sprmPFTtp + rAt.Insert( aTabLineAttr, sizeof( aTabLineAttr ), rAt.Count() ); + } + + ASSERT( pFmt, "No pFmt!" ); + if ( pFmt ) + { + const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient(); + const SwFmtVertOrient &rVert = pFmt->GetVertOrient(); + if ( + (text::RelOrientation::PRINT_AREA == rHori.GetRelationOrient() || + text::RelOrientation::FRAME == rHori.GetRelationOrient()) + && + (text::RelOrientation::PRINT_AREA == rVert.GetRelationOrient() || + text::RelOrientation::FRAME == rVert.GetRelationOrient()) + ) + { + sal_Int16 eHOri = rHori.GetHoriOrient(); + switch (eHOri) + { + case text::HoriOrientation::CENTER: + case text::HoriOrientation::RIGHT: + if( bWrtWW8 ) + SwWW8Writer::InsUInt16( rAt, NS_sprm::LN_TJc ); + else + rAt.Insert( 182, rAt.Count() ); + SwWW8Writer::InsUInt16( rAt, (text::HoriOrientation::RIGHT == eHOri ? 2 : 1 )); + break; + default: + break; + } + } + } + return rAt.Count(); +} + +//See #i19484# for why we need this +static bool CellContainsProblematicGraphic( const SwWriteTableCell *pCell, + const MSWordExportBase &rExport ) +{ + const SwNode *pStart = pCell ? pCell->GetBox()->GetSttNd() : 0; + const SwNode *pEnd = pStart ? pStart->EndOfSectionNode() : 0; + ASSERT( pStart && pEnd, "No start or end?" ); + if ( !pStart || !pEnd ) + return false; + + bool bHasGraphic = false; + + sw::Frames aFrames( GetFramesBetweenNodes( rExport.maFrames, *pStart, *pEnd ) ); + sw::FrameIter aEnd = aFrames.end(); + for ( sw::FrameIter aIter = aFrames.begin(); aIter != aEnd; ++aIter ) + { + const SwFrmFmt &rEntry = aIter->GetFrmFmt(); + if ( rEntry.GetSurround().GetSurround() == SURROUND_THROUGHT ) + { + bHasGraphic = true; + break; + } + } + return bHasGraphic; +} + +static bool RowContainsProblematicGraphic( const SwWriteTableCellPtr *pRow, + USHORT nCols, const MSWordExportBase &rExport ) +{ + bool bHasGraphic = false; + for ( USHORT nI = 0; nI < nCols; ++nI ) + { + if ( CellContainsProblematicGraphic( pRow[nI], rExport ) ) + { + bHasGraphic = true; + break; + } + } + return bHasGraphic; +} +#endif +//--------------------------------------------------------------------------- +// Tabellen +//--------------------------------------------------------------------------- + +void WW8AttributeOutput::EmptyParagraph() +{ + m_rWW8Export.WriteStringAsPara( aEmptyStr ); +} + +bool MSWordExportBase::NoPageBreakSection( const SfxItemSet* pSet ) +{ + bool bRet = false; + const SfxPoolItem* pI; + if( pSet) + { + bool bNoPageBreak = false; + if ( SFX_ITEM_ON != pSet->GetItemState(RES_PAGEDESC, true, &pI) + || 0 == ((SwFmtPageDesc*)pI)->GetPageDesc() ) + { + bNoPageBreak = true; + } + + if (bNoPageBreak) + { + if (SFX_ITEM_ON != pSet->GetItemState(RES_BREAK, true, &pI)) + bNoPageBreak = true; + else + { + SvxBreak eBreak = ((const SvxFmtBreakItem*)pI)->GetBreak(); + switch (eBreak) + { + case SVX_BREAK_PAGE_BEFORE: + case SVX_BREAK_PAGE_AFTER: + bNoPageBreak = false; + break; + default: + break; + } + } + } + bRet = bNoPageBreak; + } + return bRet; +} + +/* */ + +void MSWordExportBase::OutputSectionNode( const SwSectionNode& rSectionNode ) +{ + const SwSection& rSection = rSectionNode.GetSection(); + + SwNodeIndex aIdx( rSectionNode, 1 ); + const SwNode& rNd = aIdx.GetNode(); + if ( !rNd.IsSectionNode() && !bIsInTable ) //No sections in table + { + // Bug 74245 - if the first Node inside the section has an own + // PageDesc or PageBreak attribut, then dont write + // here the section break + ULONG nRstLnNum = 0; + const SfxItemSet* pSet; + if ( rNd.IsTableNode() ) + pSet = &rNd.GetTableNode()->GetTable().GetFrmFmt()->GetAttrSet(); + else if ( rNd.IsCntntNode() ) + { + pSet = &rNd.GetCntntNode()->GetSwAttrSet(); + nRstLnNum = ((SwFmtLineNumber&)pSet->Get( + RES_LINENUMBER )).GetStartValue(); + } + else + pSet = 0; + + if ( pSet && NoPageBreakSection( pSet ) ) + pSet = 0; + + if ( !pSet ) + { + // new Section with no own PageDesc/-Break + // -> write follow section break; + const SwSectionFmt& rFmt = *rSection.GetFmt(); + ReplaceCr( msword::PageBreak ); // Indikator fuer Page/Section-Break + + //Get the page in use at the top of this section + SwNodeIndex aIdxTmp(rSectionNode, 1); + const SwPageDesc *pCurrent = + SwPageDesc::GetPageDescOfNode(aIdxTmp.GetNode()); + if (!pCurrent) + pCurrent = pAktPageDesc; + + AppendSection( pCurrent, &rFmt, nRstLnNum ); + } + } + if ( TOX_CONTENT_SECTION == rSection.GetType() ) + bStartTOX = true; +} + + +void WW8Export::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFmt* pFmt, ULONG nLnNum ) +{ + pSepx->AppendSep(Fc2Cp(Strm().Tell()), pPageDesc, pFmt, nLnNum); +} + +/* */ + +//--------------------------------------------------------------------------- +// Flys +//--------------------------------------------------------------------------- + +void WW8Export::OutWW6FlyFrmsInCntnt( const SwTxtNode& rNd ) +{ + ASSERT(!bWrtWW8, "I shouldn't be needed for Word >=8"); + if ( bWrtWW8 ) + return; + + if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) + { + for( USHORT n=0; n < pTxtAttrs->Count(); ++n ) + { + const SwTxtAttr* pAttr = (*pTxtAttrs)[ n ]; + if( RES_TXTATR_FLYCNT == pAttr->Which() ) + { + // zeichengebundenes Attribut + const SwFmtFlyCnt& rFlyCntnt = pAttr->GetFlyCnt(); + const SwFlyFrmFmt& rFlyFrmFmt = *(SwFlyFrmFmt*)rFlyCntnt.GetFrmFmt(); + const SwNodeIndex* pNodeIndex = rFlyFrmFmt.GetCntnt().GetCntntIdx(); + + if( pNodeIndex ) + { + ULONG nStt = pNodeIndex->GetIndex()+1, + nEnd = pNodeIndex->GetNode().EndOfSectionIndex(); + + if( (nStt < nEnd) && !pDoc->GetNodes()[ nStt ]->IsNoTxtNode() ) + { + Point aOffset; + // Rechtecke des Flys und des Absatzes besorgen + SwRect aParentRect(rNd.FindLayoutRect(false, &aOffset)), + aFlyRect(rFlyFrmFmt.FindLayoutRect(false, &aOffset ) ); + + aOffset = aFlyRect.Pos() - aParentRect.Pos(); + + // PaM umsetzen: auf Inhalt des Fly-Frameformats + SaveData( nStt, nEnd ); + + // wird in OutputFormat() ausgewertet + pFlyOffset = &aOffset; + eNewAnchorType = rFlyFrmFmt.GetAnchor().GetAnchorId(); + sw::Frame aFrm(rFlyFrmFmt, SwPosition(rNd)); + mpParentFrame = &aFrm; + // Ok, rausschreiben: + WriteText(); + + RestoreData(); + } + } + } + } + } +} + +void WW8AttributeOutput::OutputFlyFrame_Impl( const sw::Frame& rFmt, const Point& rNdTopLeft ) +{ + const SwFrmFmt &rFrmFmt = rFmt.GetFrmFmt(); + const SwFmtAnchor& rAnch = rFrmFmt.GetAnchor(); + + bool bUseEscher = m_rWW8Export.bWrtWW8; + + if ( m_rWW8Export.bWrtWW8 && rFmt.IsInline() ) + { + sw::Frame::WriterSource eType = rFmt.GetWriterType(); + if ((eType == sw::Frame::eGraphic) || (eType == sw::Frame::eOle)) + bUseEscher = false; + else + bUseEscher = true; + + /* + #110185# + A special case for converting some inline form controls to form fields + when in winword 8+ mode + */ + if ((bUseEscher == true) && (eType == sw::Frame::eFormControl)) + { + if ( m_rWW8Export.MiserableFormFieldExportHack( rFrmFmt ) ) + return ; + } + } + + if (bUseEscher) + { + ASSERT( m_rWW8Export.bWrtWW8, "this has gone horribly wrong" ); + // write as escher + m_rWW8Export.AppendFlyInFlys(rFmt, rNdTopLeft); + } + else + { + bool bDone = false; + + // Hole vom Node und vom letzten Node die Position in der Section + const SwNodeIndex* pNodeIndex = rFrmFmt.GetCntnt().GetCntntIdx(); + + ULONG nStt = pNodeIndex ? pNodeIndex->GetIndex()+1 : 0; + ULONG nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0; + + if( nStt >= nEnd ) // kein Bereich, also kein gueltiger Node + return; + + if ( !m_rWW8Export.bIsInTable && rFmt.IsInline() ) + { + //Test to see if this textbox contains only a single graphic/ole + SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode(); + if ( pParTxtNode && !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode() ) + bDone = true; + } + if( !bDone ) + { + // ein NICHT zeichengebundener Rahmen liegt vor + + // --> OD 2007-04-19 #i43447# - removed +// const SwFmtFrmSize& rS = rFrmFmt.GetFrmSize(); +// nFlyWidth = rS.GetWidth(); // Fuer Anpassung Graphic-Groesse +// nFlyHeight = rS.GetHeight(); + // <-- + + m_rWW8Export.SaveData( nStt, nEnd ); + + Point aOffset; + if ( m_rWW8Export.mpParentFrame ) + { + /* + #90804# + Munge flys in fly into absolutely positioned elements for + word 6 + */ + const SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode(); + const SwRect aPageRect = pParTxtNode->FindPageFrmRect( FALSE, 0, FALSE ); + + aOffset = rFrmFmt.FindLayoutRect().Pos(); + aOffset -= aPageRect.Pos(); + + m_rWW8Export.pFlyOffset = &aOffset; + m_rWW8Export.eNewAnchorType = FLY_AT_PAGE; + } + + m_rWW8Export.mpParentFrame = &rFmt; + if ( + m_rWW8Export.bIsInTable && + (FLY_AT_PAGE != rAnch.GetAnchorId()) && + !m_rWW8Export.pDoc->GetNodes()[ nStt ]->IsNoTxtNode() + ) + { + // Beachten: Flag bOutTable wieder setzen, + // denn wir geben ja ganz normalen Content der + // Tabelenzelle aus und keinen Rahmen + // (Flag wurde oben in aSaveData() geloescht) + m_rWW8Export.bOutTable = true; + const String& rName = rFrmFmt.GetName(); + m_rWW8Export.StartCommentOutput(rName); + m_rWW8Export.WriteText(); + m_rWW8Export.EndCommentOutput(rName); + } + else + m_rWW8Export.WriteText(); + + m_rWW8Export.RestoreData(); + } + } +} + +void AttributeOutputBase::OutputFlyFrame( const sw::Frame& rFmt ) +{ + if ( !rFmt.GetCntntNode() ) + return; + + const SwCntntNode &rNode = *rFmt.GetCntntNode(); + Point aNdPos, aPgPos; + Point* pLayPos; + bool bValidNdPos = false, bValidPgPos = false; + + if (FLY_AT_PAGE == rFmt.GetFrmFmt().GetAnchor().GetAnchorId()) + { + // get the Layout Node-Position. + if ( !bValidPgPos ) + { + aPgPos = rNode.FindPageFrmRect(false, &aPgPos).Pos(); + bValidPgPos = true; + } + pLayPos = &aPgPos; + } + else + { + // get the Layout Node-Position. + if ( !bValidNdPos ) + { + aNdPos = rNode.FindLayoutRect(false, &aNdPos).Pos(); + bValidNdPos = true; + } + pLayPos = &aNdPos; + } + + OutputFlyFrame_Impl( rFmt, *pLayPos ); +} + +// write data of any redline +void WW8AttributeOutput::Redline( const SwRedlineData* pRedline ) +{ + if ( !pRedline ) + return; + + if ( pRedline->Next() ) + Redline( pRedline->Next() ); + + static USHORT __READONLY_DATA aSprmIds[ 2 * 2 * 3 ] = + { + // Ids for insert + NS_sprm::LN_CFRMark, NS_sprm::LN_CIbstRMark, NS_sprm::LN_CDttmRMark, // for WW8 + 0x0042, 0x0045, 0x0046, // for WW6 + // Ids for delete + NS_sprm::LN_CFRMarkDel, NS_sprm::LN_CIbstRMarkDel, NS_sprm::LN_CDttmRMarkDel, // for WW8 + 0x0041, 0x0045, 0x0046 // for WW6 + }; + + const USHORT* pSprmIds = 0; + switch( pRedline->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + pSprmIds = aSprmIds; + break; + + case nsRedlineType_t::REDLINE_DELETE: + pSprmIds = aSprmIds + (2 * 3); + break; + + case nsRedlineType_t::REDLINE_FORMAT: + if( m_rWW8Export.bWrtWW8 ) + { + m_rWW8Export.InsUInt16( NS_sprm::LN_CPropRMark ); + m_rWW8Export.pO->Insert( 7, m_rWW8Export.pO->Count() ); // len + m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() ); + m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) ); + m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() )); + } + break; + default: + ASSERT(!this, "Unhandled redline type for export"); + break; + } + + if ( pSprmIds ) + { + if ( !m_rWW8Export.bWrtWW8 ) + pSprmIds += 3; + + if ( m_rWW8Export.bWrtWW8 ) + m_rWW8Export.InsUInt16( pSprmIds[0] ); + else + m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[0]), m_rWW8Export.pO->Count() ); + m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() ); + + if ( m_rWW8Export.bWrtWW8 ) + m_rWW8Export.InsUInt16( pSprmIds[1] ); + else + m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[1]), m_rWW8Export.pO->Count() ); + m_rWW8Export.InsUInt16( m_rWW8Export.AddRedlineAuthor( pRedline->GetAuthor() ) ); + + if ( m_rWW8Export.bWrtWW8 ) + m_rWW8Export.InsUInt16( pSprmIds[2] ); + else + m_rWW8Export.pO->Insert( msword_cast<sal_uInt8>(pSprmIds[2]), m_rWW8Export.pO->Count() ); + m_rWW8Export.InsUInt32( sw::ms::DateTime2DTTM( pRedline->GetTimeStamp() )); + } +} + +/* */ + +void MSWordExportBase::OutputContentNode( const SwCntntNode& rNode ) +{ + switch ( rNode.GetNodeType() ) + { + case ND_TEXTNODE: + OutputTextNode( *rNode.GetTxtNode() ); + break; + case ND_GRFNODE: + OutputGrfNode( *rNode.GetGrfNode() ); + break; + case ND_OLENODE: + OutputOLENode( *rNode.GetOLENode() ); + break; + default: +#if OSL_DEBUG_LEVEL > 0 + OSL_TRACE("Unhandled node, type == %d\n", rNode.GetNodeType() ); +#endif + break; + } +} + +/* vi:set tabstop=4 shiftwidth=4 expandtab: */ |