blob: 6703948a3a31c3558503308ae9796114cbed12ca [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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 <algorithm>
#include <functional>
#include <boost/scoped_array.hpp>
#include <com/sun/star/i18n/ScriptType.hdl>
#include <rtl/tencinfo.h>
#include <hintids.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/fontitem.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdotext.hxx>
#include <svx/svdotext.hxx>
#include <svx/fmglob.hxx>
#include <editeng/frmdiritem.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/ulspitem.hxx>
#include <doc.hxx>
#include <wrtww8.hxx>
#include <docary.hxx>
#include <poolfmt.hxx>
#include <fmtpdsc.hxx>
#include <pagedesc.hxx>
#include <ndtxt.hxx>
#include <ftninfo.hxx>
#include <fmthdft.hxx>
#include <section.hxx>
#include <fmtcntnt.hxx>
#include <fmtftn.hxx>
#include <ndindex.hxx>
#include <txtftn.hxx>
#include <charfmt.hxx>
#include <docufld.hxx>
#include <dcontact.hxx>
#include <fmtcnct.hxx>
#include <ftnidx.hxx>
#include <fmtclds.hxx>
#include <lineinfo.hxx>
#include <fmtline.hxx>
#include <swtable.hxx>
#include <msfilter.hxx>
#include <swmodule.hxx>
#include <writerfilter/doctok/sprmids.hxx>
#include "writerhelper.hxx"
#include "writerwordglue.hxx"
#include "../inc/wwstyles.hxx"
#include "ww8par.hxx"
#include "ww8attributeoutput.hxx"
#include "docxattributeoutput.hxx"
#include "rtfattributeoutput.hxx"
using namespace sw::util;
using namespace nsHdFtFlags;
/// For the output of sections.
struct WW8_PdAttrDesc
{
::boost::scoped_array<sal_uInt8> m_pData;
sal_uInt16 m_nLen;
WW8_FC m_nSepxFcPos;
WW8_PdAttrDesc() : m_nLen(0), m_nSepxFcPos(0xffffffff) /*default: none*/
{ }
};
struct WW8_SED
{
SVBT16 aBits1; // orientation change + internal, Default: 6
SVBT32 fcSepx; // FC file offset to beginning of SEPX for section.
// 0xFFFFFFFF for no Sprms
SVBT16 fnMpr; // used internally by Windows Word, Default: 0
SVBT32 fcMpr; // FC, points to offset in FC space for MacWord
// Default: 0xffffffff ( nothing )
// cbSED is 12 (decimal)), C (hex).
};
SV_IMPL_VARARR( WW8_WrSepInfoPtrs, WW8_SepInfo )
// class WW8_WrPlc0 ist erstmal nur fuer Header / Footer-Positionen, d.h. es
// gibt keine inhaltstragende Struktur.
class WW8_WrPlc0
{
private:
SvULongs aPos; // PTRARR von CPs / FCs
sal_uLong nOfs;
//No copying
WW8_WrPlc0(const WW8_WrPlc0&);
WW8_WrPlc0 &operator=(const WW8_WrPlc0&);
public:
WW8_WrPlc0( sal_uLong nOffset );
sal_uInt16 Count() const { return aPos.Count(); }
void Append( sal_uLong nStartCpOrFc );
void Write( SvStream& rStrm );
};
//------------------------------------------------------------
// Styles
//------------------------------------------------------------
#define WW8_RESERVED_SLOTS 15
// GetId( SwCharFmt ) zur Benutzung im Text -> nil verboten,
// "Default Char Style" stattdessen
sal_uInt16 MSWordExportBase::GetId( const SwCharFmt& rFmt ) const
{
sal_uInt16 nRet = pStyles->GetSlot( rFmt );
return ( nRet != 0x0fff ) ? nRet : 10; // Default Char Style
}
// GetId( SwTxtFmtColl ) zur Benutzung an TextNodes -> nil verboten,
// "Standard" stattdessen
sal_uInt16 MSWordExportBase::GetId( const SwTxtFmtColl& rColl ) const
{
sal_uInt16 nRet = pStyles->GetSlot( rColl );
return ( nRet != 0xfff ) ? nRet : 0; // Default TxtFmtColl
}
//typedef pFmtT
MSWordStyles::MSWordStyles( MSWordExportBase& rExport )
: m_rExport( rExport )
{
// if exist any Foot-/End-Notes then get from the EndNoteInfo struct
// the CharFormats. They will create it!
if ( m_rExport.pDoc->GetFtnIdxs().Count() )
{
m_rExport.pDoc->GetEndNoteInfo().GetAnchorCharFmt( *m_rExport.pDoc );
m_rExport.pDoc->GetEndNoteInfo().GetCharFmt( *m_rExport.pDoc );
m_rExport.pDoc->GetFtnInfo().GetAnchorCharFmt( *m_rExport.pDoc );
m_rExport.pDoc->GetFtnInfo().GetCharFmt( *m_rExport.pDoc );
}
sal_uInt16 nAlloc = WW8_RESERVED_SLOTS + m_rExport.pDoc->GetCharFmts()->Count() - 1 +
m_rExport.pDoc->GetTxtFmtColls()->Count() - 1;
// etwas grosszuegig ( bis zu 15 frei )
pFmtA = new SwFmt*[ nAlloc ];
memset( pFmtA, 0, nAlloc * sizeof( SwFmt* ) );
BuildStylesTable();
}
MSWordStyles::~MSWordStyles()
{
delete[] pFmtA;
}
// Sty_SetWWSlot() fuer Abhaengigkeiten der Styles -> nil ist erlaubt
sal_uInt16 MSWordStyles::GetSlot( const SwFmt& rFmt ) const
{
sal_uInt16 n;
for ( n = 0; n < nUsedSlots; n++ )
if ( pFmtA[n] == &rFmt )
return n;
return 0xfff; // 0xfff: WW: nil
}
sal_uInt16 MSWordStyles::BuildGetSlot( const SwFmt& rFmt )
{
sal_uInt16 nRet;
switch ( nRet = rFmt.GetPoolFmtId() )
{
case RES_POOLCOLL_STANDARD:
nRet = 0;
break;
case RES_POOLCOLL_HEADLINE1:
case RES_POOLCOLL_HEADLINE2:
case RES_POOLCOLL_HEADLINE3:
case RES_POOLCOLL_HEADLINE4:
case RES_POOLCOLL_HEADLINE5:
case RES_POOLCOLL_HEADLINE6:
case RES_POOLCOLL_HEADLINE7:
case RES_POOLCOLL_HEADLINE8:
case RES_POOLCOLL_HEADLINE9:
nRet -= RES_POOLCOLL_HEADLINE1-1;
break;
//case RES_POOLCHR_FOOTNOTE_ANCHOR: nRet =
//case RES_POOLCHR_ENDNOTE_ANCHOR:
default:
nRet = nUsedSlots++;
break;
}
return nRet;
}
sal_uInt16 MSWordStyles::GetWWId( const SwFmt& rFmt ) const
{
sal_uInt16 nRet = ww::stiUser; // User-Style als default
sal_uInt16 nPoolId = rFmt.GetPoolFmtId();
if( nPoolId == RES_POOLCOLL_STANDARD )
nRet = 0;
else if( nPoolId >= RES_POOLCOLL_HEADLINE1 &&
nPoolId <= RES_POOLCOLL_HEADLINE9 )
nRet = static_cast< sal_uInt16 >(nPoolId + 1 - RES_POOLCOLL_HEADLINE1);
else if( nPoolId >= RES_POOLCOLL_TOX_IDX1 &&
nPoolId <= RES_POOLCOLL_TOX_IDX3 )
nRet = static_cast< sal_uInt16 >(nPoolId + 10 - RES_POOLCOLL_TOX_IDX1);
else if( nPoolId >= RES_POOLCOLL_TOX_CNTNT1 &&
nPoolId <= RES_POOLCOLL_TOX_CNTNT5 )
nRet = static_cast< sal_uInt16 >(nPoolId + 19 - RES_POOLCOLL_TOX_CNTNT1);
else if( nPoolId >= RES_POOLCOLL_TOX_CNTNT6 &&
nPoolId <= RES_POOLCOLL_TOX_CNTNT9 )
nRet = static_cast< sal_uInt16 >(nPoolId + 24 - RES_POOLCOLL_TOX_CNTNT6);
else
switch( nPoolId )
{
case RES_POOLCOLL_FOOTNOTE: nRet = 29; break;
case RES_POOLCOLL_HEADER: nRet = 31; break;
case RES_POOLCOLL_FOOTER: nRet = 32; break;
case RES_POOLCOLL_TOX_IDXH: nRet = 33; break;
case RES_POOLCOLL_JAKETADRESS: nRet = 36; break;
case RES_POOLCOLL_SENDADRESS: nRet = 37; break;
case RES_POOLCOLL_ENDNOTE: nRet = 43; break;
case RES_POOLCOLL_LISTS_BEGIN: nRet = 47; break;
case RES_POOLCOLL_DOC_TITEL: nRet = 62; break;
case RES_POOLCOLL_SIGNATURE: nRet = 64; break;
case RES_POOLCOLL_TEXT: nRet = 66; break;
case RES_POOLCOLL_TEXT_MOVE: nRet = 67; break;
case RES_POOLCOLL_DOC_SUBTITEL: nRet = 74; break;
case RES_POOLCOLL_TEXT_IDENT: nRet = 77; break;
case RES_POOLCHR_FOOTNOTE_ANCHOR: nRet = 38; break;
case RES_POOLCHR_ENDNOTE_ANCHOR: nRet = 42; break;
case RES_POOLCHR_INET_NORMAL: nRet = 85; break;
case RES_POOLCHR_INET_VISIT: nRet = 86; break;
case RES_POOLCHR_HTML_STRONG: nRet = 87; break;
case RES_POOLCHR_HTML_EMPHASIS: nRet = 88; break;
case RES_POOLCHR_LINENUM: nRet = 40; break;
case RES_POOLCHR_PAGENO: nRet = 41; break;
}
return nRet;
}
void MSWordStyles::BuildStylesTable()
{
nUsedSlots = WW8_RESERVED_SLOTS; // soviele sind reserviert fuer
// Standard und HeadingX u.a.
SwFmt* pFmt;
sal_uInt16 n;
const SvPtrarr& rArr = *m_rExport.pDoc->GetCharFmts(); // erst CharFmt
// das Default-ZeichenStyle ( 0 ) wird nicht mit ausgegeben !
for( n = 1; n < rArr.Count(); n++ )
{
pFmt = (SwFmt*)rArr[n];
pFmtA[ BuildGetSlot( *pFmt ) ] = pFmt;
}
const SvPtrarr& rArr2 = *m_rExport.pDoc->GetTxtFmtColls(); // dann TxtFmtColls
// das Default-TextStyle ( 0 ) wird nicht mit ausgegeben !
for( n = 1; n < rArr2.Count(); n++ )
{
pFmt = (SwFmt*)rArr2[n];
pFmtA[ BuildGetSlot( *pFmt ) ] = pFmt;
}
}
/// For WW8 only - extend pO so that the size of pTableStrm is even.
static void impl_SkipOdd( WW8Bytes* pO, sal_Size nTableStrmTell )
{
if ( ( nTableStrmTell + pO->Count() ) & 1 ) // Start auf gerader
pO->Insert( (sal_uInt8)0, pO->Count() ); // Adresse
}
void WW8AttributeOutput::EndStyle()
{
impl_SkipOdd( m_rWW8Export.pO, m_rWW8Export.pTableStrm->Tell() );
short nLen = m_rWW8Export.pO->Count() - 2; // Laenge des Styles
sal_uInt8* p = (sal_uInt8*)m_rWW8Export.pO->GetData() + nPOPosStdLen1;
ShortToSVBT16( nLen, p ); // nachtragen
p = (sal_uInt8*)m_rWW8Export.pO->GetData() + nPOPosStdLen2;
ShortToSVBT16( nLen, p ); // dito
m_rWW8Export.pTableStrm->Write( m_rWW8Export.pO->GetData(), m_rWW8Export.pO->Count() ); // ins File damit
m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); // leeren fuer naechsten
}
void WW8AttributeOutput::StartStyle( const String& rName, bool bPapFmt, sal_uInt16 nWwBase,
sal_uInt16 nWwNext, sal_uInt16 nWwId, sal_uInt16 /*nId*/ )
{
sal_uInt8 aWW8_STD[ sizeof( WW8_STD ) ];
sal_uInt8* pData = aWW8_STD;
memset( &aWW8_STD, 0, sizeof( WW8_STD ) );
sal_uInt16 nBit16 = 0x1000; // fInvalHeight
nBit16 |= (ww::stiNil & nWwId);
Set_UInt16( pData, nBit16 );
nBit16 = nWwBase << 4; // istdBase
nBit16 |= bPapFmt ? 1 : 2; // sgc
Set_UInt16( pData, nBit16 );
nBit16 = nWwNext << 4; // istdNext
nBit16 |= bPapFmt ? 2 : 1; // cupx
Set_UInt16( pData, nBit16 );
pData += sizeof( sal_uInt16 ); // bchUpe
if( m_rWW8Export.bWrtWW8 )
{
//-------- jetzt neu:
// ab Ver8 gibts zwei Felder mehr:
//sal_uInt16 fAutoRedef : 1; /* auto redefine style when appropriate */
//sal_uInt16 fHidden : 1; /* hidden from UI? */
//sal_uInt16 : 14; /* unused bits */
pData += sizeof( sal_uInt16 );
}
sal_uInt16 nLen = static_cast< sal_uInt16 >( ( pData - aWW8_STD ) + 1 +
((m_rWW8Export.bWrtWW8 ? 2 : 1 ) * (rName.Len() + 1)) ); // vorlaeufig
WW8Bytes* pO = m_rWW8Export.pO;
nPOPosStdLen1 = pO->Count(); // Adr1 zum nachtragen der Laenge
SwWW8Writer::InsUInt16( *pO, nLen );
pO->Insert( aWW8_STD, static_cast< sal_uInt16 >( pData - aWW8_STD ), pO->Count() );
nPOPosStdLen2 = nPOPosStdLen1 + 8; // Adr2 zum nachtragen von "end of upx"
// Namen schreiben
if( m_rWW8Export.bWrtWW8 )
{
SwWW8Writer::InsUInt16( *pO, rName.Len() ); // Laenge
SwWW8Writer::InsAsString16( *pO, rName );
}
else
{
pO->Insert( (sal_uInt8)rName.Len(), pO->Count() ); // Laenge
SwWW8Writer::InsAsString8( *pO, rName, RTL_TEXTENCODING_MS_1252 );
}
pO->Insert( (sal_uInt8)0, pO->Count() ); // Trotz P-String 0 am Ende!
}
void MSWordStyles::SetStyleDefaults( const SwFmt& rFmt, bool bPap )
{
const SwModify* pOldMod = m_rExport.pOutFmtNode;
m_rExport.pOutFmtNode = &rFmt;
bool aFlags[ static_cast< sal_uInt16 >(RES_FRMATR_END) - RES_CHRATR_BEGIN ];
sal_uInt16 nStt, nEnd, n;
if( bPap )
nStt = RES_PARATR_BEGIN, nEnd = RES_FRMATR_END;
else
nStt = RES_CHRATR_BEGIN, nEnd = RES_TXTATR_END;
// dynamic defaults
const SfxItemPool& rPool = *rFmt.GetAttrSet().GetPool();
for( n = nStt; n < nEnd; ++n )
aFlags[ n - RES_CHRATR_BEGIN ] = 0 != rPool.GetPoolDefaultItem( n );
// static defaults, that differs between WinWord and SO
if( bPap )
{
aFlags[ static_cast< sal_uInt16 >(RES_PARATR_WIDOWS) - RES_CHRATR_BEGIN ] = 1;
aFlags[ static_cast< sal_uInt16 >(RES_PARATR_HYPHENZONE) - RES_CHRATR_BEGIN ] = 1;
}
else
{
aFlags[ RES_CHRATR_FONTSIZE - RES_CHRATR_BEGIN ] = 1;
aFlags[ RES_CHRATR_LANGUAGE - RES_CHRATR_BEGIN ] = 1;
}
const SfxItemSet* pOldI = m_rExport.GetCurItemSet();
m_rExport.SetCurItemSet( &rFmt.GetAttrSet() );
const bool* pFlags = aFlags + ( nStt - RES_CHRATR_BEGIN );
for ( n = nStt; n < nEnd; ++n, ++pFlags )
{
if ( *pFlags && SFX_ITEM_SET != rFmt.GetItemState(n, false))
{
//If we are a character property then see if it is one of the
//western/asian ones that must be collapsed together for export to
//word. If so default to the western varient.
if ( bPap || m_rExport.CollapseScriptsforWordOk(
i18n::ScriptType::LATIN, n) )
{
m_rExport.AttrOutput().OutputItem( rFmt.GetFmtAttr( n, true ) );
}
}
}
m_rExport.SetCurItemSet( pOldI );
m_rExport.pOutFmtNode = pOldMod;
}
void WW8AttributeOutput::StartStyleProperties( bool bParProp, sal_uInt16 nStyle )
{
WW8Bytes* pO = m_rWW8Export.pO;
impl_SkipOdd( pO, m_rWW8Export.pTableStrm->Tell() );
sal_uInt16 nLen = ( bParProp ) ? 2 : 0; // Default-Laenge
m_nStyleLenPos = pO->Count(); // Laenge zum Nachtragen
// Keinen Pointer merken, da sich bei
// _grow der Pointer aendert !
SwWW8Writer::InsUInt16( *pO, nLen ); // Style-Len
m_nStyleStartSize = pO->Count();
if ( bParProp )
SwWW8Writer::InsUInt16( *pO, nStyle ); // Style-Nummer
}
void MSWordStyles::WriteProperties( const SwFmt* pFmt, bool bParProp, sal_uInt16 nPos,
bool bInsDefCharSiz )
{
m_rExport.AttrOutput().StartStyleProperties( bParProp, nPos );
ASSERT( m_rExport.pCurrentStyle == NULL, "Current style not NULL" ); // set current style before calling out
m_rExport.pCurrentStyle = pFmt;
m_rExport.OutputFormat( *pFmt, bParProp, !bParProp );
ASSERT( m_rExport.pCurrentStyle == pFmt, "current style was changed" );
// reset current style...
m_rExport.pCurrentStyle = NULL;
if ( bInsDefCharSiz ) // nicht abgeleitet v. anderem Style
SetStyleDefaults( *pFmt, bParProp );
m_rExport.AttrOutput().EndStyleProperties( bParProp );
}
void WW8AttributeOutput::EndStyleProperties( bool /*bParProp*/ )
{
WW8Bytes* pO = m_rWW8Export.pO;
sal_uInt16 nLen = pO->Count() - m_nStyleStartSize;
sal_uInt8* pUpxLen = (sal_uInt8*)pO->GetData() + m_nStyleLenPos; // Laenge zum Nachtragen
ShortToSVBT16( nLen, pUpxLen ); // Default-Laenge eintragen
}
void MSWordStyles::GetStyleData( SwFmt* pFmt, bool& bFmtColl, sal_uInt16& nBase, sal_uInt16& nNext )
{
bFmtColl = pFmt->Which() == RES_TXTFMTCOLL || pFmt->Which() == RES_CONDTXTFMTCOLL;
// Default: none
nBase = 0xfff;
// Derived from?
if ( !pFmt->IsDefault() )
nBase = GetSlot( *pFmt->DerivedFrom() );
SwFmt* pNext;
if ( bFmtColl )
pNext = &((SwTxtFmtColl*)pFmt)->GetNextTxtFmtColl();
else
pNext = pFmt; // CharFmt: next CharFmt == self
nNext = GetSlot( *pNext );
}
void WW8AttributeOutput::DefaultStyle( sal_uInt16 nStyle )
{
if ( nStyle == 10 ) // Default Char-Style ( nur WW )
{
if ( m_rWW8Export.bWrtWW8 )
{
sal_uInt16 n = 0;
m_rWW8Export.pTableStrm->Write( &n , 2 ); // empty Style
}
else
{
static sal_uInt8 __READONLY_DATA aDefCharSty[] = {
0x26, 0x00,
0x41, 0x40, 0xF2, 0xFF, 0xA1, 0x00, 0x26, 0x00,
0x19, 0x41, 0x62, 0x73, 0x61, 0x74, 0x7A, 0x2D,
0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64,
0x73, 0x63, 0x68, 0x72, 0x69, 0x66, 0x74, 0x61,
0x72, 0x74, 0x00, 0x00, 0x00, 0x00 };
m_rWW8Export.pTableStrm->Write( &aDefCharSty, sizeof( aDefCharSty ) );
}
}
else
{
sal_uInt16 n = 0;
m_rWW8Export.pTableStrm->Write( &n , 2 ); // empty Style
}
}
// OutputStyle geht fuer TxtFmtColls und CharFmts
void MSWordStyles::OutputStyle( SwFmt* pFmt, sal_uInt16 nPos )
{
if ( !pFmt )
m_rExport.AttrOutput().DefaultStyle( nPos );
else
{
bool bFmtColl;
sal_uInt16 nBase, nWwNext;
GetStyleData( pFmt, bFmtColl, nBase, nWwNext );
m_rExport.AttrOutput().StartStyle( pFmt->GetName(), bFmtColl,
nBase, nWwNext, GetWWId( *pFmt ), nPos );
if ( bFmtColl )
WriteProperties( pFmt, true, nPos, nBase==0xfff ); // UPX.papx
WriteProperties( pFmt, false, nPos, bFmtColl && nBase==0xfff ); // UPX.chpx
m_rExport.AttrOutput().EndStyle();
}
}
void WW8AttributeOutput::StartStyles()
{
WW8Fib& rFib = *m_rWW8Export.pFib;
sal_uLong nCurPos = m_rWW8Export.pTableStrm->Tell();
if ( nCurPos & 1 ) // Start auf gerader
{
*m_rWW8Export.pTableStrm << (char)0; // Adresse
++nCurPos;
}
rFib.fcStshfOrig = rFib.fcStshf = nCurPos;
m_nStyAnzPos = nCurPos + 2; // Anzahl wird nachgetragen
if ( m_rWW8Export.bWrtWW8 )
{
static sal_uInt8 __READONLY_DATA aStShi[] = {
0x12, 0x00,
0x0F, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x5B, 0x00,
0x0F, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00 };
m_rWW8Export.pTableStrm->Write( &aStShi, sizeof( aStShi ) );
}
else
{
static sal_uInt8 __READONLY_DATA aStShi[] = {
0x0E, 0x00,
0x0F, 0x00, 0x08, 0x00, 0x01, 0x00, 0x4B, 0x00,
0x0F, 0x00, 0x00, 0x00, 0x00, 0x00 };
m_rWW8Export.pTableStrm->Write( &aStShi, sizeof( aStShi ) );
}
}
void WW8AttributeOutput::EndStyles( sal_uInt16 nNumberOfStyles )
{
WW8Fib& rFib = *m_rWW8Export.pFib;
rFib.lcbStshfOrig = rFib.lcbStshf = m_rWW8Export.pTableStrm->Tell() - rFib.fcStshf;
SwWW8Writer::WriteShort( *m_rWW8Export.pTableStrm, m_nStyAnzPos, nNumberOfStyles );
}
void MSWordStyles::OutputStylesTable()
{
m_rExport.bStyDef = true;
m_rExport.AttrOutput().StartStyles();
sal_uInt16 n;
for ( n = 0; n < nUsedSlots; n++ )
OutputStyle( pFmtA[n], n );
m_rExport.AttrOutput().EndStyles( nUsedSlots );
m_rExport.bStyDef = false;
}
/* */
//---------------------------------------------------------------------------
// Fonts
//---------------------------------------------------------------------------
wwFont::wwFont(const String &rFamilyName, FontPitch ePitch, FontFamily eFamily,
rtl_TextEncoding eChrSet, bool bWrtWW8) : mbAlt(false), mbWrtWW8(bWrtWW8), mePitch(ePitch), meFamily(eFamily), meChrSet(eChrSet)
{
FontMapExport aResult(rFamilyName);
msFamilyNm = aResult.msPrimary;
msAltNm = aResult.msSecondary;
if (msAltNm.Len() && msAltNm != msFamilyNm &&
(msFamilyNm.Len() + msAltNm.Len() + 2 <= 65) )
{
//max size of szFfn in 65 chars
mbAlt = true;
}
memset(maWW8_FFN, 0, sizeof(maWW8_FFN));
if (bWrtWW8)
{
maWW8_FFN[0] = (sal_uInt8)( 6 - 1 + 0x22 + ( 2 * ( 1 + msFamilyNm.Len() ) ));
if (mbAlt)
maWW8_FFN[0] = static_cast< sal_uInt8 >(maWW8_FFN[0] + 2 * ( 1 + msAltNm.Len()));
}
else
{
maWW8_FFN[0] = (sal_uInt8)( 6 - 1 + 1 + msFamilyNm.Len() );
if (mbAlt)
maWW8_FFN[0] = static_cast< sal_uInt8 >(maWW8_FFN[0] + 1 + msAltNm.Len());
}
sal_uInt8 aB = 0;
switch(ePitch)
{
case PITCH_VARIABLE:
aB |= 2; // aF.prg = 2
break;
case PITCH_FIXED:
aB |= 1;
break;
default: // aF.prg = 0 : DEFAULT_PITCH (windows.h)
break;
}
aB |= 1 << 2; // aF.fTrueType = 1; weiss ich nicht besser;
switch(eFamily)
{
case FAMILY_ROMAN:
aB |= 1 << 4; // aF.ff = 1;
break;
case FAMILY_SWISS:
aB |= 2 << 4; // aF.ff = 2;
break;
case FAMILY_MODERN:
aB |= 3 << 4; // aF.ff = 3;
break;
case FAMILY_SCRIPT:
aB |= 4 << 4; // aF.ff = 4;
break;
case FAMILY_DECORATIVE:
aB |= 5 << 4; // aF.ff = 5;
break;
default: // aF.ff = 0; FF_DONTCARE (windows.h)
break;
}
maWW8_FFN[1] = aB;
ShortToSVBT16( 400, &maWW8_FFN[2] ); // weiss ich nicht besser
// 400 == FW_NORMAL (windows.h)
maWW8_FFN[4] = sw::ms::rtl_TextEncodingToWinCharset(eChrSet);
if (mbAlt)
maWW8_FFN[5] = static_cast< sal_uInt8 >(msFamilyNm.Len() + 1);
}
bool wwFont::Write(SvStream *pTableStrm) const
{
pTableStrm->Write(maWW8_FFN, sizeof(maWW8_FFN)); // fixed part
if (mbWrtWW8)
{
// ab Ver8 sind folgende beiden Felder eingeschoben,
// werden von uns ignoriert.
//char panose[ 10 ]; // 0x6 PANOSE
//char fs[ 24 ]; // 0x10 FONTSIGNATURE
SwWW8Writer::FillCount(*pTableStrm, 0x22);
SwWW8Writer::WriteString16(*pTableStrm, msFamilyNm, true);
if (mbAlt)
SwWW8Writer::WriteString16(*pTableStrm, msAltNm, true);
}
else
{
SwWW8Writer::WriteString8(*pTableStrm, msFamilyNm, true,
RTL_TEXTENCODING_MS_1252);
if (mbAlt)
{
SwWW8Writer::WriteString8( *pTableStrm, msAltNm, true,
RTL_TEXTENCODING_MS_1252);
}
}
return true;
}
#ifdef DOCX
void wwFont::WriteDocx( const DocxAttributeOutput* rAttrOutput ) const
{
// no font embedding, panose id, subsetting, ... implemented
rAttrOutput->StartFont( msFamilyNm );
if ( mbAlt )
rAttrOutput->FontAlternateName( msAltNm );
rAttrOutput->FontCharset( sw::ms::rtl_TextEncodingToWinCharset( meChrSet ) );
rAttrOutput->FontFamilyType( meFamily );
rAttrOutput->FontPitchType( mePitch );
rAttrOutput->EndFont();
}
#endif
void wwFont::WriteRtf( const RtfAttributeOutput* rAttrOutput ) const
{
rAttrOutput->FontFamilyType( meFamily, *this );
rAttrOutput->FontPitchType( mePitch );
rAttrOutput->FontCharset( sw::ms::rtl_TextEncodingToWinCharset( meChrSet ) );
rAttrOutput->StartFont( msFamilyNm );
if ( mbAlt )
rAttrOutput->FontAlternateName( msAltNm );
rAttrOutput->EndFont();
}
bool operator<(const wwFont &r1, const wwFont &r2)
{
int nRet = memcmp(r1.maWW8_FFN, r2.maWW8_FFN, sizeof(r1.maWW8_FFN));
if (nRet == 0)
{
StringCompare eRet = r1.msFamilyNm.CompareTo(r2.msFamilyNm);
if (eRet == COMPARE_EQUAL)
eRet = r1.msAltNm.CompareTo(r2.msAltNm);
nRet = eRet;
}
return nRet < 0;
}
sal_uInt16 wwFontHelper::GetId(const wwFont &rFont)
{
sal_uInt16 nRet;
::std::map<wwFont, sal_uInt16>::const_iterator aIter = maFonts.find(rFont);
if (aIter != maFonts.end())
nRet = aIter->second;
else
{
nRet = static_cast< sal_uInt16 >(maFonts.size());
maFonts[rFont] = nRet;
}
return nRet;
}
void wwFontHelper::InitFontTable(bool bWrtWW8,const SwDoc& rDoc)
{
mbWrtWW8 = bWrtWW8;
GetId(wwFont(CREATE_CONST_ASC("Times New Roman"), PITCH_VARIABLE,
FAMILY_ROMAN, RTL_TEXTENCODING_MS_1252,bWrtWW8));
GetId(wwFont(CREATE_CONST_ASC("Symbol"), PITCH_VARIABLE, FAMILY_ROMAN,
RTL_TEXTENCODING_SYMBOL,bWrtWW8));
GetId(wwFont(CREATE_CONST_ASC("Arial"), PITCH_VARIABLE, FAMILY_SWISS,
RTL_TEXTENCODING_MS_1252,bWrtWW8));
const SvxFontItem* pFont = (const SvxFontItem*)GetDfltAttr(RES_CHRATR_FONT);
GetId(wwFont(pFont->GetFamilyName(), pFont->GetPitch(),
pFont->GetFamily(), pFont->GetCharSet(),bWrtWW8));
const SfxItemPool& rPool = rDoc.GetAttrPool();
if (0 != (pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem(RES_CHRATR_FONT)))
{
GetId(wwFont(pFont->GetFamilyName(), pFont->GetPitch(),
pFont->GetFamily(), pFont->GetCharSet(),bWrtWW8));
}
if (!bLoadAllFonts)
return;
const sal_uInt16 aTypes[] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT, 0 };
for (const sal_uInt16* pId = aTypes; *pId; ++pId)
{
sal_uInt32 const nMaxItem = rPool.GetItemCount2( *pId );
for (sal_uInt32 nGet = 0; nGet < nMaxItem; ++nGet)
{
pFont = (const SvxFontItem*)rPool.GetItem2( *pId, nGet );
if (0 != pFont)
{
GetId(wwFont(pFont->GetFamilyName(), pFont->GetPitch(),
pFont->GetFamily(), pFont->GetCharSet(),bWrtWW8));
}
}
}
}
sal_uInt16 wwFontHelper::GetId(const Font& rFont)
{
wwFont aFont(rFont.GetName(), rFont.GetPitch(), rFont.GetFamily(),
rFont.GetCharSet(), mbWrtWW8);
return GetId(aFont);
}
sal_uInt16 wwFontHelper::GetId(const SvxFontItem& rFont)
{
wwFont aFont(rFont.GetFamilyName(), rFont.GetPitch(), rFont.GetFamily(),
rFont.GetCharSet(), mbWrtWW8);
return GetId(aFont);
}
::std::vector< const wwFont* > wwFontHelper::AsVector() const
{
::std::vector<const wwFont *> aFontList( maFonts.size() );
typedef ::std::map<wwFont, sal_uInt16>::const_iterator myiter;
myiter aEnd = maFonts.end();
for ( myiter aIter = maFonts.begin(); aIter != aEnd; ++aIter )
aFontList[aIter->second] = &aIter->first;
return aFontList;
}
void wwFontHelper::WriteFontTable(SvStream *pTableStream, WW8Fib& rFib)
{
rFib.fcSttbfffn = pTableStream->Tell();
/*
* Reserve some space to fill in the len after we know how big it is
*/
if (mbWrtWW8)
SwWW8Writer::WriteLong(*pTableStream, 0);
else
SwWW8Writer::WriteShort(*pTableStream, 0);
/*
* Convert from fast insertion map to linear vector in the order that we
* want to write.
*/
::std::vector<const wwFont *> aFontList( AsVector() );
/*
* Write them all to pTableStream
*/
::std::for_each(aFontList.begin(), aFontList.end(),
::std::bind2nd(::std::mem_fun(&wwFont::Write),pTableStream));
/*
* Write the position and len in the FIB
*/
rFib.lcbSttbfffn = pTableStream->Tell() - rFib.fcSttbfffn;
if (mbWrtWW8)
SwWW8Writer::WriteLong( *pTableStream, rFib.fcSttbfffn, maFonts.size());
else
{
SwWW8Writer::WriteShort( *pTableStream, rFib.fcSttbfffn,
(sal_Int16)rFib.lcbSttbfffn );
}
}
#ifdef DOCX
void wwFontHelper::WriteFontTable( const DocxAttributeOutput& rAttrOutput )
{
::std::vector<const wwFont *> aFontList( AsVector() );
::std::for_each( aFontList.begin(), aFontList.end(),
::std::bind2nd( ::std::mem_fun( &wwFont::WriteDocx ), &rAttrOutput ) );
}
#endif
void wwFontHelper::WriteFontTable( const RtfAttributeOutput& rAttrOutput )
{
::std::vector<const wwFont *> aFontList( AsVector() );
::std::for_each( aFontList.begin(), aFontList.end(),
::std::bind2nd( ::std::mem_fun( &wwFont::WriteRtf ), &rAttrOutput ) );
}
/* */
WW8_WrPlc0::WW8_WrPlc0( sal_uLong nOffset )
: aPos( 4, 4 ), nOfs( nOffset )
{
}
void WW8_WrPlc0::Append( sal_uLong nStartCpOrFc )
{
aPos.Insert( nStartCpOrFc - nOfs, aPos.Count() );
}
void WW8_WrPlc0::Write( SvStream& rStrm )
{
sal_uInt16 nLen = aPos.Count();
for( sal_uInt16 i = 0; i < nLen; ++i )
{
SVBT32 nP;
UInt32ToSVBT32( aPos[i], nP );
rStrm.Write( nP, 4 );
}
}
//------------------------------------------------------------------------------
/* */
//------------------------------------------------------------------------------
// class MSWordSections : Uebersetzung PageDescs in Sections
// behandelt auch Header und Footer
//------------------------------------------------------------------------------
MSWordSections::MSWordSections( MSWordExportBase& rExport )
: mbDocumentIsProtected( false ),
aSects( 4, 4 )
{
const SwSectionFmt *pFmt = 0;
rExport.pAktPageDesc = &const_cast<const SwDoc *>(rExport.pDoc)->GetPageDesc( 0 );
const SfxPoolItem* pI;
const SwNode* pNd = rExport.pCurPam->GetCntntNode();
const SfxItemSet* pSet = pNd ? &((SwCntntNode*)pNd)->GetSwAttrSet() : 0;
sal_uLong nRstLnNum = pSet ? ((SwFmtLineNumber&)pSet->Get( RES_LINENUMBER )).GetStartValue() : 0;
const SwTableNode* pTblNd = rExport.pCurPam->GetNode()->FindTableNode();
const SwSectionNode* pSectNd;
if ( pTblNd )
{
pSet = &pTblNd->GetTable().GetFrmFmt()->GetAttrSet();
pNd = pTblNd;
}
else if ( 0 != ( pSectNd = pNd->FindSectionNode() ) )
{
if ( TOX_HEADER_SECTION == pSectNd->GetSection().GetType() &&
pSectNd->StartOfSectionNode()->IsSectionNode() )
{
pSectNd = pSectNd->StartOfSectionNode()->GetSectionNode();
}
if ( TOX_CONTENT_SECTION == pSectNd->GetSection().GetType() )
{
pNd = pSectNd;
rExport.pCurPam->GetPoint()->nNode = *pNd;
}
if ( CONTENT_SECTION == pSectNd->GetSection().GetType() )
pFmt = pSectNd->GetSection().GetFmt();
}
// Hole evtl. Pagedesc des 1. Nodes
if ( pSet &&
SFX_ITEM_ON == pSet->GetItemState( RES_PAGEDESC, true, &pI ) &&
( (SwFmtPageDesc*)pI )->GetPageDesc() )
{
AppendSection( *(SwFmtPageDesc*)pI, *pNd, pFmt, nRstLnNum );
}
else
AppendSection( rExport.pAktPageDesc, pFmt, nRstLnNum );
}
WW8_WrPlcSepx::WW8_WrPlcSepx( MSWordExportBase& rExport )
: MSWordSections( rExport )
, aCps( 4, 4 )
, m_bHeaderFooterWritten(false)
, pTxtPos( 0 )
{
// to be in sync with the AppendSection() call in the MSWordSections
// constructor
aCps.Insert( sal_uLong( 0 ), aCps.Count() );
}
MSWordSections::~MSWordSections()
{
}
WW8_WrPlcSepx::~WW8_WrPlcSepx()
{
delete pTxtPos;
}
bool MSWordSections::HeaderFooterWritten()
{
return false; // only relevant for WW8
}
bool WW8_WrPlcSepx::HeaderFooterWritten()
{
return m_bHeaderFooterWritten;
}
sal_uInt16 MSWordSections::CurrentNumberOfColumns( const SwDoc &rDoc ) const
{
ASSERT( aSects.Count(), "no segement inserted yet" );
if ( !aSects.Count() )
return 1;
return NumberOfColumns( rDoc, aSects[aSects.Count() - 1] );
}
sal_uInt16 MSWordSections::NumberOfColumns( const SwDoc &rDoc, const WW8_SepInfo& rInfo ) const
{
const SwPageDesc* pPd = rInfo.pPageDesc;
if ( !pPd )
pPd = &rDoc.GetPageDesc( 0 );
if ( !pPd )
{
ASSERT( pPd, "totally impossible" );
return 1;
}
const SfxItemSet &rSet = pPd->GetMaster().GetAttrSet();
SfxItemSet aSet( *rSet.GetPool(), RES_COL, RES_COL );
aSet.SetParent( &rSet );
//0xffffffff, what the hell is going on with that!, fixme most terribly
if ( rInfo.pSectionFmt && (SwSectionFmt*)0xFFFFFFFF != rInfo.pSectionFmt )
aSet.Put( rInfo.pSectionFmt->GetFmtAttr( RES_COL ) );
const SwFmtCol& rCol = (const SwFmtCol&)aSet.Get( RES_COL );
const SwColumns& rColumns = rCol.GetColumns();
return rColumns.Count();
}
const WW8_SepInfo* MSWordSections::CurrentSectionInfo()
{
if ( aSects.Count() > 0 )
return &aSects[aSects.Count() - 1];
return NULL;
}
void MSWordSections::AppendSection( const SwPageDesc* pPd,
const SwSectionFmt* pSectionFmt, sal_uLong nLnNumRestartNo )
{
if (HeaderFooterWritten()) {
return; // #i117955# prevent new sections in endnotes
}
aSects.Insert( WW8_SepInfo( pPd, pSectionFmt, nLnNumRestartNo ),
aSects.Count() );
NeedsDocumentProtected( aSects[aSects.Count()-1] );
}
void WW8_WrPlcSepx::AppendSep( WW8_CP nStartCp, const SwPageDesc* pPd,
const SwSectionFmt* pSectionFmt, sal_uLong nLnNumRestartNo )
{
if (HeaderFooterWritten()) {
return; // #i117955# prevent new sections in endnotes
}
aCps.Insert( nStartCp, aCps.Count() );
AppendSection( pPd, pSectionFmt, nLnNumRestartNo );
}
void MSWordSections::AppendSection( const SwFmtPageDesc& rPD,
const SwNode& rNd, const SwSectionFmt* pSectionFmt, sal_uLong nLnNumRestartNo )
{
if (HeaderFooterWritten()) {
return; // #i117955# prevent new sections in endnotes
}
WW8_SepInfo aI( rPD.GetPageDesc(), pSectionFmt, nLnNumRestartNo,
rPD.GetNumOffset(), &rNd );
aSects.Insert( aI, aSects.Count() );
NeedsDocumentProtected( aI );
}
void WW8_WrPlcSepx::AppendSep( WW8_CP nStartCp, const SwFmtPageDesc& rPD,
const SwNode& rNd, const SwSectionFmt* pSectionFmt, sal_uLong nLnNumRestartNo )
{
if (HeaderFooterWritten()) {
return; // #i117955# prevent new sections in endnotes
}
aCps.Insert(nStartCp, aCps.Count());
AppendSection( rPD, rNd, pSectionFmt, nLnNumRestartNo );
}
// MSWordSections::SetNum() setzt in jeder Section beim 1. Aufruf den
// Num-Pointer, alle folgenden Aufrufe werden ignoriert. Damit wird
// die erste Aufzaehlung einer Section uebernommen.
void MSWordSections::SetNum( const SwTxtNode* pNumNd )
{
WW8_SepInfo& rInfo = aSects[ aSects.Count() - 1 ];
if ( !rInfo.pNumNd ) // noch nicht belegt
rInfo.pNumNd = pNumNd;
}
void WW8_WrPlcSepx::WriteFtnEndTxt( WW8Export& rWrt, sal_uLong nCpStt )
{
sal_uInt8 nInfoFlags = 0;
const SwFtnInfo& rInfo = rWrt.pDoc->GetFtnInfo();
if( rInfo.aErgoSum.Len() ) nInfoFlags |= 0x02;
if( rInfo.aQuoVadis.Len() ) nInfoFlags |= 0x04;
sal_uInt8 nEmptyStt = rWrt.bWrtWW8 ? 0 : 6;
if( nInfoFlags )
{
if( rWrt.bWrtWW8 )
pTxtPos->Append( nCpStt ); // empty footenote separator
if( 0x02 & nInfoFlags ) // Footenote contiunation separator
{
pTxtPos->Append( nCpStt );
rWrt.WriteStringAsPara( rInfo.aErgoSum );
rWrt.WriteStringAsPara( aEmptyStr );
nCpStt = rWrt.Fc2Cp( rWrt.Strm().Tell() );
}
else if( rWrt.bWrtWW8 )
pTxtPos->Append( nCpStt );
if( 0x04 & nInfoFlags ) // Footenote contiunation notice
{
pTxtPos->Append( nCpStt );
rWrt.WriteStringAsPara( rInfo.aQuoVadis );
rWrt.WriteStringAsPara( aEmptyStr );
nCpStt = rWrt.Fc2Cp( rWrt.Strm().Tell() );
}
else if( rWrt.bWrtWW8 )
pTxtPos->Append( nCpStt );
if( rWrt.bWrtWW8 )
nEmptyStt = 3;
else
rWrt.pDop->grpfIhdt = nInfoFlags;
}
while( 6 > nEmptyStt++ )
pTxtPos->Append( nCpStt );
// gleich die Flags am Dop setzen
WW8Dop& rDop = *rWrt.pDop;
// Footnote Info
switch( rInfo.eNum )
{
case FTNNUM_PAGE: rDop.rncFtn = 2; break;
case FTNNUM_CHAPTER: rDop.rncFtn = 1; break;
default: rDop.rncFtn = 0; break;
} // rncFtn
rDop.nfcFtnRef = WW8Export::GetNumId( rInfo.aFmt.GetNumberingType() );
rDop.nFtn = rInfo.nFtnOffset + 1;
rDop.fpc = rWrt.bFtnAtTxtEnd ? 2 : 1;
// Endnote Info
rDop.rncEdn = 0; // rncEdn: Don't Restart
const SwEndNoteInfo& rEndInfo = rWrt.pDoc->GetEndNoteInfo();
rDop.nfcEdnRef = WW8Export::GetNumId( rEndInfo.aFmt.GetNumberingType() );
rDop.nEdn = rEndInfo.nFtnOffset + 1;
rDop.epc = rWrt.bEndAtTxtEnd ? 3 : 0;
}
void MSWordSections::SetHeaderFlag( sal_uInt8& rHeadFootFlags, const SwFmt& rFmt,
sal_uInt8 nFlag )
{
const SfxPoolItem* pItem;
if( SFX_ITEM_SET == rFmt.GetItemState(RES_HEADER, true, &pItem)
&& ((SwFmtHeader*)pItem)->IsActive() &&
((SwFmtHeader*)pItem)->GetHeaderFmt() )
rHeadFootFlags |= nFlag;
}
void MSWordSections::SetFooterFlag( sal_uInt8& rHeadFootFlags, const SwFmt& rFmt,
sal_uInt8 nFlag )
{
const SfxPoolItem* pItem;
if( SFX_ITEM_SET == rFmt.GetItemState(RES_FOOTER, true, &pItem)
&& ((SwFmtFooter*)pItem)->IsActive() &&
((SwFmtFooter*)pItem)->GetFooterFmt() )
rHeadFootFlags |= nFlag;
}
void WW8_WrPlcSepx::OutHeaderFooter( WW8Export& rWrt, bool bHeader,
const SwFmt& rFmt, sal_uLong& rCpPos, sal_uInt8 nHFFlags,
sal_uInt8 nFlag, sal_uInt8 nBreakCode)
{
if ( nFlag & nHFFlags )
{
pTxtPos->Append( rCpPos );
rWrt.WriteHeaderFooterText( rFmt, bHeader);
rWrt.WriteStringAsPara( aEmptyStr ); // CR ans Ende ( sonst mault WW )
rCpPos = rWrt.Fc2Cp( rWrt.Strm().Tell() );
}
else if ( rWrt.bWrtWW8 )
{
pTxtPos->Append( rCpPos );
if (rWrt.bHasHdr && nBreakCode!=0)
{
rWrt.WriteStringAsPara( aEmptyStr ); // Empty paragraph for empty header/footer
rWrt.WriteStringAsPara( aEmptyStr ); // a CR that WW8 needs for end of the stream
rCpPos = rWrt.Fc2Cp( rWrt.Strm().Tell() );
}
}
}
void MSWordSections::NeedsDocumentProtected(const WW8_SepInfo &rInfo)
{
if (rInfo.IsProtected())
mbDocumentIsProtected = true;
}
bool WW8_SepInfo::IsProtected() const
{
bool bRet = false;
if (
pSectionFmt &&
((SwSectionFmt*)0xFFFFFFFF != pSectionFmt)
)
{
const SwSection *pSection = pSectionFmt->GetSection();
if (pSection && pSection->IsProtect())
{
bRet = true;
}
}
return bRet;
}
void MSWordSections::CheckForFacinPg( WW8Export& rWrt ) const
{
// 2 Werte werden gesetzt
// Dop.fFacingPages == Kopf-/Fusszeilen unterschiedlich
// Dop.fSwapBordersFacingPgs == gespiegelte Raender
for( sal_uInt16 i = 0, nEnde = 0; i < aSects.Count(); ++i )
{
WW8_SepInfo& rSepInfo = aSects[i];
if( !rSepInfo.pSectionFmt )
{
const SwPageDesc* pPd = rSepInfo.pPageDesc;
if( pPd->GetFollow() && pPd != pPd->GetFollow() &&
pPd->GetFollow()->GetFollow() == pPd->GetFollow() &&
rSepInfo.pPDNd &&
pPd->IsFollowNextPageOfNode( *rSepInfo.pPDNd ) )
// das ist also 1.Seite und nachfolgende, also nur den
// follow beachten
pPd = pPd->GetFollow();
// left-/right chain of pagedescs ?
else if( !( 1 & nEnde ) &&
pPd->GetFollow() && pPd != pPd->GetFollow() &&
pPd->GetFollow()->GetFollow() == pPd &&
(( nsUseOnPage::PD_LEFT == ( nsUseOnPage::PD_ALL & pPd->ReadUseOn() ) &&
nsUseOnPage::PD_RIGHT == ( nsUseOnPage::PD_ALL & pPd->GetFollow()->ReadUseOn() )) ||
( nsUseOnPage::PD_RIGHT == ( nsUseOnPage::PD_ALL & pPd->ReadUseOn() ) &&
nsUseOnPage::PD_LEFT == ( nsUseOnPage::PD_ALL & pPd->GetFollow()->ReadUseOn() )) ))
{
rWrt.pDop->fFacingPages = rWrt.pDop->fMirrorMargins = true;
nEnde |= 1;
}
if( !( 1 & nEnde ) &&
( !pPd->IsHeaderShared() || !pPd->IsFooterShared() ))
{
rWrt.pDop->fFacingPages = true;
nEnde |= 1;
}
if( !( 2 & nEnde ) &&
nsUseOnPage::PD_MIRROR == ( nsUseOnPage::PD_MIRROR & pPd->ReadUseOn() ))
{
rWrt.pDop->fSwapBordersFacingPgs =
rWrt.pDop->fMirrorMargins = true;
nEnde |= 2;
}
if( 3 == nEnde )
break; // weiter brauchen wird nicht
}
}
}
int MSWordSections::HasBorderItem( const SwFmt& rFmt )
{
const SfxPoolItem* pItem;
return SFX_ITEM_SET == rFmt.GetItemState(RES_BOX, true, &pItem) &&
( ((SvxBoxItem*)pItem)->GetTop() ||
((SvxBoxItem*)pItem)->GetBottom() ||
((SvxBoxItem*)pItem)->GetLeft() ||
((SvxBoxItem*)pItem)->GetRight() );
}
void WW8AttributeOutput::StartSection()
{
m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); // leeren
}
void WW8AttributeOutput::SectionFormProtection( bool bProtected )
{
//If the document is to be exported as protected, then if a segment
//is not protected, set the unlocked flag
if ( m_rWW8Export.pSepx->DocumentIsProtected() && !bProtected )
{
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SFProtected );
else
m_rWW8Export.pO->Insert( 139, m_rWW8Export.pO->Count() );
m_rWW8Export.pO->Insert( 1 , m_rWW8Export.pO->Count() );
}
}
void WW8AttributeOutput::SectionLineNumbering( sal_uLong nRestartNo, const SwLineNumberInfo& rLnNumInfo )
{
// sprmSNLnnMod - activate Line Numbering and define Modulo
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SNLnnMod );
else
m_rWW8Export.pO->Insert( 154, m_rWW8Export.pO->Count() );
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, (sal_uInt16)rLnNumInfo.GetCountBy() );
// sprmSDxaLnn - xPosition of Line Number
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SDxaLnn );
else
m_rWW8Export.pO->Insert( 155, m_rWW8Export.pO->Count() );
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, (sal_uInt16)rLnNumInfo.GetPosFromLeft() );
// sprmSLnc - restart number: 0 per page, 1 per section, 2 never restart
if ( nRestartNo || !rLnNumInfo.IsRestartEachPage() )
{
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SLnc );
else
m_rWW8Export.pO->Insert( 152, m_rWW8Export.pO->Count() );
m_rWW8Export.pO->Insert( nRestartNo ? 1 : 2, m_rWW8Export.pO->Count() );
}
// sprmSLnnMin - Restart the Line Number with given value
if ( nRestartNo )
{
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SLnnMin );
else
m_rWW8Export.pO->Insert( 160, m_rWW8Export.pO->Count() );
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, (sal_uInt16)nRestartNo - 1 );
}
}
void WW8AttributeOutput::SectionTitlePage()
{
// sprmSFTitlePage
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SFTitlePage );
else
m_rWW8Export.pO->Insert( 143, m_rWW8Export.pO->Count() );
m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() );
}
void WW8AttributeOutput::SectionPageBorders( const SwFrmFmt* pPdFmt, const SwFrmFmt* pPdFirstPgFmt )
{
if ( m_rWW8Export.bWrtWW8 ) // Seitenumrandung schreiben
{
sal_uInt16 nPgBorder = MSWordSections::HasBorderItem( *pPdFmt ) ? 0 : USHRT_MAX;
if ( pPdFmt != pPdFirstPgFmt )
{
if ( MSWordSections::HasBorderItem( *pPdFirstPgFmt ) )
{
if ( USHRT_MAX == nPgBorder )
{
nPgBorder = 1;
// nur die 1. Seite umrandet -> BoxItem aus dem
// richtigen Format besorgen
m_rWW8Export.pISet = &pPdFirstPgFmt->GetAttrSet();
OutputItem( pPdFirstPgFmt->GetFmtAttr( RES_BOX ) );
}
}
else if ( !nPgBorder )
nPgBorder = 2;
}
if ( USHRT_MAX != nPgBorder )
{
// Flag und das Border Attribut schreiben
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SPgbProp );
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, nPgBorder );
}
}
}
void WW8AttributeOutput::SectionBiDi( bool bBiDi )
{
if ( m_rWW8Export.bWrtWW8 )
{
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SFBiDi );
m_rWW8Export.pO->Insert( bBiDi? 1: 0, m_rWW8Export.pO->Count() );
}
}
void WW8AttributeOutput::SectionPageNumbering( sal_uInt16 nNumType, sal_uInt16 nPageRestartNumber )
{
// sprmSNfcPgn
sal_uInt8 nb = WW8Export::GetNumId( nNumType );
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SNfcPgn );
else
m_rWW8Export.pO->Insert( 147, m_rWW8Export.pO->Count() );
m_rWW8Export.pO->Insert( nb, m_rWW8Export.pO->Count() );
if ( nPageRestartNumber )
{
// sprmSFPgnRestart
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SFPgnRestart );
else
m_rWW8Export.pO->Insert( 150, m_rWW8Export.pO->Count() );
m_rWW8Export.pO->Insert( 1, m_rWW8Export.pO->Count() );
// sprmSPgnStart
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SPgnStart );
else
m_rWW8Export.pO->Insert( 161, m_rWW8Export.pO->Count() );
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, nPageRestartNumber );
}
}
void WW8AttributeOutput::SectionType( sal_uInt8 nBreakCode )
{
if ( 2 != nBreakCode ) // new page is the default
{
if ( m_rWW8Export.bWrtWW8 )
SwWW8Writer::InsUInt16( *m_rWW8Export.pO, NS_sprm::LN_SBkc );
else
m_rWW8Export.pO->Insert( 142, m_rWW8Export.pO->Count() );
m_rWW8Export.pO->Insert( nBreakCode, m_rWW8Export.pO->Count() );
}
}
void WW8AttributeOutput::SectionWW6HeaderFooterFlags( sal_uInt8 nHeadFootFlags )
{
if ( nHeadFootFlags && !m_rWW8Export.bWrtWW8 )
{
sal_uInt8 nTmpFlags = nHeadFootFlags;
if ( m_rWW8Export.pDop->fFacingPages )
{
if ( !(nTmpFlags & WW8_FOOTER_EVEN) && (nTmpFlags & WW8_FOOTER_ODD ) )
nTmpFlags |= WW8_FOOTER_EVEN;
if ( !(nTmpFlags & WW8_HEADER_EVEN) && (nTmpFlags & WW8_HEADER_ODD ) )
nTmpFlags |= WW8_HEADER_EVEN;
}
// sprmSGprfIhdt, wird nur noch im WW95 benoetigt
m_rWW8Export.pO->Insert( 153, m_rWW8Export.pO->Count() );
m_rWW8Export.pO->Insert( nTmpFlags, m_rWW8Export.pO->Count() );
}
}
void WW8Export::SetupSectionPositions( WW8_PdAttrDesc* pA )
{
if ( !pA )
return;
if (pO->Count()) // are there attributes?
{
pA->m_nLen = pO->Count();
pA->m_pData.reset(new sal_uInt8[pO->Count()]);
// store for later
memcpy( pA->m_pData.get(), pO->GetData(), pO->Count() );
pO->Remove( 0, pO->Count() ); // leeren fuer HdFt-Text
}
else
{
pA->m_pData.reset();
pA->m_nLen = 0;
}
}
void WW8Export::WriteHeadersFooters( sal_uInt8 nHeadFootFlags,
const SwFrmFmt& rFmt, const SwFrmFmt& rLeftFmt, const SwFrmFmt& rFirstPageFmt, sal_uInt8 nBreakCode )
{
sal_uLong nCpPos = Fc2Cp( Strm().Tell() );
IncrementHdFtIndex();
if ( !(nHeadFootFlags & WW8_HEADER_EVEN) && pDop->fFacingPages )
pSepx->OutHeaderFooter( *this, true, rFmt, nCpPos, nHeadFootFlags, WW8_HEADER_ODD, nBreakCode );
else
pSepx->OutHeaderFooter( *this, true, rLeftFmt, nCpPos, nHeadFootFlags, WW8_HEADER_EVEN, nBreakCode );
IncrementHdFtIndex();
pSepx->OutHeaderFooter( *this, true, rFmt, nCpPos, nHeadFootFlags, WW8_HEADER_ODD, nBreakCode );
IncrementHdFtIndex();
if ( !(nHeadFootFlags & WW8_FOOTER_EVEN) && pDop->fFacingPages )
pSepx->OutHeaderFooter( *this, false, rFmt, nCpPos, nHeadFootFlags, WW8_FOOTER_ODD, nBreakCode );
else
pSepx->OutHeaderFooter( *this, false, rLeftFmt, nCpPos, nHeadFootFlags, WW8_FOOTER_EVEN, nBreakCode );
IncrementHdFtIndex();
pSepx->OutHeaderFooter( *this, false, rFmt, nCpPos, nHeadFootFlags, WW8_FOOTER_ODD, nBreakCode );
//#i24344# Drawing objects cannot be directly shared between main hd/ft
//and title hd/ft so we need to differenciate them
IncrementHdFtIndex();
pSepx->OutHeaderFooter( *this, true, rFirstPageFmt, nCpPos, nHeadFootFlags, WW8_HEADER_FIRST, nBreakCode );
pSepx->OutHeaderFooter( *this, false, rFirstPageFmt, nCpPos, nHeadFootFlags, WW8_FOOTER_FIRST, nBreakCode );
}
void MSWordExportBase::SectionProperties( const WW8_SepInfo& rSepInfo, WW8_PdAttrDesc* pA )
{
const SwPageDesc* pPd = rSepInfo.pPageDesc;
if ( rSepInfo.pSectionFmt && !pPd )
pPd = &const_cast<const SwDoc *>( pDoc )->GetPageDesc( 0 );
pAktPageDesc = pPd;
if ( !pPd )
return;
bool bOldPg = bOutPageDescs;
bOutPageDescs = true;
AttrOutput().StartSection();
// forms
AttrOutput().SectionFormProtection( rSepInfo.IsProtected() );
// line numbers
const SwLineNumberInfo& rLnNumInfo = pDoc->GetLineNumberInfo();
if ( rLnNumInfo.IsPaintLineNumbers() )
AttrOutput().SectionLineNumbering( rSepInfo.nLnNumRestartNo, rLnNumInfo );
/* sprmSBkc, break code: 0 No break, 1 New column
2 New page, 3 Even page, 4 Odd page
*/
sal_uInt8 nBreakCode = 2; // default neue Seite beginnen
bool bOutPgDscSet = true, bLeftRightPgChain = false;
const SwFrmFmt* pPdFmt = &pPd->GetMaster();
const SwFrmFmt* pPdFirstPgFmt = pPdFmt;
if ( rSepInfo.pSectionFmt )
{
// ist pSectionFmt gesetzt, dann gab es einen SectionNode
// gueltiger Pointer -> Section beginnt,
// 0xfff -> Section wird beendet
nBreakCode = 0; // fortlaufender Abschnitt
if ( rSepInfo.pPDNd && rSepInfo.pPDNd->IsCntntNode() )
{
if ( !NoPageBreakSection( &rSepInfo.pPDNd->GetCntntNode()->GetSwAttrSet() ) )
{
nBreakCode = 2;
}
}
if ( (SwSectionFmt*)0xFFFFFFFF != rSepInfo.pSectionFmt )
{
if ( nBreakCode == 0 )
bOutPgDscSet = false;
// Itemset erzeugen, das das PgDesk-AttrSet beerbt:
// als Nachkomme wird bei 'deep'-OutputItemSet
// auch der Vorfahr abgeklappert
const SfxItemSet* pPdSet = &pPdFmt->GetAttrSet();
SfxItemSet aSet( *pPdSet->GetPool(), pPdSet->GetRanges() );
aSet.SetParent( pPdSet );
// am Nachkommen NUR die Spaltigkeit gemaess Sect-Attr.
// umsetzen
const SvxLRSpaceItem &rSectionLR =
ItemGet<SvxLRSpaceItem>( *(rSepInfo.pSectionFmt), RES_LR_SPACE );
const SvxLRSpaceItem &rPageLR =
ItemGet<SvxLRSpaceItem>( *pPdFmt, RES_LR_SPACE );
SvxLRSpaceItem aResultLR( rPageLR.GetLeft() +
rSectionLR.GetLeft(), rPageLR.GetRight() +
rSectionLR.GetRight(), 0, 0, RES_LR_SPACE );
//i120133: The Section width should consider section indent value.
if (rSectionLR.GetLeft()+rSectionLR.GetRight()!=0)
{
const SwFmtCol& rCol = dynamic_cast<const SwFmtCol&>(rSepInfo.pSectionFmt->GetFmtAttr(RES_COL));
SwFmtCol aCol(rCol);
aCol.SetAdjustValue(rSectionLR.GetLeft()+rSectionLR.GetRight());
aSet.Put(aCol);
}
else
aSet.Put(rSepInfo.pSectionFmt->GetFmtAttr(RES_COL));
aSet.Put( aResultLR );
// und raus damit ins WW-File
const SfxItemSet* pOldI = pISet;
pISet = &aSet;
// --> OD 2007-06-12 #TESTING#
// Switch off test on default item values, if page description
// set (value of <bOutPgDscSet>) isn't written.
AttrOutput().OutputStyleItemSet( aSet, true, bOutPgDscSet );
// <--
//Cannot export as normal page framedir, as continous sections
//cannot contain any grid settings like proper sections
AttrOutput().SectionBiDi( FRMDIR_HORI_RIGHT_TOP == TrueFrameDirection( *rSepInfo.pSectionFmt ) );
pISet = pOldI;
}
}
if ( bOutPgDscSet )
{
// es ist ein Follow gesetzt und dieser zeigt nicht auf sich
// selbst, so liegt eine Seitenverkettung vor.
// Falls damit eine "Erste Seite" simuliert werden soll, so
// koennen wir das auch als solches schreiben.
// Anders sieht es mit Links/Rechts wechseln aus. Dafuer muss
// erkannt werden, wo der Seitenwechsel statt findet. Hier ist
// es aber dafuer zuspaet!
if ( pPd->GetFollow() && pPd != pPd->GetFollow() &&
pPd->GetFollow()->GetFollow() == pPd->GetFollow() &&
( !rSepInfo.pPDNd || pPd->IsFollowNextPageOfNode( *rSepInfo.pPDNd ) ) )
{
const SwPageDesc *pFollow = pPd->GetFollow();
const SwFrmFmt& rFollowFmt = pFollow->GetMaster();
const sal_Int8 nType = pDoc->GetDocumentType();
if ( sw::util::IsPlausableSingleWordSection( *pPdFmt, rFollowFmt, nType ))
{
if (rSepInfo.pPDNd)
pPdFirstPgFmt = pPd->GetPageFmtOfNode( *rSepInfo.pPDNd );
else
pPdFirstPgFmt = &pPd->GetMaster();
pAktPageDesc = pPd = pFollow;
pPdFmt = &rFollowFmt;
// has different headers/footers for the title page
AttrOutput().SectionTitlePage();
}
}
const SfxItemSet* pOldI = pISet;
AttrOutput().SectionPageBorders( pPdFmt, pPdFirstPgFmt );
const SfxPoolItem* pItem;
if ( pPdFmt != pPdFirstPgFmt && SFX_ITEM_SET ==
pPdFirstPgFmt->GetItemState( RES_PAPER_BIN, true, &pItem ) )
{
pISet = &pPdFirstPgFmt->GetAttrSet();
bOutFirstPage = true;
AttrOutput().OutputItem( *pItem );
bOutFirstPage = false;
}
// left-/right chain of pagedescs ?
if ( pPd->GetFollow() && pPd != pPd->GetFollow() &&
pPd->GetFollow()->GetFollow() == pPd &&
(( nsUseOnPage::PD_LEFT == ( nsUseOnPage::PD_ALL & pPd->ReadUseOn() ) &&
nsUseOnPage::PD_RIGHT == ( nsUseOnPage::PD_ALL & pPd->GetFollow()->ReadUseOn() )) ||
( nsUseOnPage::PD_RIGHT == ( nsUseOnPage::PD_ALL & pPd->ReadUseOn() ) &&
nsUseOnPage::PD_LEFT == ( nsUseOnPage::PD_ALL & pPd->GetFollow()->ReadUseOn() )) ))
{
bLeftRightPgChain = true;
// welches ist der Bezugspunkt ????? (links oder rechts?)
// annahme die rechte Seite!
if ( nsUseOnPage::PD_LEFT == ( nsUseOnPage::PD_ALL & pPd->ReadUseOn() ) )
{
nBreakCode = 3;
pPd = pPd->GetFollow();
pPdFmt = &pPd->GetMaster();
}
else
nBreakCode = 4;
}
pISet = &pPdFmt->GetAttrSet();
AttrOutput().OutputStyleItemSet( pPdFmt->GetAttrSet(), true, false );
pISet = pOldI;
// dann noch die restlichen Einstellungen aus dem PageDesc
AttrOutput().SectionPageNumbering( pPd->GetNumType().GetNumberingType(), rSepInfo.nPgRestartNo );
// werden es nur linke oder nur rechte Seiten?
if ( 2 == nBreakCode )
{
if ( nsUseOnPage::PD_LEFT == ( nsUseOnPage::PD_ALL & pPd->ReadUseOn() ) )
nBreakCode = 3;
else if ( nsUseOnPage::PD_RIGHT == ( nsUseOnPage::PD_ALL & pPd->ReadUseOn() ) )
nBreakCode = 4;
}
}
AttrOutput().SectionType( nBreakCode );
const SwTxtNode* pNd = rSepInfo.pNumNd;
if ( pNd )
{
const SwNumRule* pRule = pNd->GetNumRule();
if ( pRule )
OutputOlst( *pRule );
}
// Header oder Footer
sal_uInt8 nHeadFootFlags = 0;
const SwFrmFmt* pPdLeftFmt = bLeftRightPgChain
? &pPd->GetFollow()->GetMaster()
: &pPd->GetLeft();
if ( nBreakCode != 0 )
{
MSWordSections::SetHeaderFlag( nHeadFootFlags, *pPdFmt, WW8_HEADER_ODD );
MSWordSections::SetFooterFlag( nHeadFootFlags, *pPdFmt, WW8_FOOTER_ODD );
if ( !pPd->IsHeaderShared() || bLeftRightPgChain )
MSWordSections::SetHeaderFlag( nHeadFootFlags, *pPdLeftFmt, WW8_HEADER_EVEN );
if ( !pPd->IsFooterShared() || bLeftRightPgChain )
MSWordSections::SetFooterFlag( nHeadFootFlags, *pPdLeftFmt, WW8_FOOTER_EVEN );
if ( pPdFmt != pPdFirstPgFmt )
{
// es gibt eine ErsteSeite:
MSWordSections::SetHeaderFlag( nHeadFootFlags, *pPdFirstPgFmt, WW8_HEADER_FIRST );
MSWordSections::SetFooterFlag( nHeadFootFlags, *pPdFirstPgFmt, WW8_FOOTER_FIRST );
}
AttrOutput().SectionWW6HeaderFooterFlags( nHeadFootFlags );
}
// binary filters only
SetupSectionPositions( pA );
/*
!!!!!!!!!!!
// Umrandungen an Kopf- und Fusstexten muessten etwa so gehen:
// Dabei muss etwas wie pOut eingebaut werden,
// das bei jeder Spezialtext-Zeile wiederholt wird.
const SwFrmFmt* pFFmt = rFt.GetFooterFmt();
const SvxBoxItem& rBox = pFFmt->GetBox(false);
OutWW8_SwFmtBox1( m_rWW8Export.pOut, rBox, false);
!!!!!!!!!!!
Man koennt daraus Absatzattribute machen, die dann bei jedem Absatz
beachtet werden. Gilt fuer Hintergrund/Umrandung
!!!!!!!!!!!
*/
const SwTxtNode *pOldPageRoot = GetHdFtPageRoot();
SetHdFtPageRoot( rSepInfo.pPDNd ? rSepInfo.pPDNd->GetTxtNode() : 0 );
WriteHeadersFooters( nHeadFootFlags, *pPdFmt, *pPdLeftFmt, *pPdFirstPgFmt, nBreakCode );
SetHdFtPageRoot( pOldPageRoot );
AttrOutput().EndSection();
// outside of the section properties again
bOutPageDescs = bOldPg;
}
bool WW8_WrPlcSepx::WriteKFTxt( WW8Export& rWrt )
{
sal_uLong nCpStart = rWrt.Fc2Cp( rWrt.Strm().Tell() );
ASSERT( !pTxtPos, "wer hat den Pointer gesetzt?" );
pTxtPos = new WW8_WrPlc0( nCpStart );
WriteFtnEndTxt( rWrt, nCpStart );
CheckForFacinPg( rWrt );
unsigned int nOldIndex = rWrt.GetHdFtIndex();
rWrt.SetHdFtIndex( 0 );
// FIXME: this writes the section properties, but not of all sections;
// it's possible that later in the document (e.g. in endnotes) sections
// are added, but they won't have their properties written here!
m_bHeaderFooterWritten = true;
for ( sal_uInt16 i = 0; i < aSects.Count(); ++i )
{
::boost::shared_ptr<WW8_PdAttrDesc> const pAttrDesc(new WW8_PdAttrDesc);
m_SectionAttributes.push_back(pAttrDesc);
WW8_SepInfo& rSepInfo = aSects[i];
rWrt.SectionProperties( rSepInfo, pAttrDesc.get() );
}
rWrt.SetHdFtIndex( nOldIndex ); //0
if ( pTxtPos->Count() )
{
// HdFt vorhanden ?
sal_uLong nCpEnd = rWrt.Fc2Cp( rWrt.Strm().Tell() );
pTxtPos->Append( nCpEnd ); // Ende letzter Hd/Ft fuer PlcfHdd
if ( nCpEnd > nCpStart )
{
++nCpEnd;
pTxtPos->Append( nCpEnd + 1 ); // Ende letzter Hd/Ft fuer PlcfHdd
rWrt.WriteStringAsPara( aEmptyStr ); // CR ans Ende ( sonst mault WW )
}
rWrt.pFldHdFt->Finish( nCpEnd, rWrt.pFib->ccpText + rWrt.pFib->ccpFtn );
rWrt.pFib->ccpHdr = nCpEnd - nCpStart;
}
else
delete pTxtPos, pTxtPos = 0;
return rWrt.pFib->ccpHdr != 0;
}
void WW8_WrPlcSepx::WriteSepx( SvStream& rStrm ) const
{
OSL_ENSURE(m_SectionAttributes.size() == static_cast<size_t>(aSects.Count())
, "WriteSepx(): arrays out of sync!");
for (size_t i = 0; i < m_SectionAttributes.size(); i++) // all sections
{
WW8_PdAttrDesc *const pA = m_SectionAttributes[i].get();
if (pA->m_nLen && bool(pA->m_pData))
{
SVBT16 nL;
pA->m_nSepxFcPos = rStrm.Tell();
ShortToSVBT16( pA->m_nLen, nL );
rStrm.Write( nL, 2 );
rStrm.Write( pA->m_pData.get(), pA->m_nLen );
}
}
}
void WW8_WrPlcSepx::WritePlcSed( WW8Export& rWrt ) const
{
OSL_ENSURE(m_SectionAttributes.size() == static_cast<size_t>(aSects.Count())
, "WritePlcSed(): arrays out of sync!");
ASSERT( aCps.Count() == aSects.Count() + 1, "WrPlcSepx: DeSync" );
sal_uLong nFcStart = rWrt.pTableStrm->Tell();
sal_uInt16 i;
// ( ueber alle Sections )
for( i = 0; i <= aSects.Count(); i++ )
{
sal_uInt32 nP = aCps[i];
SVBT32 nPos;
UInt32ToSVBT32( nP, nPos );
rWrt.pTableStrm->Write( nPos, 4 );
}
static WW8_SED aSed = {{4, 0},{0, 0, 0, 0},{0, 0},{0xff, 0xff, 0xff, 0xff}};
// ( ueber alle Sections )
for (size_t j = 0; j < m_SectionAttributes.size(); j++ )
{
// Sepx-Pos
UInt32ToSVBT32( m_SectionAttributes[j]->m_nSepxFcPos, aSed.fcSepx );
rWrt.pTableStrm->Write( &aSed, sizeof( aSed ) );
}
rWrt.pFib->fcPlcfsed = nFcStart;
rWrt.pFib->lcbPlcfsed = rWrt.pTableStrm->Tell() - nFcStart;
}
void WW8_WrPlcSepx::WritePlcHdd( WW8Export& rWrt ) const
{
if( pTxtPos && pTxtPos->Count() )
{
rWrt.pFib->fcPlcfhdd = rWrt.pTableStrm->Tell();
pTxtPos->Write( *rWrt.pTableStrm ); // Plc0
rWrt.pFib->lcbPlcfhdd = rWrt.pTableStrm->Tell() -
rWrt.pFib->fcPlcfhdd;
}
}
void MSWordExportBase::WriteHeaderFooterText( const SwFmt& rFmt, bool bHeader )
{
const SwFmtCntnt *pCntnt;
if ( bHeader )
{
bHasHdr = true;
const SwFmtHeader& rHd = rFmt.GetHeader();
ASSERT( rHd.GetHeaderFmt(), "Header text is not here" );
pCntnt = &rHd.GetHeaderFmt()->GetCntnt();
}
else
{
bHasFtr = true;
const SwFmtFooter& rFt = rFmt.GetFooter();
ASSERT( rFt.GetFooterFmt(), "Footer text is not here" );
pCntnt = &rFt.GetFooterFmt()->GetCntnt();
}
const SwNodeIndex* pSttIdx = pCntnt->GetCntntIdx();
if ( pSttIdx )
{
SwNodeIndex aIdx( *pSttIdx, 1 ),
aEnd( *pSttIdx->GetNode().EndOfSectionNode() );
sal_uLong nStart = aIdx.GetIndex();
sal_uLong nEnd = aEnd.GetIndex();
// Bereich also gueltiger Node
if ( nStart < nEnd )
{
bool bOldKF = bOutKF;
bOutKF = true;
WriteSpecialText( nStart, nEnd, TXT_HDFT );
bOutKF = bOldKF;
}
else
pSttIdx = 0;
}
if ( !pSttIdx )
{
// es gibt keine Kopf-/Fusszeile, aber ein CR ist immer noch noetig
ASSERT( pSttIdx, "K/F-Text nicht richtig da" );
AttrOutput().EmptyParagraph(); // CR ans Ende ( sonst mault WW )
}
}
/* */
//------------------------------------------------------------------------------
// class WW8_WrPlcFtnEdn : Sammeln der Fuss/Endnoten und Ausgeben der Texte
// und Plcs am Ende des Docs.
// WW8_WrPlcFtnEdn ist die Klasse fuer Fuss- und Endnoten
//------------------------------------------------------------------------------
WW8_WrPlcSubDoc::WW8_WrPlcSubDoc()
: aCps( 0, 16 ), aCntnt( 0, 16 ), pTxtPos( 0 )
{
}
WW8_WrPlcSubDoc::~WW8_WrPlcSubDoc()
{
delete pTxtPos;
}
void WW8_WrPlcFtnEdn::Append( WW8_CP nCp, const SwFmtFtn& rFtn )
{
aCps.Insert( nCp, aCps.Count() );
void* p = (void*)&rFtn;
aCntnt.Insert( p, aCntnt.Count() );
}
WW8_Annotation::WW8_Annotation(const SwPostItField* pPostIt)
{
mpRichText = pPostIt->GetTextObject();
if (!mpRichText)
msSimpleText = pPostIt->GetContent();
msOwner = pPostIt->GetPar1();
maDateTime = DateTime(pPostIt->GetDate(), pPostIt->GetTime());
}
WW8_Annotation::WW8_Annotation(const SwRedlineData* pRedline) : mpRichText(0)
{
msSimpleText = pRedline->GetComment();
msOwner = SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor());
maDateTime = pRedline->GetTimeStamp();
}
void WW8_WrPlcAnnotations::Append( WW8_CP nCp, const SwPostItField *pPostIt )
{
aCps.Insert( nCp, aCps.Count() );
WW8_Annotation* p = new WW8_Annotation(pPostIt);
aCntnt.Insert( p, aCntnt.Count() );
}
void WW8_WrPlcAnnotations::Append( WW8_CP nCp, const SwRedlineData *pRedline )
{
maProcessedRedlines.insert(pRedline);
aCps.Insert( nCp, aCps.Count() );
WW8_Annotation* p = new WW8_Annotation(pRedline);
aCntnt.Insert( p, aCntnt.Count() );
}
bool WW8_WrPlcAnnotations::IsNewRedlineComment( const SwRedlineData *pRedline )
{
return maProcessedRedlines.find(pRedline) == maProcessedRedlines.end();
}
WW8_WrPlcAnnotations::~WW8_WrPlcAnnotations()
{
for( sal_uInt16 n=0; n < aCntnt.Count(); n++ )
delete (WW8_Annotation*)aCntnt[n];
}
bool WW8_WrPlcSubDoc::WriteGenericTxt( WW8Export& rWrt, sal_uInt8 nTTyp,
WW8_CP& rCount )
{
sal_uInt16 nLen = aCntnt.Count();
if ( !nLen )
return false;
sal_uLong nCpStart = rWrt.Fc2Cp( rWrt.Strm().Tell() );
pTxtPos = new WW8_WrPlc0( nCpStart );
sal_uInt16 i;
switch ( nTTyp )
{
case TXT_ATN:
for ( i = 0; i < nLen; i++ )
{
// Anfaenge fuer PlcfAtnTxt
pTxtPos->Append( rWrt.Fc2Cp( rWrt.Strm().Tell() ));
rWrt.WritePostItBegin();
const WW8_Annotation& rAtn = *(const WW8_Annotation*)aCntnt[i];
if (rAtn.mpRichText)
rWrt.WriteOutliner(*rAtn.mpRichText, nTTyp);
else
{
String sTxt(rAtn.msSimpleText);
sTxt.SearchAndReplaceAll(0x0A, 0x0B);
rWrt.WriteStringAsPara( sTxt );
}
}
break;
case TXT_TXTBOX:
case TXT_HFTXTBOX:
for ( i = 0; i < nLen; i++ )
{
// textbox - content
WW8_CP nCP = rWrt.Fc2Cp( rWrt.Strm().Tell() );
aCps.Insert( nCP, i );
pTxtPos->Append( nCP );
if( aCntnt[ i ] != NULL )
{
// is it an writer or sdr - textbox?
const SdrObject& rObj = *(SdrObject*)aCntnt[ i ];
if (rObj.GetObjInventor() == FmFormInventor)
{
sal_uInt8 nOldTyp = rWrt.nTxtTyp;
rWrt.nTxtTyp = nTTyp;
rWrt.GetOCXExp().ExportControl(rWrt,&rObj);
rWrt.nTxtTyp = nOldTyp;
}
else if( rObj.ISA( SdrTextObj ) )
rWrt.WriteSdrTextObj(rObj, nTTyp);
else
{
const SwFrmFmt* pFmt = ::FindFrmFmt( &rObj );
ASSERT( pFmt, "wo ist das Format geblieben?" );
const SwNodeIndex* pNdIdx = pFmt->GetCntnt().GetCntntIdx();
ASSERT( pNdIdx, "wo ist der StartNode der Textbox?" );
rWrt.WriteSpecialText( pNdIdx->GetIndex() + 1,
pNdIdx->GetNode().EndOfSectionIndex(),
nTTyp );
// --> OD 2008-08-07 #156757#
{
SwNodeIndex aContentIdx = *pNdIdx;
aContentIdx++;
if ( aContentIdx.GetNode().IsTableNode() )
{
bool bContainsOnlyTables = true;
do {
aContentIdx = *(aContentIdx.GetNode().EndOfSectionNode());
aContentIdx++;
if ( !aContentIdx.GetNode().IsTableNode() &&
aContentIdx.GetIndex() != pNdIdx->GetNode().EndOfSectionIndex() )
{
bContainsOnlyTables = false;
}
} while ( aContentIdx.GetNode().IsTableNode() );
if ( bContainsOnlyTables )
{
// Additional paragraph containing a space to
// assure that by WW created RTF from written WW8
// does not crash WW.
rWrt.WriteStringAsPara( String::CreateFromAscii( " " ) );
}
}
}
// <--
}
}
else if( i < aSpareFmts.Count() )
{
if( const SwFrmFmt* pFmt = (const SwFrmFmt*)aSpareFmts[ i ] )
{
const SwNodeIndex* pNdIdx = pFmt->GetCntnt().GetCntntIdx();
rWrt.WriteSpecialText( pNdIdx->GetIndex() + 1,
pNdIdx->GetNode().EndOfSectionIndex(), nTTyp );
}
}
// CR at end of one textbox text ( otherwise WW gpft :-( )
rWrt.WriteStringAsPara( aEmptyStr );
}
break;
case TXT_EDN:
case TXT_FTN:
for ( i = 0; i < nLen; i++ )
{
// Anfaenge fuer PlcfFtnTxt/PlcfEdnTxt
pTxtPos->Append( rWrt.Fc2Cp( rWrt.Strm().Tell() ));
// Noten-Inhalt
const SwFmtFtn* pFtn = (SwFmtFtn*)aCntnt[ i ];
rWrt.WriteFtnBegin( *pFtn );
const SwNodeIndex* pIdx = pFtn->GetTxtFtn()->GetStartNode();
ASSERT( pIdx, "wo ist der StartNode der Fuss-/EndNote?" );
rWrt.WriteSpecialText( pIdx->GetIndex() + 1,
pIdx->GetNode().EndOfSectionIndex(),
nTTyp );
}
break;
default:
ASSERT( !this, "was ist das fuer ein SubDocType?" );
}
pTxtPos->Append( rWrt.Fc2Cp( rWrt.Strm().Tell() ));
// CR ans Ende ( sonst mault WW )
rWrt.WriteStringAsPara( aEmptyStr );
WW8_CP nCpEnd = rWrt.Fc2Cp( rWrt.Strm().Tell() );
pTxtPos->Append( nCpEnd );
rCount = nCpEnd - nCpStart;
return ( rCount != 0 );
}
void WW8_WrPlcSubDoc::WriteGenericPlc( WW8Export& rWrt, sal_uInt8 nTTyp,
WW8_FC& rTxtStart, sal_Int32& rTxtCount, WW8_FC& rRefStart, sal_Int32& rRefCount ) const
{
typedef ::std::vector<String>::iterator myiter;
sal_uLong nFcStart = rWrt.pTableStrm->Tell();
sal_uInt16 nLen = aCps.Count();
if ( !nLen )
return;
ASSERT( aCps.Count() + 2 == pTxtPos->Count(), "WritePlc: DeSync" );
::std::vector<String> aStrArr;
WW8Fib& rFib = *rWrt.pFib; // n+1-te CP-Pos nach Handbuch
sal_uInt16 i;
bool bWriteCP = true;
switch ( nTTyp )
{
case TXT_ATN:
{
// then write first the GrpXstAtnOwners
for ( i = 0; i < nLen; ++i )
{
const WW8_Annotation& rAtn = *(const WW8_Annotation*)aCntnt[i];
aStrArr.push_back(rAtn.msOwner);
}
//sort and remove duplicates
::std::sort(aStrArr.begin(), aStrArr.end());
myiter aIter = ::std::unique(aStrArr.begin(), aStrArr.end());
aStrArr.erase(aIter, aStrArr.end());
if ( rWrt.bWrtWW8 )
{
for ( i = 0; i < aStrArr.size(); ++i )
{
const String& rStr = aStrArr[i];
SwWW8Writer::WriteShort(*rWrt.pTableStrm, rStr.Len());
SwWW8Writer::WriteString16(*rWrt.pTableStrm, rStr,
false);
}
}
else
{
for ( i = 0; i < aStrArr.size(); ++i )
{
const String& rStr = aStrArr[i];
*rWrt.pTableStrm << (sal_uInt8)rStr.Len();
SwWW8Writer::WriteString8(*rWrt.pTableStrm, rStr, false,
RTL_TEXTENCODING_MS_1252);
}
}
rFib.fcGrpStAtnOwners = nFcStart;
nFcStart = rWrt.pTableStrm->Tell();
rFib.lcbGrpStAtnOwners = nFcStart - rFib.fcGrpStAtnOwners;
// Write the extended >= Word XP ATLD records
if( rWrt.bWrtWW8 )
{
for( i = 0; i < nLen; ++i )
{
const WW8_Annotation& rAtn = *(const WW8_Annotation*)aCntnt[i];
sal_uInt32 nDTTM = sw::ms::DateTime2DTTM(rAtn.maDateTime);
SwWW8Writer::WriteLong( *rWrt.pTableStrm, nDTTM );
SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0 );
SwWW8Writer::WriteLong( *rWrt.pTableStrm, 0 );
SwWW8Writer::WriteLong( *rWrt.pTableStrm, 0 );
SwWW8Writer::WriteLong( *rWrt.pTableStrm, 0 );
}
rFib.fcAtrdExtra = nFcStart;
nFcStart = rWrt.pTableStrm->Tell();
rFib.lcbAtrdExtra = nFcStart - rFib.fcAtrdExtra;
rFib.fcHplxsdr = 0x01010002; //WTF, but apparently necessary
rFib.lcbHplxsdr = 0;
}
}
break;
case TXT_TXTBOX:
case TXT_HFTXTBOX:
{
pTxtPos->Write( *rWrt.pTableStrm );
const SvULongs* pShapeIds = GetShapeIdArr();
ASSERT( pShapeIds, "wo sind die ShapeIds?" );
// nLen = pTxtPos->Count();
for ( i = 0; i < nLen; ++i )
{
// write textbox story - FTXBXS
// is it an writer or sdr - textbox?
const SdrObject* pObj = (SdrObject*)aCntnt[ i ];
sal_Int32 nCnt = 1;
if (pObj && !pObj->ISA( SdrTextObj ) )
{
// find the "highest" SdrObject of this
const SwFrmFmt& rFmt = *::FindFrmFmt( pObj );
const SwFmtChain* pChn = &rFmt.GetChain();
while ( pChn->GetNext() )
{
// has a chain?
// then calc the cur pos in the chain
++nCnt;
pChn = &pChn->GetNext()->GetChain();
}
}
if( NULL == pObj )
{
if( i < aSpareFmts.Count() && aSpareFmts[ i ] )
{
const SwFrmFmt& rFmt = *(const SwFrmFmt*)aSpareFmts[ i ];
const SwFmtChain* pChn = &rFmt.GetChain();
while( pChn->GetNext() )
{
// has a chain?
// then calc the cur pos in the chain
++nCnt;
pChn = &pChn->GetNext()->GetChain();
}
}
}
// long cTxbx / iNextReuse
SwWW8Writer::WriteLong( *rWrt.pTableStrm, nCnt );
// long cReusable
SwWW8Writer::WriteLong( *rWrt.pTableStrm, 0 );
// short fReusable
SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0 );
// long reserved
SwWW8Writer::WriteLong( *rWrt.pTableStrm, -1 );
// long lid
SwWW8Writer::WriteLong( *rWrt.pTableStrm,
(*pShapeIds)[i]);
// long txidUndo
SwWW8Writer::WriteLong( *rWrt.pTableStrm, 0 );
}
SwWW8Writer::FillCount( *rWrt.pTableStrm, 22 );
bWriteCP = false;
}
break;
}
if ( bWriteCP )
{
// Schreibe CP-Positionen
for ( i = 0; i < nLen; i++ )
SwWW8Writer::WriteLong( *rWrt.pTableStrm, aCps[ i ] );
// n+1-te CP-Pos nach Handbuch
SwWW8Writer::WriteLong( *rWrt.pTableStrm,
rFib.ccpText + rFib.ccpFtn + rFib.ccpHdr + rFib.ccpEdn +
rFib.ccpTxbx + rFib.ccpHdrTxbx + 1 );
if ( TXT_ATN == nTTyp )
{
for ( i = 0; i < nLen; ++i )
{
const WW8_Annotation& rAtn = *(const WW8_Annotation*)aCntnt[i];
//aStrArr is sorted
myiter aIter = ::std::lower_bound(aStrArr.begin(),
aStrArr.end(), rAtn.msOwner);
ASSERT(aIter != aStrArr.end() && *aIter == rAtn.msOwner,
"Impossible");
sal_uInt16 nFndPos = static_cast< sal_uInt16 >(aIter - aStrArr.begin());
String sAuthor(*aIter);
sal_uInt8 nNameLen = (sal_uInt8)sAuthor.Len();
if ( nNameLen > 9 )
{
sAuthor.Erase( 9 );
nNameLen = 9;
}
// xstUsrInitl[ 10 ] pascal-style String holding initials
// of annotation author
if ( rWrt.bWrtWW8 )
{
SwWW8Writer::WriteShort(*rWrt.pTableStrm, nNameLen);
SwWW8Writer::WriteString16(*rWrt.pTableStrm, sAuthor,
false);
SwWW8Writer::FillCount( *rWrt.pTableStrm,
(9 - nNameLen) * 2 );
}
else
{
*rWrt.pTableStrm << nNameLen;
SwWW8Writer::WriteString8(*rWrt.pTableStrm, sAuthor,
false, RTL_TEXTENCODING_MS_1252);
SwWW8Writer::FillCount(*rWrt.pTableStrm, 9 - nNameLen);
}
//SVBT16 ibst; // index into GrpXstAtnOwners
//SVBT16 ak; // not used
//SVBT16 grfbmc; // not used
//SVBT32 ITagBkmk; // when not -1, this tag identifies the
SwWW8Writer::WriteShort( *rWrt.pTableStrm, nFndPos );
SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0 );
SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0 );
SwWW8Writer::WriteLong( *rWrt.pTableStrm, -1 );
}
}
else
{
sal_uInt16 nNo = 0;
for ( i = 0; i < nLen; ++i ) // Schreibe Flags
{
const SwFmtFtn* pFtn = (SwFmtFtn*)aCntnt[ i ];
SwWW8Writer::WriteShort( *rWrt.pTableStrm,
pFtn->GetNumStr().Len() ? 0 : ++nNo );
}
}
}
rRefStart = nFcStart;
nFcStart = rWrt.pTableStrm->Tell();
rRefCount = nFcStart - rRefStart;
pTxtPos->Write( *rWrt.pTableStrm );
switch ( nTTyp )
{
case TXT_TXTBOX:
case TXT_HFTXTBOX:
for ( i = 0; i < nLen; ++i )
{
// write break descriptor (BKD)
// short itxbxs
SwWW8Writer::WriteShort( *rWrt.pTableStrm, i );
// short dcpDepend
SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0 );
// short flags : icol/fTableBreak/fColumnBreak/fMarked/
// fUnk/fTextOverflow
SwWW8Writer::WriteShort( *rWrt.pTableStrm, 0x800 );
}
SwWW8Writer::FillCount( *rWrt.pTableStrm, 6 );
break;
}
rTxtStart = nFcStart;
rTxtCount = rWrt.pTableStrm->Tell() - nFcStart;
}
const SvULongs* WW8_WrPlcSubDoc::GetShapeIdArr() const
{
return 0;
}
/* vi:set tabstop=4 shiftwidth=4 expandtab: */