blob: a5fd5825dfecaa6ce92dc3afe7585c81783637cb [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"
#include <hintids.hxx>
#define _SVSTDARR_STRINGSSORTDTOR
#include <svl/svstdarr.hxx>
#include <sot/storage.hxx>
#include <sfx2/docfile.hxx>
#include <svl/urihelper.hxx>
#include <svtools/filter.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/eeitem.hxx>
#include <shellio.hxx>
#include <pam.hxx>
#include <doc.hxx>
#include <docary.hxx>
#include <IMark.hxx>
#include <numrule.hxx>
#include <swerror.h>
#include <boost/bind.hpp>
using namespace ::com::sun::star;
// Stringbuffer fuer die umgewandelten Zahlen
static sal_Char aNToABuf[] = "0000000000000000000000000";
#define NTOABUFLEN (sizeof(aNToABuf))
DECLARE_TABLE( SwBookmarkNodeTable, SvPtrarr* )
struct Writer_Impl
{
SvStream * m_pStream;
SvStringsSortDtor *pSrcArr, *pDestArr;
SvPtrarr* pFontRemoveLst, *pBkmkArr;
SwBookmarkNodeTable* pBkmkNodePos;
Writer_Impl();
~Writer_Impl();
void RemoveFontList( SwDoc& rDoc );
void InsertBkmk( const ::sw::mark::IMark& rBkmk );
};
Writer_Impl::Writer_Impl()
: m_pStream(0)
, pSrcArr( 0 ), pDestArr( 0 ), pFontRemoveLst( 0 ), pBkmkNodePos( 0 )
{
}
Writer_Impl::~Writer_Impl()
{
delete pSrcArr;
delete pDestArr;
delete pFontRemoveLst;
if( pBkmkNodePos )
{
for( SvPtrarr* p = pBkmkNodePos->First(); p; p = pBkmkNodePos->Next() )
delete p;
delete pBkmkNodePos;
}
}
void Writer_Impl::RemoveFontList( SwDoc& rDoc )
{
ASSERT( pFontRemoveLst, "wo ist die FontListe?" );
for( sal_uInt16 i = pFontRemoveLst->Count(); i; )
{
SvxFontItem* pItem = (SvxFontItem*)(*pFontRemoveLst)[ --i ];
rDoc.GetAttrPool().Remove( *pItem );
}
}
void Writer_Impl::InsertBkmk(const ::sw::mark::IMark& rBkmk)
{
if( !pBkmkNodePos )
pBkmkNodePos = new SwBookmarkNodeTable;
sal_uLong nNd = rBkmk.GetMarkPos().nNode.GetIndex();
SvPtrarr* pArr = pBkmkNodePos->Get( nNd );
if( !pArr )
{
pArr = new SvPtrarr( 1, 4 );
pBkmkNodePos->Insert( nNd, pArr );
}
void* p = (void*)&rBkmk;
pArr->Insert( p, pArr->Count() );
if(rBkmk.IsExpanded() && rBkmk.GetOtherMarkPos().nNode != nNd)
{
nNd = rBkmk.GetOtherMarkPos().nNode.GetIndex();
pArr = pBkmkNodePos->Get( nNd );
if( !pArr )
{
pArr = new SvPtrarr( 1, 4 );
pBkmkNodePos->Insert( nNd, pArr );
}
pArr->Insert( p, pArr->Count() );
}
}
/*
* Dieses Modul ist die Zentrale-Sammelstelle fuer alle Write-Filter
* und ist eine DLL !
*
* Damit der Writer mit den unterschiedlichen Writern arbeiten kann,
* muessen fuer diese die Ausgabe-Funktionen der Inhalts tragenden
* Objecte auf die verschiedenen Ausgabe-Funktionen gemappt werden.
*
* Dazu kann fuer jedes Object ueber den Which-Wert in einen Tabelle ge-
* griffen werden, um seine Ausgabe-Funktion zu erfragen.
* Diese Funktionen stehen in den entsprechenden Writer-DLL's.
*/
Writer::Writer()
: m_pImpl(new Writer_Impl)
, pOrigPam(0), pOrigFileName(0), pDoc(0), pCurPam(0)
{
bWriteAll = bShowProgress = bUCS2_WithStartChar = true;
bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
bOrganizerMode = false;
bExportPargraphNumbering = sal_True;
}
Writer::~Writer()
{
}
/*
* Document Interface Access
*/
IDocumentSettingAccess* Writer::getIDocumentSettingAccess() { return pDoc; }
const IDocumentSettingAccess* Writer::getIDocumentSettingAccess() const { return pDoc; }
IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() { return pDoc; }
const IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() const { return pDoc; }
void Writer::ResetWriter()
{
if (m_pImpl->pFontRemoveLst)
{
m_pImpl->RemoveFontList( *pDoc );
}
m_pImpl.reset(new Writer_Impl);
if( pCurPam )
{
while( pCurPam->GetNext() != pCurPam )
delete pCurPam->GetNext();
delete pCurPam;
}
pCurPam = 0;
pOrigFileName = 0;
pDoc = 0;
bShowProgress = bUCS2_WithStartChar = sal_True;
bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
bOrganizerMode = sal_False;
}
sal_Bool Writer::CopyNextPam( SwPaM ** ppPam )
{
if( (*ppPam)->GetNext() == pOrigPam )
{
*ppPam = pOrigPam; // wieder auf den Anfangs-Pam setzen
return sal_False; // Ende vom Ring
}
// ansonsten kopiere den die Werte aus dem naechsten Pam
*ppPam = ((SwPaM*)(*ppPam)->GetNext() );
*pCurPam->GetPoint() = *(*ppPam)->Start();
*pCurPam->GetMark() = *(*ppPam)->End();
return sal_True;
}
// suche die naechste Bookmark-Position aus der Bookmark-Tabelle
sal_Int32 Writer::FindPos_Bkmk(const SwPosition& rPos) const
{
const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
const IDocumentMarkAccess::const_iterator_t ppBkmk = ::std::lower_bound(
pMarkAccess->getAllMarksBegin(),
pMarkAccess->getAllMarksEnd(),
rPos,
::boost::bind(&::sw::mark::IMark::StartsBefore, _1, _2)); // find the first Mark that does not start before
if(ppBkmk != pMarkAccess->getAllMarksEnd())
return ppBkmk - pMarkAccess->getAllMarksBegin();
return -1;
}
SwPaM *
Writer::NewSwPaM(SwDoc & rDoc, sal_uLong const nStartIdx, sal_uLong const nEndIdx)
{
SwNodes *const pNds = &rDoc.GetNodes();
SwNodeIndex aStt( *pNds, nStartIdx );
SwCntntNode* pCNode = aStt.GetNode().GetCntntNode();
if( !pCNode && 0 == ( pCNode = pNds->GoNext( &aStt )) )
{
ASSERT( false, "An StartPos kein ContentNode mehr" );
}
SwPaM* pNew = new SwPaM( aStt );
pNew->SetMark();
aStt = nEndIdx;
if( 0 == (pCNode = aStt.GetNode().GetCntntNode()) &&
0 == (pCNode = pNds->GoPrevious( &aStt )) )
{
ASSERT( false, "An StartPos kein ContentNode mehr" );
}
pCNode->MakeEndIndex( &pNew->GetPoint()->nContent );
pNew->GetPoint()->nNode = aStt;
return pNew;
}
/////////////////////////////////////////////////////////////////////////////
// Stream-spezifisches
SvStream& Writer::Strm()
{
ASSERT( m_pImpl->m_pStream, "Oh-oh. Writer with no Stream!" );
return *m_pImpl->m_pStream;
}
void Writer::SetStream(SvStream *const pStream)
{ m_pImpl->m_pStream = pStream; }
SvStream& Writer::OutHex( SvStream& rStrm, sal_uLong nHex, sal_uInt8 nLen )
{ // in einen Stream aus
// Pointer an das Bufferende setzen
sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
for( sal_uInt8 n = 0; n < nLen; ++n )
{
*(--pStr) = (sal_Char)(nHex & 0xf ) + 48;
if( *pStr > '9' )
*pStr += 39;
nHex >>= 4;
}
return rStrm << pStr;
}
SvStream& Writer::OutLong( SvStream& rStrm, long nVal )
{
// Pointer an das Bufferende setzen
sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
int bNeg = nVal < 0;
if( bNeg )
nVal = -nVal;
do {
*(--pStr) = (sal_Char)(nVal % 10 ) + 48;
nVal /= 10;
} while( nVal );
// Ist Zahl negativ, dann noch -
if( bNeg )
*(--pStr) = '-';
return rStrm << pStr;
}
SvStream& Writer::OutULong( SvStream& rStrm, sal_uLong nVal )
{
// Pointer an das Bufferende setzen
sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
do {
*(--pStr) = (sal_Char)(nVal % 10 ) + 48;
nVal /= 10;
} while ( nVal );
return rStrm << pStr;
}
sal_uLong Writer::Write( SwPaM& rPaM, SvStream& rStrm, const String* pFName )
{
if ( IsStgWriter() )
{
SotStorageRef aRef = new SotStorage( rStrm );
sal_uLong nResult = Write( rPaM, *aRef, pFName );
if ( nResult == ERRCODE_NONE )
aRef->Commit();
return nResult;
}
pDoc = rPaM.GetDoc();
pOrigFileName = pFName;
m_pImpl->m_pStream = &rStrm;
// PaM kopieren, damit er veraendert werden kann
pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
// zum Vergleich auf den akt. Pam sichern
pOrigPam = &rPaM;
sal_uLong nRet = WriteStream();
ResetWriter();
return nRet;
}
sal_uLong Writer::Write( SwPaM& rPam, SfxMedium& rMed, const String* pFileName )
{
// This method must be overloaded in SwXMLWriter a storage from medium will be used there.
// The microsoft format can write to storage but the storage will be based on the stream.
return Write( rPam, *rMed.GetOutStream(), pFileName );
}
sal_uLong Writer::Write( SwPaM& /*rPam*/, SvStorage&, const String* )
{
ASSERT( !this, "Schreiben in Storages auf einem Stream?" );
return ERR_SWG_WRITE_ERROR;
}
sal_uLong Writer::Write( SwPaM&, const uno::Reference < embed::XStorage >&, const String*, SfxMedium* )
{
ASSERT( !this, "Schreiben in Storages auf einem Stream?" );
return ERR_SWG_WRITE_ERROR;
}
sal_Bool Writer::CopyLocalFileToINet( String& rFileNm )
{
if( !pOrigFileName ) // can be happen, by example if we
return sal_False; // write into the clipboard
sal_Bool bRet = sal_False;
INetURLObject aFileUrl( rFileNm ), aTargetUrl( *pOrigFileName );
// JP 01.11.00: what is the correct question for the portal??
// if( aFileUrl.GetProtocol() == aFileUrl.GetProtocol() )
// return bRet;
// this is our old without the Mail-Export
if( ! ( INET_PROT_FILE == aFileUrl.GetProtocol() &&
INET_PROT_FILE != aTargetUrl.GetProtocol() &&
INET_PROT_FTP <= aTargetUrl.GetProtocol() &&
INET_PROT_NEWS >= aTargetUrl.GetProtocol() ) )
return bRet;
if (m_pImpl->pSrcArr)
{
// wurde die Datei schon verschoben
sal_uInt16 nPos;
if (m_pImpl->pSrcArr->Seek_Entry( &rFileNm, &nPos ))
{
rFileNm = *(*m_pImpl->pDestArr)[ nPos ];
return sal_True;
}
}
else
{
m_pImpl->pSrcArr = new SvStringsSortDtor( 4, 4 );
m_pImpl->pDestArr = new SvStringsSortDtor( 4, 4 );
}
String *pSrc = new String( rFileNm );
String *pDest = new String( aTargetUrl.GetPartBeforeLastName() );
*pDest += String(aFileUrl.GetName());
SfxMedium aSrcFile( *pSrc, STREAM_READ, sal_False );
SfxMedium aDstFile( *pDest, STREAM_WRITE | STREAM_SHARE_DENYNONE, sal_False );
*aDstFile.GetOutStream() << *aSrcFile.GetInStream();
aSrcFile.Close();
aDstFile.Commit();
bRet = 0 == aDstFile.GetError();
if( bRet )
{
m_pImpl->pSrcArr->Insert( pSrc );
m_pImpl->pDestArr->Insert( pDest );
rFileNm = *pDest;
}
else
{
delete pSrc;
delete pDest;
}
return bRet;
}
void Writer::PutNumFmtFontsInAttrPool()
{
// dann gibt es noch in den NumRules ein paar Fonts
// Diese in den Pool putten. Haben sie danach einen RefCount > 1
// kann es wieder entfernt werden - ist schon im Pool
SfxItemPool& rPool = pDoc->GetAttrPool();
const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl();
const SwNumRule* pRule;
const SwNumFmt* pFmt;
// --> OD 2006-06-27 #b644095#
// const Font *pFont, *pDefFont = &SwNumRule::GetDefBulletFont();
const Font* pFont;
const Font* pDefFont = &numfunc::GetDefBulletFont();
// <--
sal_Bool bCheck = sal_False;
for( sal_uInt16 nGet = rListTbl.Count(); nGet; )
if( pDoc->IsUsed( *(pRule = rListTbl[ --nGet ] )))
for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
if( SVX_NUM_CHAR_SPECIAL == (pFmt = &pRule->Get( nLvl ))->GetNumberingType() ||
SVX_NUM_BITMAP == pFmt->GetNumberingType() )
{
if( 0 == ( pFont = pFmt->GetBulletFont() ) )
pFont = pDefFont;
if( bCheck )
{
if( *pFont == *pDefFont )
continue;
}
else if( *pFont == *pDefFont )
bCheck = sal_True;
_AddFontItem( rPool, SvxFontItem( pFont->GetFamily(),
pFont->GetName(), pFont->GetStyleName(),
pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT ));
}
}
void Writer::PutEditEngFontsInAttrPool( sal_Bool bIncl_CJK_CTL )
{
SfxItemPool& rPool = pDoc->GetAttrPool();
if( rPool.GetSecondaryPool() )
{
_AddFontItems( rPool, EE_CHAR_FONTINFO );
if( bIncl_CJK_CTL )
{
_AddFontItems( rPool, EE_CHAR_FONTINFO_CJK );
_AddFontItems( rPool, EE_CHAR_FONTINFO_CTL );
}
}
}
void Writer::PutCJKandCTLFontsInAttrPool()
{
SfxItemPool& rPool = pDoc->GetAttrPool();
_AddFontItems( rPool, RES_CHRATR_CJK_FONT );
_AddFontItems( rPool, RES_CHRATR_CTL_FONT );
}
void Writer::_AddFontItems( SfxItemPool& rPool, sal_uInt16 nW )
{
const SvxFontItem* pFont = (const SvxFontItem*)&rPool.GetDefaultItem( nW );
_AddFontItem( rPool, *pFont );
if( 0 != ( pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem( nW )) )
_AddFontItem( rPool, *pFont );
sal_uInt32 nMaxItem = rPool.GetItemCount2( nW );
for( sal_uInt32 nGet = 0; nGet < nMaxItem; ++nGet )
if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem2( nW, nGet )) )
_AddFontItem( rPool, *pFont );
}
void Writer::_AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
{
const SvxFontItem* pItem;
if( RES_CHRATR_FONT != rFont.Which() )
{
SvxFontItem aFont( rFont );
aFont.SetWhich( RES_CHRATR_FONT );
pItem = (SvxFontItem*)&rPool.Put( aFont );
}
else
pItem = (SvxFontItem*)&rPool.Put( rFont );
if( 1 < pItem->GetRefCount() )
rPool.Remove( *pItem );
else
{
if (!m_pImpl->pFontRemoveLst)
{
m_pImpl->pFontRemoveLst = new SvPtrarr( 0, 10 );
}
void* p = (void*)pItem;
m_pImpl->pFontRemoveLst->Insert( p, m_pImpl->pFontRemoveLst->Count() );
}
}
// build a bookmark table, which is sort by the node position. The
// OtherPos of the bookmarks also inserted.
void Writer::CreateBookmarkTbl()
{
const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
for(IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getBookmarksBegin();
ppBkmk != pMarkAccess->getBookmarksEnd();
++ppBkmk)
{
m_pImpl->InsertBkmk(**ppBkmk);
}
}
// search alle Bookmarks in the range and return it in the Array
sal_uInt16 Writer::GetBookmarks(const SwCntntNode& rNd, xub_StrLen nStt,
xub_StrLen nEnd, SvPtrarr& rArr)
{
ASSERT( !rArr.Count(), "es sind noch Eintraege vorhanden" );
sal_uLong nNd = rNd.GetIndex();
SvPtrarr* pArr = (m_pImpl->pBkmkNodePos) ?
m_pImpl->pBkmkNodePos->Get( nNd ) : 0;
if( pArr )
{
// there exist some bookmarks, search now all which is in the range
if( !nStt && nEnd == rNd.Len() )
// all
rArr.Insert( pArr, 0 );
else
{
sal_uInt16 n;
xub_StrLen nCntnt;
for( n = 0; n < pArr->Count(); ++n )
{
void* p = (*pArr)[ n ];
const ::sw::mark::IMark& rBkmk = *(::sw::mark::IMark *)p;
if( rBkmk.GetMarkPos().nNode == nNd &&
(nCntnt = rBkmk.GetMarkPos().nContent.GetIndex() ) >= nStt &&
nCntnt < nEnd )
{
rArr.Insert( p, rArr.Count() );
}
else if( rBkmk.IsExpanded() && nNd ==
rBkmk.GetOtherMarkPos().nNode.GetIndex() && (nCntnt =
rBkmk.GetOtherMarkPos().nContent.GetIndex() ) >= nStt &&
nCntnt < nEnd )
{
rArr.Insert( p, rArr.Count() );
}
}
}
}
return rArr.Count();
}
////////////////////////////////////////////////////////////////////////////
// Storage-spezifisches
sal_uLong StgWriter::WriteStream()
{
ASSERT( !this, "Schreiben in Streams auf einem Storage?" );
return ERR_SWG_WRITE_ERROR;
}
sal_uLong StgWriter::Write( SwPaM& rPaM, SvStorage& rStg, const String* pFName )
{
SetStream(0);
pStg = &rStg;
pDoc = rPaM.GetDoc();
pOrigFileName = pFName;
// PaM kopieren, damit er veraendert werden kann
pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
// zum Vergleich auf den akt. Pam sichern
pOrigPam = &rPaM;
sal_uLong nRet = WriteStorage();
pStg = NULL;
ResetWriter();
return nRet;
}
sal_uLong StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const String* pFName, SfxMedium* pMedium )
{
SetStream(0);
pStg = 0;
xStg = rStg;
pDoc = rPaM.GetDoc();
pOrigFileName = pFName;
// PaM kopieren, damit er veraendert werden kann
pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
// zum Vergleich auf den akt. Pam sichern
pOrigPam = &rPaM;
sal_uLong nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
pStg = NULL;
ResetWriter();
return nRet;
}