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
);
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
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() )
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() ) )
381 // wurde die Datei schon verschoben
383 if( pImpl
->pSrcArr
->Seek_Entry( &rFileNm
, &nPos
))
385 rFileNm
= *(*pImpl
->pDestArr
)[ nPos
];
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();
407 bRet
= 0 == aDstFile
.GetError();
411 pImpl
->pSrcArr
->Insert( pSrc
);
412 pImpl
->pDestArr
->Insert( pDest
);
424 void Writer::PutNumFmtFontsInAttrPool()
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();
439 const Font
* pDefFont
= &numfunc::GetDefBulletFont();
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() ) )
454 if( *pFont
== *pDefFont
)
457 else if( *pFont
== *pDefFont
)
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
)
469 pImpl
= new Writer_Impl( *pDoc
);
471 SfxItemPool
& rPool
= pDoc
->GetAttrPool();
472 if( rPool
.GetSecondaryPool() )
474 _AddFontItems( rPool
, EE_CHAR_FONTINFO
);
477 _AddFontItems( rPool
, EE_CHAR_FONTINFO_CJK
);
478 _AddFontItems( rPool
, EE_CHAR_FONTINFO_CTL
);
483 void Writer::PutCJKandCTLFontsInAttrPool()
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
);
518 pItem
= (SvxFontItem
*)&rPool
.Put( rFont
);
520 if( 1 < pItem
->GetRefCount() )
521 rPool
.Remove( *pItem
);
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();
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;
554 // there exist some bookmarks, search now all which is in the range
555 if( !nStt
&& nEnd
== rNd
.Len() )
557 rArr
.Insert( pArr
, 0 );
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
&&
570 rArr
.Insert( p
, rArr
.Count() );
572 else if( rBkmk
.IsExpanded() && nNd
==
573 rBkmk
.GetOtherMarkPos().nNode
.GetIndex() && (nCntnt
=
574 rBkmk
.GetOtherMarkPos().nContent
.GetIndex() ) >= nStt
&&
577 rArr
.Insert( p
, 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
)
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
608 ULONG nRet
= WriteStorage();
616 ULONG
StgWriter::Write( SwPaM
& rPaM
, const uno::Reference
< embed::XStorage
>& rStg
, const String
* pFName
, SfxMedium
* pMedium
)
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
630 ULONG nRet
= pMedium
? WriteMedium( *pMedium
) : WriteStorage();