1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: writer.cxx,v $
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>
50 #include <numrule.hxx>
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
* )
65 SvStringsSortDtor
*pSrcArr
, *pDestArr
;
66 SvPtrarr
* pFontRemoveLst
, *pBkmkArr
;
67 SwBookmarkNodeTable
* pBkmkNodePos
;
69 Writer_Impl( const SwDoc
& rDoc
);
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()
85 delete pFontRemoveLst
;
89 for( SvPtrarr
* p
= pBkmkNodePos
->First(); p
; p
= pBkmkNodePos
->Next() )
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
)
108 pBkmkNodePos
= new SwBookmarkNodeTable
;
110 ULONG nNd
= rBkmk
.GetMarkPos().nNode
.GetIndex();
111 SvPtrarr
* pArr
= pBkmkNodePos
->Get( nNd
);
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
);
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
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.
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
;
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;
177 while( pCurPam
->GetNext() != pCurPam
)
178 delete pCurPam
->GetNext();
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();
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(),
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();
225 SwPaM
* Writer::NewSwPaM( SwDoc
& rDoc
, ULONG nStartIdx
, ULONG nEndIdx
,
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
);
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
;
250 /////////////////////////////////////////////////////////////////////////////
252 // Stream-spezifisches
254 SvStream
& Writer::Strm()
256 ASSERT( pStrm
, "Oh-oh. Dies ist ein Storage-Writer. Gleich knallts!" );
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;
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);
286 *(--pStr
) = (sal_Char
)(nVal
% 10 ) + 48;
290 // Ist Zahl negativ, dann noch -
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);
303 *(--pStr
) = (sal_Char
)(nVal
% 10 ) + 48;
306 return rStrm
<< pStr
;
310 ULONG
Writer::Write( SwPaM
& rPaM
, SvStream
& rStrm
, const String
* pFName
)
314 SotStorageRef aRef
= new SotStorage( rStrm
);
315 ULONG nResult
= Write( rPaM
, *aRef
, pFName
);
316 if ( nResult
== ERRCODE_NONE
)
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
331 ULONG nRet
= WriteStream();
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
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() )
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() ) )
377 // wurde die Datei schon verschoben
379 if( pImpl
->pSrcArr
->Seek_Entry( &rFileNm
, &nPos
))
381 rFileNm
= *(*pImpl
->pDestArr
)[ nPos
];
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();
403 bRet
= 0 == aDstFile
.GetError();
407 pImpl
->pSrcArr
->Insert( pSrc
);
408 pImpl
->pDestArr
->Insert( pDest
);
420 void Writer::PutNumFmtFontsInAttrPool()
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();
435 const Font
* pDefFont
= &numfunc::GetDefBulletFont();
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() ) )
450 if( *pFont
== *pDefFont
)
453 else if( *pFont
== *pDefFont
)
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
)
465 pImpl
= new Writer_Impl( *pDoc
);
467 SfxItemPool
& rPool
= pDoc
->GetAttrPool();
468 if( rPool
.GetSecondaryPool() )
470 _AddFontItems( rPool
, EE_CHAR_FONTINFO
);
473 _AddFontItems( rPool
, EE_CHAR_FONTINFO_CJK
);
474 _AddFontItems( rPool
, EE_CHAR_FONTINFO_CTL
);
479 void Writer::PutCJKandCTLFontsInAttrPool()
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
);
514 pItem
= (SvxFontItem
*)&rPool
.Put( rFont
);
516 if( 1 < pItem
->GetRefCount() )
517 rPool
.Remove( *pItem
);
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();
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;
550 // there exist some bookmarks, search now all which is in the range
551 if( !nStt
&& nEnd
== rNd
.Len() )
553 rArr
.Insert( pArr
, 0 );
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
&&
566 rArr
.Insert( p
, rArr
.Count() );
568 else if( rBkmk
.IsExpanded() && nNd
==
569 rBkmk
.GetOtherMarkPos().nNode
.GetIndex() && (nCntnt
=
570 rBkmk
.GetOtherMarkPos().nContent
.GetIndex() ) >= nStt
&&
573 rArr
.Insert( p
, 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
)
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
604 ULONG nRet
= WriteStorage();
612 ULONG
StgWriter::Write( SwPaM
& rPaM
, const uno::Reference
< embed::XStorage
>& rStg
, const String
* pFName
, SfxMedium
* pMedium
)
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
626 ULONG nRet
= pMedium
? WriteMedium( *pMedium
) : WriteStorage();