update dev300-m58
[ooovba.git] / sw / source / filter / writer / writer.cxx
blob725f5097c8a1bd6cdca4f5db637991ffa4289125
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 );
344 // return IsStgWriter()
345 // ? Write( rPam, rMed.GetStorage(), pFileName )
346 // : Write( rPam, *rMed.GetOutStream(), pFileName );
349 ULONG Writer::Write( SwPaM& /*rPam*/, SvStorage&, const String* )
351 ASSERT( !this, "Schreiben in Storages auf einem Stream?" );
352 return ERR_SWG_WRITE_ERROR;
355 ULONG Writer::Write( SwPaM&, const uno::Reference < embed::XStorage >&, const String*, SfxMedium* )
357 ASSERT( !this, "Schreiben in Storages auf einem Stream?" );
358 return ERR_SWG_WRITE_ERROR;
361 BOOL Writer::CopyLocalFileToINet( String& rFileNm )
363 if( !pOrigFileName ) // can be happen, by example if we
364 return FALSE; // write into the clipboard
366 BOOL bRet = FALSE;
367 INetURLObject aFileUrl( rFileNm ), aTargetUrl( *pOrigFileName );
369 // JP 01.11.00: what is the correct question for the portal??
370 // if( aFileUrl.GetProtocol() == aFileUrl.GetProtocol() )
371 // return bRet;
372 // this is our old without the Mail-Export
373 if( ! ( INET_PROT_FILE == aFileUrl.GetProtocol() &&
374 INET_PROT_FILE != aTargetUrl.GetProtocol() &&
375 INET_PROT_FTP <= aTargetUrl.GetProtocol() &&
376 INET_PROT_NEWS >= aTargetUrl.GetProtocol() ) )
377 return bRet;
379 if( pImpl->pSrcArr )
381 // wurde die Datei schon verschoben
382 USHORT nPos;
383 if( pImpl->pSrcArr->Seek_Entry( &rFileNm, &nPos ))
385 rFileNm = *(*pImpl->pDestArr)[ nPos ];
386 return TRUE;
389 else
391 pImpl->pSrcArr = new SvStringsSortDtor( 4, 4 );
392 pImpl->pDestArr = new SvStringsSortDtor( 4, 4 );
395 String *pSrc = new String( rFileNm );
396 String *pDest = new String( aTargetUrl.GetPartBeforeLastName() );
397 *pDest += String(aFileUrl.GetName());
399 SfxMedium aSrcFile( *pSrc, STREAM_READ, FALSE );
400 SfxMedium aDstFile( *pDest, STREAM_WRITE | STREAM_SHARE_DENYNONE, FALSE );
402 *aDstFile.GetOutStream() << *aSrcFile.GetInStream();
404 aSrcFile.Close();
405 aDstFile.Commit();
407 bRet = 0 == aDstFile.GetError();
409 if( bRet )
411 pImpl->pSrcArr->Insert( pSrc );
412 pImpl->pDestArr->Insert( pDest );
413 rFileNm = *pDest;
415 else
417 delete pSrc;
418 delete pDest;
421 return bRet;
424 void Writer::PutNumFmtFontsInAttrPool()
426 if( !pImpl )
427 pImpl = new Writer_Impl( *pDoc );
429 // dann gibt es noch in den NumRules ein paar Fonts
430 // Diese in den Pool putten. Haben sie danach einen RefCount > 1
431 // kann es wieder entfernt werden - ist schon im Pool
432 SfxItemPool& rPool = pDoc->GetAttrPool();
433 const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl();
434 const SwNumRule* pRule;
435 const SwNumFmt* pFmt;
436 // --> OD 2006-06-27 #b644095#
437 // const Font *pFont, *pDefFont = &SwNumRule::GetDefBulletFont();
438 const Font* pFont;
439 const Font* pDefFont = &numfunc::GetDefBulletFont();
440 // <--
441 BOOL bCheck = FALSE;
443 for( USHORT nGet = rListTbl.Count(); nGet; )
444 if( pDoc->IsUsed( *(pRule = rListTbl[ --nGet ] )))
445 for( BYTE nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
446 if( SVX_NUM_CHAR_SPECIAL == (pFmt = &pRule->Get( nLvl ))->GetNumberingType() ||
447 SVX_NUM_BITMAP == pFmt->GetNumberingType() )
449 if( 0 == ( pFont = pFmt->GetBulletFont() ) )
450 pFont = pDefFont;
452 if( bCheck )
454 if( *pFont == *pDefFont )
455 continue;
457 else if( *pFont == *pDefFont )
458 bCheck = TRUE;
460 _AddFontItem( rPool, SvxFontItem( pFont->GetFamily(),
461 pFont->GetName(), pFont->GetStyleName(),
462 pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT ));
466 void Writer::PutEditEngFontsInAttrPool( BOOL bIncl_CJK_CTL )
468 if( !pImpl )
469 pImpl = new Writer_Impl( *pDoc );
471 SfxItemPool& rPool = pDoc->GetAttrPool();
472 if( rPool.GetSecondaryPool() )
474 _AddFontItems( rPool, EE_CHAR_FONTINFO );
475 if( bIncl_CJK_CTL )
477 _AddFontItems( rPool, EE_CHAR_FONTINFO_CJK );
478 _AddFontItems( rPool, EE_CHAR_FONTINFO_CTL );
483 void Writer::PutCJKandCTLFontsInAttrPool()
485 if( !pImpl )
486 pImpl = new Writer_Impl( *pDoc );
488 SfxItemPool& rPool = pDoc->GetAttrPool();
489 _AddFontItems( rPool, RES_CHRATR_CJK_FONT );
490 _AddFontItems( rPool, RES_CHRATR_CTL_FONT );
494 void Writer::_AddFontItems( SfxItemPool& rPool, USHORT nW )
496 const SvxFontItem* pFont = (const SvxFontItem*)&rPool.GetDefaultItem( nW );
497 _AddFontItem( rPool, *pFont );
499 if( 0 != ( pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem( nW )) )
500 _AddFontItem( rPool, *pFont );
502 USHORT nMaxItem = rPool.GetItemCount( nW );
503 for( USHORT nGet = 0; nGet < nMaxItem; ++nGet )
504 if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem( nW, nGet )) )
505 _AddFontItem( rPool, *pFont );
508 void Writer::_AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
510 const SvxFontItem* pItem;
511 if( RES_CHRATR_FONT != rFont.Which() )
513 SvxFontItem aFont( rFont );
514 aFont.SetWhich( RES_CHRATR_FONT );
515 pItem = (SvxFontItem*)&rPool.Put( aFont );
517 else
518 pItem = (SvxFontItem*)&rPool.Put( rFont );
520 if( 1 < pItem->GetRefCount() )
521 rPool.Remove( *pItem );
522 else
524 if( !pImpl->pFontRemoveLst )
525 pImpl->pFontRemoveLst = new SvPtrarr( 0, 10 );
527 void* p = (void*)pItem;
528 pImpl->pFontRemoveLst->Insert( p, pImpl->pFontRemoveLst->Count() );
532 // build a bookmark table, which is sort by the node position. The
533 // OtherPos of the bookmarks also inserted.
534 void Writer::CreateBookmarkTbl()
536 const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
537 for(IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getBookmarksBegin();
538 ppBkmk != pMarkAccess->getBookmarksEnd();
539 ++ppBkmk)
540 pImpl->InsertBkmk(**ppBkmk);
544 // search alle Bookmarks in the range and return it in the Array
545 USHORT Writer::GetBookmarks(const SwCntntNode& rNd, xub_StrLen nStt,
546 xub_StrLen nEnd, SvPtrarr& rArr)
548 ASSERT( !rArr.Count(), "es sind noch Eintraege vorhanden" );
550 ULONG nNd = rNd.GetIndex();
551 SvPtrarr* pArr = pImpl->pBkmkNodePos ? pImpl->pBkmkNodePos->Get( nNd ) : 0;
552 if( pArr )
554 // there exist some bookmarks, search now all which is in the range
555 if( !nStt && nEnd == rNd.Len() )
556 // all
557 rArr.Insert( pArr, 0 );
558 else
560 USHORT n;
561 xub_StrLen nCntnt;
562 for( n = 0; n < pArr->Count(); ++n )
564 void* p = (*pArr)[ n ];
565 const ::sw::mark::IMark& rBkmk = *(::sw::mark::IMark *)p;
566 if( rBkmk.GetMarkPos().nNode == nNd &&
567 (nCntnt = rBkmk.GetMarkPos().nContent.GetIndex() ) >= nStt &&
568 nCntnt < nEnd )
570 rArr.Insert( p, rArr.Count() );
572 else if( rBkmk.IsExpanded() && nNd ==
573 rBkmk.GetOtherMarkPos().nNode.GetIndex() && (nCntnt =
574 rBkmk.GetOtherMarkPos().nContent.GetIndex() ) >= nStt &&
575 nCntnt < nEnd )
577 rArr.Insert( p, rArr.Count() );
582 return rArr.Count();
585 ////////////////////////////////////////////////////////////////////////////
587 // Storage-spezifisches
589 ULONG StgWriter::WriteStream()
591 ASSERT( !this, "Schreiben in Streams auf einem Storage?" );
592 return ERR_SWG_WRITE_ERROR;
595 ULONG StgWriter::Write( SwPaM& rPaM, SvStorage& rStg, const String* pFName )
597 pStrm = 0;
598 pStg = &rStg;
599 pDoc = rPaM.GetDoc();
600 pOrigFileName = pFName;
601 pImpl = new Writer_Impl( *pDoc );
603 // PaM kopieren, damit er veraendert werden kann
604 pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
605 // zum Vergleich auf den akt. Pam sichern
606 pOrigPam = &rPaM;
608 ULONG nRet = WriteStorage();
610 pStg = NULL;
611 ResetWriter();
613 return nRet;
616 ULONG StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const String* pFName, SfxMedium* pMedium )
618 pStrm = 0;
619 pStg = 0;
620 xStg = rStg;
621 pDoc = rPaM.GetDoc();
622 pOrigFileName = pFName;
623 pImpl = new Writer_Impl( *pDoc );
625 // PaM kopieren, damit er veraendert werden kann
626 pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
627 // zum Vergleich auf den akt. Pam sichern
628 pOrigPam = &rPaM;
630 ULONG nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
632 pStg = NULL;
633 ResetWriter();
635 return nRet;