merge the formfield patch from ooo-build
[ooovba.git] / sw / source / filter / writer / writer.cxx
blobe0a2067cfc9009900ac988f16bff296cc639fbd9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: writer.cxx,v $
10 * $Revision: 1.26 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include <hintids.hxx>
35 #define _SVSTDARR_STRINGSSORTDTOR
36 #include <svtools/svstdarr.hxx>
38 #include <sot/storage.hxx>
39 #include <sfx2/docfile.hxx>
40 #include <svtools/urihelper.hxx>
41 #include <svtools/filter.hxx>
42 #include <svx/impgrf.hxx>
43 #include <svx/fontitem.hxx>
44 #include <svx/eeitem.hxx>
45 #include <shellio.hxx>
46 #include <pam.hxx>
47 #include <doc.hxx>
48 #include <docary.hxx>
49 #include <IMark.hxx>
50 #include <numrule.hxx>
51 #include <swerror.h>
52 #include <boost/bind.hpp>
54 using namespace ::com::sun::star;
57 // Stringbuffer fuer die umgewandelten Zahlen
58 static sal_Char aNToABuf[] = "0000000000000000000000000";
59 #define NTOABUFLEN (sizeof(aNToABuf))
61 DECLARE_TABLE( SwBookmarkNodeTable, SvPtrarr* )
63 struct Writer_Impl
65 SvStringsSortDtor *pSrcArr, *pDestArr;
66 SvPtrarr* pFontRemoveLst, *pBkmkArr;
67 SwBookmarkNodeTable* pBkmkNodePos;
69 Writer_Impl( const SwDoc& rDoc );
70 ~Writer_Impl();
72 void RemoveFontList( SwDoc& rDoc );
73 void InsertBkmk( const ::sw::mark::IMark& rBkmk );
76 Writer_Impl::Writer_Impl( const SwDoc& /*rDoc*/ )
77 : pSrcArr( 0 ), pDestArr( 0 ), pFontRemoveLst( 0 ), pBkmkNodePos( 0 )
81 Writer_Impl::~Writer_Impl()
83 delete pSrcArr;
84 delete pDestArr;
85 delete pFontRemoveLst;
87 if( pBkmkNodePos )
89 for( SvPtrarr* p = pBkmkNodePos->First(); p; p = pBkmkNodePos->Next() )
90 delete p;
91 delete pBkmkNodePos;
95 void Writer_Impl::RemoveFontList( SwDoc& rDoc )
97 ASSERT( pFontRemoveLst, "wo ist die FontListe?" );
98 for( USHORT i = pFontRemoveLst->Count(); i; )
100 SvxFontItem* pItem = (SvxFontItem*)(*pFontRemoveLst)[ --i ];
101 rDoc.GetAttrPool().Remove( *pItem );
105 void Writer_Impl::InsertBkmk(const ::sw::mark::IMark& rBkmk)
107 if( !pBkmkNodePos )
108 pBkmkNodePos = new SwBookmarkNodeTable;
110 ULONG nNd = rBkmk.GetMarkPos().nNode.GetIndex();
111 SvPtrarr* pArr = pBkmkNodePos->Get( nNd );
112 if( !pArr )
114 pArr = new SvPtrarr( 1, 4 );
115 pBkmkNodePos->Insert( nNd, pArr );
118 void* p = (void*)&rBkmk;
119 pArr->Insert( p, pArr->Count() );
121 if(rBkmk.IsExpanded() && rBkmk.GetOtherMarkPos().nNode != nNd)
123 nNd = rBkmk.GetOtherMarkPos().nNode.GetIndex();
124 pArr = pBkmkNodePos->Get( nNd );
125 if( !pArr )
127 pArr = new SvPtrarr( 1, 4 );
128 pBkmkNodePos->Insert( nNd, pArr );
130 pArr->Insert( p, pArr->Count() );
135 * Dieses Modul ist die Zentrale-Sammelstelle fuer alle Write-Filter
136 * und ist eine DLL !
138 * Damit der Writer mit den unterschiedlichen Writern arbeiten kann,
139 * muessen fuer diese die Ausgabe-Funktionen der Inhalts tragenden
140 * Objecte auf die verschiedenen Ausgabe-Funktionen gemappt werden.
142 * Dazu kann fuer jedes Object ueber den Which-Wert in einen Tabelle ge-
143 * griffen werden, um seine Ausgabe-Funktion zu erfragen.
144 * Diese Funktionen stehen in den entsprechenden Writer-DLL's.
147 Writer::Writer()
148 : pImpl(0), pStrm(0), pOrigPam(0), pOrigFileName(0), pDoc(0), pCurPam(0)
150 bWriteAll = bShowProgress = bUCS2_WithStartChar = true;
151 bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
152 bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
153 bOrganizerMode = false;
154 bExportPargraphNumbering = sal_True;
157 Writer::~Writer()
162 * Document Interface Access
164 IDocumentSettingAccess* Writer::getIDocumentSettingAccess() { return pDoc; }
165 const IDocumentSettingAccess* Writer::getIDocumentSettingAccess() const { return pDoc; }
166 IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() { return pDoc; }
167 const IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() const { return pDoc; }
169 void Writer::ResetWriter()
171 if( pImpl && pImpl->pFontRemoveLst )
172 pImpl->RemoveFontList( *pDoc );
173 delete pImpl, pImpl = 0;
175 if( pCurPam )
177 while( pCurPam->GetNext() != pCurPam )
178 delete pCurPam->GetNext();
179 delete pCurPam;
181 pCurPam = 0;
182 pOrigFileName = 0;
183 pDoc = 0;
184 pStrm = 0;
186 bShowProgress = bUCS2_WithStartChar = TRUE;
187 bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
188 bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
189 bOrganizerMode = FALSE;
192 BOOL Writer::CopyNextPam( SwPaM ** ppPam )
194 if( (*ppPam)->GetNext() == pOrigPam )
196 *ppPam = pOrigPam; // wieder auf den Anfangs-Pam setzen
197 return FALSE; // Ende vom Ring
200 // ansonsten kopiere den die Werte aus dem naechsten Pam
201 *ppPam = ((SwPaM*)(*ppPam)->GetNext() );
203 *pCurPam->GetPoint() = *(*ppPam)->Start();
204 *pCurPam->GetMark() = *(*ppPam)->End();
206 return TRUE;
209 // suche die naechste Bookmark-Position aus der Bookmark-Tabelle
211 sal_Int32 Writer::FindPos_Bkmk(const SwPosition& rPos) const
213 const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
214 const IDocumentMarkAccess::const_iterator_t ppBkmk = ::std::lower_bound(
215 pMarkAccess->getMarksBegin(),
216 pMarkAccess->getMarksEnd(),
217 rPos,
218 ::boost::bind(&::sw::mark::IMark::StartsBefore, _1, _2)); // find the first Mark that does not start before
219 if(ppBkmk != pMarkAccess->getMarksEnd())
220 return ppBkmk - pMarkAccess->getMarksBegin();
221 return -1;
225 SwPaM* Writer::NewSwPaM( SwDoc & rDoc, ULONG nStartIdx, ULONG nEndIdx,
226 BOOL bNodesArray )
228 SwNodes* pNds = bNodesArray ? &rDoc.GetNodes() : (SwNodes*)rDoc.GetUndoNds();
230 SwNodeIndex aStt( *pNds, nStartIdx );
231 SwCntntNode* pCNode = aStt.GetNode().GetCntntNode();
232 if( !pCNode && 0 == ( pCNode = pNds->GoNext( &aStt )) )
234 ASSERT( false, "An StartPos kein ContentNode mehr" );
237 SwPaM* pNew = new SwPaM( aStt );
238 pNew->SetMark();
239 aStt = nEndIdx;
240 if( 0 == (pCNode = aStt.GetNode().GetCntntNode()) &&
241 0 == (pCNode = pNds->GoPrevious( &aStt )) )
243 ASSERT( false, "An StartPos kein ContentNode mehr" );
245 pCNode->MakeEndIndex( &pNew->GetPoint()->nContent );
246 pNew->GetPoint()->nNode = aStt;
247 return pNew;
250 /////////////////////////////////////////////////////////////////////////////
252 // Stream-spezifisches
253 #ifndef PRODUCT
254 SvStream& Writer::Strm()
256 ASSERT( pStrm, "Oh-oh. Dies ist ein Storage-Writer. Gleich knallts!" );
257 return *pStrm;
259 #endif
262 SvStream& Writer::OutHex( SvStream& rStrm, ULONG nHex, BYTE nLen )
263 { // in einen Stream aus
264 // Pointer an das Bufferende setzen
265 sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
266 for( BYTE n = 0; n < nLen; ++n )
268 *(--pStr) = (sal_Char)(nHex & 0xf ) + 48;
269 if( *pStr > '9' )
270 *pStr += 39;
271 nHex >>= 4;
273 return rStrm << pStr;
276 SvStream& Writer::OutLong( SvStream& rStrm, long nVal )
278 // Pointer an das Bufferende setzen
279 sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
281 int bNeg = nVal < 0;
282 if( bNeg )
283 nVal = -nVal;
285 do {
286 *(--pStr) = (sal_Char)(nVal % 10 ) + 48;
287 nVal /= 10;
288 } while( nVal );
290 // Ist Zahl negativ, dann noch -
291 if( bNeg )
292 *(--pStr) = '-';
294 return rStrm << pStr;
297 SvStream& Writer::OutULong( SvStream& rStrm, ULONG nVal )
299 // Pointer an das Bufferende setzen
300 sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
302 do {
303 *(--pStr) = (sal_Char)(nVal % 10 ) + 48;
304 nVal /= 10;
305 } while ( nVal );
306 return rStrm << pStr;
310 ULONG Writer::Write( SwPaM& rPaM, SvStream& rStrm, const String* pFName )
312 if ( IsStgWriter() )
314 SotStorageRef aRef = new SotStorage( rStrm );
315 ULONG nResult = Write( rPaM, *aRef, pFName );
316 if ( nResult == ERRCODE_NONE )
317 aRef->Commit();
318 return nResult;
321 pStrm = &rStrm;
322 pDoc = rPaM.GetDoc();
323 pOrigFileName = pFName;
324 pImpl = new Writer_Impl( *pDoc );
326 // PaM kopieren, damit er veraendert werden kann
327 pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
328 // zum Vergleich auf den akt. Pam sichern
329 pOrigPam = &rPaM;
331 ULONG nRet = WriteStream();
333 ResetWriter();
335 return nRet;
338 ULONG Writer::Write( SwPaM& rPam, SfxMedium& rMed, const String* pFileName )
340 // This method must be overloaded in SwXMLWriter a storage from medium will be used there.
341 // The microsoft format can write to storage but the storage will be based on the stream.
342 return Write( rPam, *rMed.GetOutStream(), pFileName );
345 ULONG Writer::Write( SwPaM& /*rPam*/, SvStorage&, const String* )
347 ASSERT( !this, "Schreiben in Storages auf einem Stream?" );
348 return ERR_SWG_WRITE_ERROR;
351 ULONG Writer::Write( SwPaM&, const uno::Reference < embed::XStorage >&, const String*, SfxMedium* )
353 ASSERT( !this, "Schreiben in Storages auf einem Stream?" );
354 return ERR_SWG_WRITE_ERROR;
357 BOOL Writer::CopyLocalFileToINet( String& rFileNm )
359 if( !pOrigFileName ) // can be happen, by example if we
360 return FALSE; // write into the clipboard
362 BOOL bRet = FALSE;
363 INetURLObject aFileUrl( rFileNm ), aTargetUrl( *pOrigFileName );
365 // JP 01.11.00: what is the correct question for the portal??
366 // if( aFileUrl.GetProtocol() == aFileUrl.GetProtocol() )
367 // return bRet;
368 // this is our old without the Mail-Export
369 if( ! ( INET_PROT_FILE == aFileUrl.GetProtocol() &&
370 INET_PROT_FILE != aTargetUrl.GetProtocol() &&
371 INET_PROT_FTP <= aTargetUrl.GetProtocol() &&
372 INET_PROT_NEWS >= aTargetUrl.GetProtocol() ) )
373 return bRet;
375 if( pImpl->pSrcArr )
377 // wurde die Datei schon verschoben
378 USHORT nPos;
379 if( pImpl->pSrcArr->Seek_Entry( &rFileNm, &nPos ))
381 rFileNm = *(*pImpl->pDestArr)[ nPos ];
382 return TRUE;
385 else
387 pImpl->pSrcArr = new SvStringsSortDtor( 4, 4 );
388 pImpl->pDestArr = new SvStringsSortDtor( 4, 4 );
391 String *pSrc = new String( rFileNm );
392 String *pDest = new String( aTargetUrl.GetPartBeforeLastName() );
393 *pDest += String(aFileUrl.GetName());
395 SfxMedium aSrcFile( *pSrc, STREAM_READ, FALSE );
396 SfxMedium aDstFile( *pDest, STREAM_WRITE | STREAM_SHARE_DENYNONE, FALSE );
398 *aDstFile.GetOutStream() << *aSrcFile.GetInStream();
400 aSrcFile.Close();
401 aDstFile.Commit();
403 bRet = 0 == aDstFile.GetError();
405 if( bRet )
407 pImpl->pSrcArr->Insert( pSrc );
408 pImpl->pDestArr->Insert( pDest );
409 rFileNm = *pDest;
411 else
413 delete pSrc;
414 delete pDest;
417 return bRet;
420 void Writer::PutNumFmtFontsInAttrPool()
422 if( !pImpl )
423 pImpl = new Writer_Impl( *pDoc );
425 // dann gibt es noch in den NumRules ein paar Fonts
426 // Diese in den Pool putten. Haben sie danach einen RefCount > 1
427 // kann es wieder entfernt werden - ist schon im Pool
428 SfxItemPool& rPool = pDoc->GetAttrPool();
429 const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl();
430 const SwNumRule* pRule;
431 const SwNumFmt* pFmt;
432 // --> OD 2006-06-27 #b644095#
433 // const Font *pFont, *pDefFont = &SwNumRule::GetDefBulletFont();
434 const Font* pFont;
435 const Font* pDefFont = &numfunc::GetDefBulletFont();
436 // <--
437 BOOL bCheck = FALSE;
439 for( USHORT nGet = rListTbl.Count(); nGet; )
440 if( pDoc->IsUsed( *(pRule = rListTbl[ --nGet ] )))
441 for( BYTE nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
442 if( SVX_NUM_CHAR_SPECIAL == (pFmt = &pRule->Get( nLvl ))->GetNumberingType() ||
443 SVX_NUM_BITMAP == pFmt->GetNumberingType() )
445 if( 0 == ( pFont = pFmt->GetBulletFont() ) )
446 pFont = pDefFont;
448 if( bCheck )
450 if( *pFont == *pDefFont )
451 continue;
453 else if( *pFont == *pDefFont )
454 bCheck = TRUE;
456 _AddFontItem( rPool, SvxFontItem( pFont->GetFamily(),
457 pFont->GetName(), pFont->GetStyleName(),
458 pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT ));
462 void Writer::PutEditEngFontsInAttrPool( BOOL bIncl_CJK_CTL )
464 if( !pImpl )
465 pImpl = new Writer_Impl( *pDoc );
467 SfxItemPool& rPool = pDoc->GetAttrPool();
468 if( rPool.GetSecondaryPool() )
470 _AddFontItems( rPool, EE_CHAR_FONTINFO );
471 if( bIncl_CJK_CTL )
473 _AddFontItems( rPool, EE_CHAR_FONTINFO_CJK );
474 _AddFontItems( rPool, EE_CHAR_FONTINFO_CTL );
479 void Writer::PutCJKandCTLFontsInAttrPool()
481 if( !pImpl )
482 pImpl = new Writer_Impl( *pDoc );
484 SfxItemPool& rPool = pDoc->GetAttrPool();
485 _AddFontItems( rPool, RES_CHRATR_CJK_FONT );
486 _AddFontItems( rPool, RES_CHRATR_CTL_FONT );
490 void Writer::_AddFontItems( SfxItemPool& rPool, USHORT nW )
492 const SvxFontItem* pFont = (const SvxFontItem*)&rPool.GetDefaultItem( nW );
493 _AddFontItem( rPool, *pFont );
495 if( 0 != ( pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem( nW )) )
496 _AddFontItem( rPool, *pFont );
498 USHORT nMaxItem = rPool.GetItemCount( nW );
499 for( USHORT nGet = 0; nGet < nMaxItem; ++nGet )
500 if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem( nW, nGet )) )
501 _AddFontItem( rPool, *pFont );
504 void Writer::_AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
506 const SvxFontItem* pItem;
507 if( RES_CHRATR_FONT != rFont.Which() )
509 SvxFontItem aFont( rFont );
510 aFont.SetWhich( RES_CHRATR_FONT );
511 pItem = (SvxFontItem*)&rPool.Put( aFont );
513 else
514 pItem = (SvxFontItem*)&rPool.Put( rFont );
516 if( 1 < pItem->GetRefCount() )
517 rPool.Remove( *pItem );
518 else
520 if( !pImpl->pFontRemoveLst )
521 pImpl->pFontRemoveLst = new SvPtrarr( 0, 10 );
523 void* p = (void*)pItem;
524 pImpl->pFontRemoveLst->Insert( p, pImpl->pFontRemoveLst->Count() );
528 // build a bookmark table, which is sort by the node position. The
529 // OtherPos of the bookmarks also inserted.
530 void Writer::CreateBookmarkTbl()
532 const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
533 for(IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getBookmarksBegin();
534 ppBkmk != pMarkAccess->getBookmarksEnd();
535 ++ppBkmk)
536 pImpl->InsertBkmk(**ppBkmk);
540 // search alle Bookmarks in the range and return it in the Array
541 USHORT Writer::GetBookmarks(const SwCntntNode& rNd, xub_StrLen nStt,
542 xub_StrLen nEnd, SvPtrarr& rArr)
544 ASSERT( !rArr.Count(), "es sind noch Eintraege vorhanden" );
546 ULONG nNd = rNd.GetIndex();
547 SvPtrarr* pArr = pImpl->pBkmkNodePos ? pImpl->pBkmkNodePos->Get( nNd ) : 0;
548 if( pArr )
550 // there exist some bookmarks, search now all which is in the range
551 if( !nStt && nEnd == rNd.Len() )
552 // all
553 rArr.Insert( pArr, 0 );
554 else
556 USHORT n;
557 xub_StrLen nCntnt;
558 for( n = 0; n < pArr->Count(); ++n )
560 void* p = (*pArr)[ n ];
561 const ::sw::mark::IMark& rBkmk = *(::sw::mark::IMark *)p;
562 if( rBkmk.GetMarkPos().nNode == nNd &&
563 (nCntnt = rBkmk.GetMarkPos().nContent.GetIndex() ) >= nStt &&
564 nCntnt < nEnd )
566 rArr.Insert( p, rArr.Count() );
568 else if( rBkmk.IsExpanded() && nNd ==
569 rBkmk.GetOtherMarkPos().nNode.GetIndex() && (nCntnt =
570 rBkmk.GetOtherMarkPos().nContent.GetIndex() ) >= nStt &&
571 nCntnt < nEnd )
573 rArr.Insert( p, rArr.Count() );
578 return rArr.Count();
581 ////////////////////////////////////////////////////////////////////////////
583 // Storage-spezifisches
585 ULONG StgWriter::WriteStream()
587 ASSERT( !this, "Schreiben in Streams auf einem Storage?" );
588 return ERR_SWG_WRITE_ERROR;
591 ULONG StgWriter::Write( SwPaM& rPaM, SvStorage& rStg, const String* pFName )
593 pStrm = 0;
594 pStg = &rStg;
595 pDoc = rPaM.GetDoc();
596 pOrigFileName = pFName;
597 pImpl = new Writer_Impl( *pDoc );
599 // PaM kopieren, damit er veraendert werden kann
600 pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
601 // zum Vergleich auf den akt. Pam sichern
602 pOrigPam = &rPaM;
604 ULONG nRet = WriteStorage();
606 pStg = NULL;
607 ResetWriter();
609 return nRet;
612 ULONG StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const String* pFName, SfxMedium* pMedium )
614 pStrm = 0;
615 pStg = 0;
616 xStg = rStg;
617 pDoc = rPaM.GetDoc();
618 pOrigFileName = pFName;
619 pImpl = new Writer_Impl( *pDoc );
621 // PaM kopieren, damit er veraendert werden kann
622 pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
623 // zum Vergleich auf den akt. Pam sichern
624 pOrigPam = &rPaM;
626 ULONG nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
628 pStg = NULL;
629 ResetWriter();
631 return nRet;