/* -*- 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sw.hxx" #include #include #include #include #include #include #if OSL_DEBUG_LEVEL > 1 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "svl/urihelper.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "writerhelper.hxx" #include "writerwordglue.hxx" #include #include "wrtww8.hxx" #include "ww8par.hxx" #include #include "ww8attributeoutput.hxx" #include #include #include 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 ) { OSL_ENSURE(pFieldmark!=NULL, "where is my fieldmark???"); if ( !pFieldmark) { return String(); } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMTEXT ) ) ) { return String::CreateFromAscii(" FORMTEXT "); } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMDROPDOWN ) ) ) { return String::CreateFromAscii(" FORMDROPDOWN "); } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMCHECKBOX ) ) ) { return String::CreateFromAscii(" FORMCHECKBOX "); } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_TOC ) ) ) { return String::CreateFromAscii(" TOC "); } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_HYPERLINK ) ) ) { return String::CreateFromAscii(" HYPERLINK "); } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_PAGEREF ) ) ) { return String::CreateFromAscii(" PAGEREF "); } else { return pFieldmark->GetFieldname(); } } ww::eField lcl_getFieldId( const IFieldmark* pFieldmark ) { OSL_ENSURE(pFieldmark!=NULL, "where is my fieldmark???"); if ( !pFieldmark ) { return ww::eUNKNOWN; } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMTEXT ) ) ) { return ww::eFORMTEXT; } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMDROPDOWN ) ) ) { return ww::eFORMDROPDOWN; } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMCHECKBOX ) ) ) { return ww::eFORMCHECKBOX; } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_TOC ) ) ) { return ww::eTOC; } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_HYPERLINK ) ) ) { return ww::eHYPERLINK; } else if ( pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( 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; } class sortswflys : public std::binary_function { public: bool operator()(const sw::Frame &rOne, const sw::Frame &rTwo) const { return rOne.GetPosition() < rTwo.GetPosition(); } }; void SwWW8AttrIter::IterToCurrent() { OSL_ENSURE(maCharRuns.begin() != maCharRuns.end(), "Impossible"); mnScript = maCharRunIter->mnScript; meChrSet = maCharRunIter->meCharSet; mbCharIsRTL = maCharRunIter->mbRTL; } SwWW8AttrIter::SwWW8AttrIter(MSWordExportBase& rWr, const SwTxtNode& rTxtNd) : MSWordAttrIter(rWr), rNd(rTxtNd), maCharRuns(GetPseudoCharRuns(rTxtNd, 0, !rWr.SupportsUnicode())), 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.SupportsUnicode() && 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 SwWW8AttrIter::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; } bool lcl_isFontsizeItem( const SfxPoolItem& rItem ) { return ( rItem.Which( ) == RES_CHRATR_FONTSIZE || rItem.Which( ) == RES_CHRATR_CJK_FONTSIZE || rItem.Which( ) == RES_CHRATR_CTL_FONTSIZE ); } void SwWW8AttrIter::OutAttr( xub_StrLen nSwPos, bool bRuby ) { 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( (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()) { sal_Bool bDeep = sal_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(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 == RES_TXTATR_AUTOFMT) { const SwFmtAutoFmt& rAutoFmt = static_cast(pHt->GetAttr()); const boost::shared_ptr pSet = rAutoFmt.GetStyleHandle(); SfxWhichIter aIter( *pSet ); const SfxPoolItem* pItem; sal_uInt16 nWhichId = aIter.FirstWhich(); while( nWhichId ) { if( SFX_ITEM_SET == pSet->GetItemState( nWhichId, sal_False, &pItem )) { if (nWhichId == nFontId) pFont = &(item_cast(*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, false ); sw::cPoolItemIter aEnd = aRangeItems.end(); for ( sw::cPoolItemIter aI = aRangeItems.begin(); aI != aEnd; ++aI ) { if ( !bRuby || !lcl_isFontsizeItem( *aI->second ) ) 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; } OSL_ENSURE( 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.SupportsUnicode() ) aFont.SetCharSet( GetCharSet() ); if ( rParentFont != aFont ) m_rExport.AttrOutput().OutputItem( aFont ); } } void SwWW8AttrIter::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 SwWW8AttrIter::IsTxtAttr( xub_StrLen nSwPos ) { // search for attrs with CH_TXTATR if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) { for (sal_uInt16 i = 0; i < pTxtAttrs->Count(); ++i) { const SwTxtAttr* pHt = (*pTxtAttrs)[i]; if ( pHt->HasDummyChar() && (*pHt->GetStart() == nSwPos) ) return true; } } return false; } bool SwWW8AttrIter::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 SwWW8AttrIter::RequiresImplicitBookmark() { SwImplBookmarksIter bkmkIterEnd = m_rExport.maImplicitBookmarks.end(); for ( SwImplBookmarksIter aIter = m_rExport.maImplicitBookmarks.begin(); aIter != bkmkIterEnd; ++aIter ) { sal_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* SwWW8AttrIter::HasTextItem( sal_uInt16 nWhich ) const { const SfxPoolItem* pRet = 0; const SwpHints* pTxtAttrs = rNd.GetpSwpHints(); if (pTxtAttrs && m_rExport.m_aCurrentCharPropStarts.size()) { xub_StrLen nTmpSwPos = m_rExport.m_aCurrentCharPropStarts.top(); for (sal_uInt16 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 { sal_uInt16 nEnd = pO ? pO->Count() : 0; for (sal_uInt16 nI = 0; nI < nEnd; ++nI) rItems.Insert((*pO)[nI], rItems.Count()); } const SfxPoolItem& SwWW8AttrIter::GetItem(sal_uInt16 nWhich) const { const SfxPoolItem* pRet = HasTextItem(nWhich); return pRet ? *pRet : rNd.SwCntntNode::GetAttr(nWhich); } void WW8AttributeOutput::StartRuby( const SwTxtNode& rNode, xub_StrLen /*nPos*/, 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: OSL_ENSURE( !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. */ sal_uInt16 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(); pPool = pPool ? pPool : &m_rWW8Export.pDoc->GetAttrPool(); const SvxFontItem &rFont = DefaultItemGet< SvxFontItem >( *pPool, GetWhichOfScript( RES_CHRATR_FONT,nRubyScript ) ); sFamilyName = rFont.GetFamilyName(); const SvxFontHeightItem &rHeight = DefaultItemGet< SvxFontHeightItem > ( *pPool, 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( ")" ); // The parameter separator depends on the FIB.lid if ( m_rWW8Export.pFib->getNumDecimalSep() == '.' ) aStr.APPEND_CONST_ASC( "," ); else 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 ); OSL_ENSURE( 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_USTRINGPARAM( "_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 sal_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 sal_uInt8 aArr1[] = { 0x03, 0x6a, 0,0,0,0, // sprmCPicLocation 0x06, 0x08, 0x01, // sprmCFData 0x55, 0x08, 0x01, // sprmCFSpec 0x02, 0x08, 0x01 // sprmCFFldVanish }; sal_uInt8* 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(); // Compare the URL written by AnalyzeURL with the original one to see if // the output URL is absolute or relative. String sRelativeURL; if ( rUrl.Len() ) sRelativeURL = URIHelper::simpleNormalizedMakeRelative( m_rWW8Export.GetWriter().GetBaseURL(), rUrl ); bool bAbsolute = sRelativeURL.Equals( rUrl ); static sal_uInt8 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 sal_uInt8 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 ) ); /* Write HFD Structure */ sal_uInt8 nAnchor = 0x00; if ( sMark.Len() ) nAnchor = 0x08; m_rWW8Export.pDataStrm->Write( &nAnchor, 1 ); // HFDBits m_rWW8Export.pDataStrm->Write( MAGIC_A, sizeof(MAGIC_A) ); //clsid /* Write Hyperlink Object see [MS-OSHARED] spec*/ SwWW8Writer::WriteLong( *m_rWW8Export.pDataStrm, 0x00000002); sal_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 || eProto == INET_PROT_SMB ) { // version 1 (for a document) static sal_uInt8 MAGIC_C[] = { 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00 }; static sal_uInt8 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 ( eProto == INET_PROT_FILE && 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( '/', '\\' ); } // n#261623 convert smb notation to '\\' const char pSmb[] = "smb://"; if ( eProto == INET_PROT_SMB && sURL.EqualsAscii( pSmb, 0, sizeof( pSmb ) - 1 ) ) { sURL.Erase( 0, sizeof( pSmb ) - 3 ); 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 sal_uInt8 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 SwWW8AttrIter::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() ); sal_uInt16 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 ); sal_uInt16 nLvl = rAttr.GetLevel(); if (nLvl > WW8ListManager::nMaxLevel) nLvl = WW8ListManager::nMaxLevel; ((sTxt.APPEND_CONST_ASC( "\" \\l " )) += String::CreateFromInt32( nLvl )) += ' '; } break; default: OSL_ENSURE( !this, "Unhandled option for toc export" ); break; } if ( sTxt.Len() ) FieldVanish( sTxt, eType ); } int SwWW8AttrIter::OutAttrWithRange(xub_StrLen nPos) { int nRet = 0; if ( const SwpHints* pTxtAttrs = rNd.GetpSwpHints() ) { m_rExport.m_aCurrentCharPropStarts.push( nPos ); const xub_StrLen* pEnd; for ( sal_uInt16 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, nPos, *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 SwWW8AttrIter::IsRedlineAtEnd( xub_StrLen nEnd ) const { bool bRet = false; // search next Redline for( sal_uInt16 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* SwWW8AttrIter::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( 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(); OSL_ENSURE( nRet != FRMDIR_ENVIRONMENT, "leaving with environment direction" ); return nRet; } const SvxBrushItem* WW8Export::GetCurrentPageBgBrush() const { const SwFrmFmt &rFmt = pAktPageDesc ? pAktPageDesc->GetMaster() : const_cast(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(*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 SwWW8AttrIter::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 ) { sal_uInt16 nPos = 0; sal_uInt16 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( pTxtNode->GetAnyFmtColl() ); } void WW8AttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop &rSwFmtDrop, sal_uInt16 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( (sal_uInt8*)&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< sal_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< sal_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< sal_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< sal_uInt16 >( -rDropHeight ) ); m_rWW8Export.InsUInt16( 0 ); } } m_rWW8Export.WriteCR( pTextNodeInfoInner ); if ( pTextNodeInfo.get() != NULL ) { #if OSL_DEBUG_LEVEL > 1 ::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< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) ); m_rWW8Export.InsUInt16( NS_sprm::LN_CHps ); // Font Size m_rWW8Export.InsUInt16( static_cast< sal_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< sal_uInt16 >( -((nDropLines - 1)*rDropDescent) / 10 ) ); m_rWW8Export.pO->Insert( 99, m_rWW8Export.pO->Count() ); // Font Size m_rWW8Export.InsUInt16( static_cast< sal_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( SwWW8AttrIter* aAttrIter, const SwTxtNode& rNode, xub_StrLen nAktPos ) { // Get the bookmarks for the normal run xub_StrLen nNextPos = aAttrIter->WhereNext(); xub_StrLen nNextBookmark = nNextPos; if( nNextBookmark > nAktPos ) //no need to search for bookmarks otherwise (checked in UpdatePosition()) { GetSortedBookmarks( rNode, nAktPos, nNextBookmark - nAktPos ); NearestBookmark( nNextBookmark, nAktPos, false ); } return std::min( nNextPos, nNextBookmark ); } void MSWordExportBase::UpdatePosition( SwWW8AttrIter* aAttrIter, xub_StrLen nAktPos, xub_StrLen /*nEnd*/ ) { xub_StrLen nNextPos; // go to next attribute if no bookmark is found or if the bookmark is behind the next attribute position bool bNextBookmark = NearestBookmark( nNextPos, nAktPos, true ); if( !bNextBookmark || nNextPos > aAttrIter->WhereNext() ) aAttrIter->NextPos(); } bool MSWordExportBase::GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt, xub_StrLen nEnd, IMarkVector& rArr ) { IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); sal_uLong nNd = rNd.GetIndex( ); const sal_Int32 nMarks = pMarkAccess->getMarksCount(); for ( sal_Int32 i = 0; i < nMarks; i++ ) { IMark* pMark = ( pMarkAccess->getMarksBegin() + i )->get(); // Only keep the bookmarks starting or ending in this node if ( pMark->GetMarkStart().nNode == nNd || pMark->GetMarkEnd().nNode == nNd ) { xub_StrLen nBStart = pMark->GetMarkStart().nContent.GetIndex(); xub_StrLen nBEnd = pMark->GetMarkEnd().nContent.GetIndex(); // Keep only the bookmars starting or ending in the snippet bool bIsStartOk = ( nBStart >= nStt ) && ( nBStart <= nEnd ); bool bIsEndOk = ( nBEnd >= nStt ) && ( nBEnd <= nEnd ); if ( bIsStartOk || bIsEndOk ) rArr.push_back( pMark ); } } return ( rArr.size() > 0 ); } class CompareMarksEnd : public std::binary_function < const IMark *, const IMark *, bool > { public: inline bool operator() ( const IMark * pOneB, const IMark * pTwoB ) const { xub_StrLen nOEnd = pOneB->GetMarkEnd().nContent.GetIndex(); xub_StrLen nTEnd = pTwoB->GetMarkEnd().nContent.GetIndex(); return nOEnd < nTEnd; } }; bool MSWordExportBase::NearestBookmark( xub_StrLen& rNearest, const xub_StrLen nAktPos, bool bNextPositionOnly ) { bool bHasBookmark = false; if ( m_rSortedMarksStart.size( ) > 0 ) { IMark* pMarkStart = m_rSortedMarksStart.front(); xub_StrLen nNext = pMarkStart->GetMarkStart().nContent.GetIndex(); if( !bNextPositionOnly || (nNext > nAktPos )) { rNearest = nNext; bHasBookmark = true; } } if ( m_rSortedMarksEnd.size( ) > 0 ) { IMark* pMarkEnd = m_rSortedMarksEnd[0]; xub_StrLen nNext = pMarkEnd->GetMarkEnd().nContent.GetIndex(); if( !bNextPositionOnly || nNext > nAktPos ) { if ( !bHasBookmark ) rNearest = nNext; else rNearest = std::min( rNearest, nNext ); bHasBookmark = true; } } return bHasBookmark; } void MSWordExportBase::GetSortedBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen ) { IMarkVector aMarksStart; if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarksStart ) ) { IMarkVector aSortedEnd; IMarkVector aSortedStart; for ( IMarkVector::const_iterator it = aMarksStart.begin(), end = aMarksStart.end(); it < end; ++it ) { IMark* pMark = (*it); // Remove the positions egals to the current pos xub_StrLen nStart = pMark->GetMarkStart().nContent.GetIndex(); xub_StrLen nEnd = pMark->GetMarkEnd().nContent.GetIndex(); if ( nStart > nAktPos && ( pMark->GetMarkStart().nNode == rNode.GetIndex()) ) aSortedStart.push_back( pMark ); if ( nEnd > nAktPos && nEnd <= ( nAktPos + nLen ) && (pMark->GetMarkEnd().nNode == rNode.GetIndex()) ) aSortedEnd.push_back( pMark ); } // Sort the bookmarks by end position std::sort( aSortedEnd.begin(), aSortedEnd.end(), CompareMarksEnd() ); m_rSortedMarksStart.swap( aSortedStart ); m_rSortedMarksEnd.swap( aSortedEnd ); } else { m_rSortedMarksStart.clear( ); m_rSortedMarksEnd.clear( ); } } void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) { #if OSL_DEBUG_LEVEL > 1 ::std::clog << "" << ::std::endl; #endif ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo( mpTableInfo->getTableNodeInfo( &rNode ) ); AttrOutput().StartParagraph( pTextNodeInfo ); bool bFlyInTable = mpParentFrame && IsInTable(); 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 sal_uInt16 nStyle = nStyleBeforeFly; SwWW8AttrIter 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_USTRINGPARAM( "_toc" ) ); sBkmkName += String::CreateFromInt32( rNode.GetIndex() ); AppendWordBookmark( sBkmkName ); } String aStr( rNode.GetTxt() ); xub_StrLen nAktPos = 0; xub_StrLen const 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 ); if( nTxtTyp == TXT_FTN || nTxtTyp == TXT_EDN ) AttrOutput().FootnoteEndnoteRefTag(); 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 ) ); ::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 && pFieldmark->GetFieldname().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMTEXT ) ) ) AppendBookmark( pFieldmark->GetName(), false ); ww::eField eFieldId = lcl_getFieldId( pFieldmark ); String sCode = lcl_getFieldCode( pFieldmark ); if ( pFieldmark && pFieldmark->GetFieldname().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_UNHANDLED ) ) ) { IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( ODF_ID_PARAM )) ); if ( it != pFieldmark->GetParameters()->end() ) { rtl::OUString sFieldId; it->second >>= sFieldId; eFieldId = (ww::eField)sFieldId.toInt32(); } it = pFieldmark->GetParameters()->find( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( ODF_CODE_PARAM )) ); if ( it != pFieldmark->GetParameters()->end() ) { rtl::OUString sOUCode; it->second >>= sOUCode; sCode = sOUCode; } } OutputField( NULL, eFieldId, sCode, WRITEFIELD_START | WRITEFIELD_CMD_START ); if ( pFieldmark && pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMTEXT ) ) ) WriteFormData( *pFieldmark ); else if ( pFieldmark && pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_HYPERLINK ) ) ) WriteHyperlinkData( *pFieldmark ); OutputField( NULL, lcl_getFieldId( pFieldmark ), String(), WRITEFIELD_CMD_END ); if ( pFieldmark && pFieldmark->GetFieldname().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_UNHANDLED ) ) ) { // Check for the presence of a linked OLE object IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( ODF_OLE_PARAM )) ); if ( it != pFieldmark->GetParameters()->end() ) { rtl::OUString sOleId; uno::Any aValue = it->second; aValue >>= sOleId; if ( sOleId.getLength( ) > 0 ) OutputLinkedOLE( sOleId ); } } } else if ( ch == CH_TXT_ATR_FIELDEND ) { 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 FIELDEND??" ); ww::eField eFieldId = lcl_getFieldId( pFieldmark ); if ( pFieldmark && pFieldmark->GetFieldname().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_UNHANDLED ) ) ) { IFieldmark::parameter_map_t::const_iterator it = pFieldmark->GetParameters()->find( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( ODF_ID_PARAM )) ); if ( it != pFieldmark->GetParameters()->end() ) { rtl::OUString sFieldId; it->second >>= sFieldId; eFieldId = (ww::eField)sFieldId.toInt32(); } } OutputField( NULL, eFieldId, String(), WRITEFIELD_CLOSE ); if ( pFieldmark && pFieldmark->GetFieldname().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( 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 && (pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ODF_FORMDROPDOWN ) ) || pFieldmark->GetFieldname( ).equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( 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< sal_uInt16 >( ofs ); String aSnippet( aAttrIter.GetSnippet( aStr, nAktPos + static_cast< sal_uInt16 >( 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 ); if (0 != nEnd) { // Output the character attributes // #i51277# do this before writing flys at end of paragraph AttrOutput().StartRunProperties(); aAttrIter.OutAttr( nAktPos ); AttrOutput().EndRunProperties( pRedlineData ); } // At the end of line, output the attributes until the CR. // Exception: footnotes at the end of line if ( nNextAttr == nEnd ) { OSL_ENSURE( 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 ); } } } if (0 == nEnd) { // Output the character attributes // do it after WriteCR for an empty paragraph (otherwise // WW8_WrFkp::Append throws SPRMs away...) AttrOutput().StartRunProperties(); aAttrIter.OutAttr( nAktPos ); AttrOutput().EndRunProperties( pRedlineData ); } // Exception: footnotes at the end of line if ( nNextAttr == nEnd ) { OSL_ENSURE(nOpenAttrWithRange >= 0, "odd to see this happening, expected >= 0"); bool bAttrWithRange = (nOpenAttrWithRange > 0); if ( nAktPos != nEnd ) { nOpenAttrWithRange += aAttrIter.OutAttrWithRange(nEnd); OSL_ENSURE(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().WritePostitFieldReference(); AttrOutput().EndRun(); nAktPos = nNextAttr; UpdatePosition( &aAttrIter, nAktPos, nEnd ); eChrSet = aAttrIter.GetCharSet(); } while ( nAktPos < nEnd ); AttrOutput().StartParagraphProperties( rNode ); AttrOutput().ParagraphStyle( nStyle ); if ( mpParentFrame && IsInTable() ) // Fly-Attrs OutputFormat( mpParentFrame->GetFrmFmt(), false, false, true ); if ( pTextNodeInfo.get() != NULL ) { #if OSL_DEBUG_LEVEL > 1 ::std::clog << pTextNodeInfo->toString() << ::std::endl; #endif AttrOutput().TableInfoCell( pTextNodeInfoInner ); if (pTextNodeInfoInner->isFirstInTable()) { const SwTable * pTable = pTextNodeInfoInner->getTable(); const SwTableFmt * pTabFmt = pTable->GetTableFmt(); if (pTabFmt != NULL) { if (pTabFmt->GetBreak().GetBreak() == SVX_BREAK_PAGE_BEFORE) AttrOutput().PageBreakBefore(true); } } } if ( !bFlyInTable ) { SfxItemSet* pTmpSet = 0; const sal_uInt8 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 ); // #i25901#- consider compatibility option if (!pDoc->get(IDocumentSettingAccess::PARA_SPACE_MAX_AT_PAGES)) { if( !(ND_HAS_PREV_LAYNODE & nPrvNxtNd )) aUL.SetUpper( 0 ); } // #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 ); } } sal_Bool bParaRTL = sal_False; const SvxFrameDirectionItem* pItem = (const SvxFrameDirectionItem*) rNode.GetSwAttrSet().GetItem(RES_FRAMEDIR); if ( aAttrIter.IsParaRTL()) bParaRTL = sal_True; if( rNode.IsNumbered()) { const SwNumRule* pRule = rNode.GetNumRule(); sal_uInt8 nLvl = static_cast< sal_uInt8 >( rNode.GetActualListLevel() ); const SwNumFmt* pFmt = pRule->GetNumFmt( nLvl ); if( !pFmt ) pFmt = &pRule->Get( nLvl ); if( !pTmpSet ) pTmpSet = new SfxItemSet( rNode.GetSwAttrSet() ); SvxLRSpaceItem aLR(ItemGet(*pTmpSet, RES_LR_SPACE)); // #i86652# if ( pFmt->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) { aLR.SetTxtLeft( aLR.GetTxtLeft() + pFmt->GetAbsLSpace() ); } if( rNode.IsNumbered() && rNode.IsCountedInList() ) { // #i86652# if ( pFmt->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) { if (bParaRTL) aLR.SetTxtFirstLineOfstValue(pFmt->GetAbsLSpace() - pFmt->GetFirstLineOffset()); else aLR.SetTxtFirstLineOfst(GetWordFirstLineOffset(*pFmt)); } // 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); // #i86652# if ( pFmt->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) { pTmpSet->Put(aLR); //#i21847# SvxTabStopItem aItem( ItemGet(*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)); } // 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 // #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, sal_True, &pPoolItem); SvxLRSpaceItem aLRSpace( ( pPoolItem == NULL ) ? SvxLRSpaceItem(0, 0, 0, 0, RES_LR_SPACE) : *static_cast( pPoolItem ) ); // new left margin = old left + label space const SwNumRule* pRule = rNode.GetNumRule(); const SwNumFmt& rNumFmt = pRule->Get( static_cast< sal_uInt16 >(rNode.GetActualListLevel()) ); // #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 if (SFX_ITEM_SET != pTmpSet->GetItemState(RES_PARATR_NUMRULE, false) ) { pTmpSet->Put( SwNumRuleItem( pRule->GetName() )); } } // #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(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( rNode, RES_PAGEDESC ); if( rPageDescAtParaStyle.KnowsPageDesc() ) pTmpSet->ClearItem( RES_BREAK ); } } // #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( sal_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, false); pStyAttr = 0; pOutFmtNode = pOldMod; if( pNewSet != rNode.GetpSwAttrSet() ) delete pNewSet; } } AttrOutput().EndParagraphProperties(); AttrOutput().EndParagraph( pTextNodeInfoInner ); #if OSL_DEBUG_LEVEL > 1 ::std::clog << "" << ::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( (sal_uInt8*)&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; } } //--------------------------------------------------------------------------- // 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() && !IsInTable() ) //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 sal_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, sal_uLong nLnNum ) { pSepx->AppendSep(Fc2Cp(Strm().Tell()), pPageDesc, pFmt, nLnNum); } //--------------------------------------------------------------------------- // Flys //--------------------------------------------------------------------------- void WW8Export::OutWW6FlyFrmsInCntnt( const SwTxtNode& rNd ) { OSL_ENSURE(!bWrtWW8, "I shouldn't be needed for Word >=8"); if ( bWrtWW8 ) return; if (const SwpHints* pTxtAttrs = rNd.GetpSwpHints()) { for( sal_uInt16 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 ) { sal_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; /* 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) { OSL_ENSURE( 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(); sal_uLong nStt = pNodeIndex ? pNodeIndex->GetIndex()+1 : 0; sal_uLong nEnd = pNodeIndex ? pNodeIndex->GetNode().EndOfSectionIndex() : 0; if( nStt >= nEnd ) // kein Bereich, also kein gueltiger Node return; if ( !m_rWW8Export.IsInTable() && 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 ) { m_rWW8Export.SaveData( nStt, nEnd ); Point aOffset; if ( m_rWW8Export.mpParentFrame ) { /* Munge flys in fly into absolutely positioned elements for word 6 */ const SwTxtNode* pParTxtNode = rAnch.GetCntntAnchor()->nNode.GetNode().GetTxtNode(); const SwRect aPageRect = pParTxtNode->FindPageFrmRect( sal_False, 0, sal_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.IsInTable() && (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 sal_uInt16 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 sal_uInt16* 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: OSL_ENSURE(!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(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(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(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: { const SwTxtNode& rTextNode = *rNode.GetTxtNode(); if( !mbOutOutlineOnly || rTextNode.IsOutline() ) OutputTextNode( rTextNode ); } break; case ND_GRFNODE: OutputGrfNode( *rNode.GetGrfNode() ); break; case ND_OLENODE: OutputOLENode( *rNode.GetOLENode() ); break; default: OSL_TRACE("Unhandled node, type == %d", rNode.GetNodeType() ); break; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */