1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <hintids.hxx>
23 #include <sot/storage.hxx>
24 #include <sfx2/docfile.hxx>
25 #include <comphelper/diagnose_ex.hxx>
26 #include <editeng/fontitem.hxx>
27 #include <editeng/eeitem.hxx>
28 #include <osl/diagnose.h>
29 #include <shellio.hxx>
33 #include <IDocumentSettingAccess.hxx>
34 #include <IDocumentMarkAccess.hxx>
35 #include <numrule.hxx>
37 #include <com/sun/star/ucb/ContentCreationException.hpp>
41 typedef std::multimap
<SwNodeOffset
, const ::sw::mark::IMark
*> SwBookmarkNodeTable
;
47 std::map
<OUString
, OUString
> maFileNameMap
;
48 std::vector
<const SvxFontItem
*> aFontRemoveLst
;
49 SwBookmarkNodeTable aBkmkNodePos
;
53 void RemoveFontList( SwDoc
& rDoc
);
54 void InsertBkmk( const ::sw::mark::IMark
& rBkmk
);
57 Writer_Impl::Writer_Impl()
62 void Writer_Impl::RemoveFontList( SwDoc
& rDoc
)
64 for( const auto& rpFontItem
: aFontRemoveLst
)
66 rDoc
.GetAttrPool().Remove( *rpFontItem
);
70 void Writer_Impl::InsertBkmk(const ::sw::mark::IMark
& rBkmk
)
72 SwNodeOffset nNd
= rBkmk
.GetMarkPos().GetNodeIndex();
74 aBkmkNodePos
.emplace( nNd
, &rBkmk
);
76 if(rBkmk
.IsExpanded() && rBkmk
.GetOtherMarkPos().GetNodeIndex() != nNd
)
78 nNd
= rBkmk
.GetOtherMarkPos().GetNodeIndex();
79 aBkmkNodePos
.emplace( nNd
, &rBkmk
);
84 * This module is the central collection point for all writer-filters
87 * So that the Writer can work with different writers, the output-functions
88 * of the content carrying objects have to be mapped to the various
91 * For that, to inquire its output function, every object can be gripped
92 * via the which-value in a table.
93 * These functions are available in the corresponding Writer-DLL's.
97 : m_pImpl(std::make_unique
<Writer_Impl
>())
98 , m_pOrigFileName(nullptr), m_pDoc(nullptr), m_pOrigPam(nullptr)
99 , m_bHideDeleteRedlines(false)
101 m_bWriteAll
= m_bShowProgress
= m_bUCS2_WithStartChar
= true;
102 m_bASCII_NoLastLineEnd
= m_bASCII_ParaAsBlank
= m_bASCII_ParaAsCR
=
103 m_bWriteClipboardDoc
= m_bWriteOnlyFirstTable
= m_bBlock
=
104 m_bOrganizerMode
= false;
105 m_bExportParagraphNumbering
= true;
113 * Document Interface Access
115 IDocumentSettingAccess
& Writer::getIDocumentSettingAccess() { return m_pDoc
->getIDocumentSettingAccess(); }
116 const IDocumentSettingAccess
& Writer::getIDocumentSettingAccess() const { return m_pDoc
->getIDocumentSettingAccess(); }
117 IDocumentStylePoolAccess
& Writer::getIDocumentStylePoolAccess() { return m_pDoc
->getIDocumentStylePoolAccess(); }
118 const IDocumentStylePoolAccess
& Writer::getIDocumentStylePoolAccess() const { return m_pDoc
->getIDocumentStylePoolAccess(); }
120 void Writer::ResetWriter()
122 m_pImpl
->RemoveFontList( *m_pDoc
);
123 m_pImpl
.reset(new Writer_Impl
);
127 while (m_pCurrentPam
->GetNext() != m_pCurrentPam
.get())
128 delete m_pCurrentPam
->GetNext();
129 m_pCurrentPam
.reset();
131 m_pCurrentPam
= nullptr;
132 m_pOrigFileName
= nullptr;
135 m_bShowProgress
= m_bUCS2_WithStartChar
= true;
136 m_bASCII_NoLastLineEnd
= m_bASCII_ParaAsBlank
= m_bASCII_ParaAsCR
=
137 m_bWriteClipboardDoc
= m_bWriteOnlyFirstTable
= m_bBlock
=
138 m_bOrganizerMode
= false;
141 bool Writer::CopyNextPam( SwPaM
** ppPam
)
143 if( (*ppPam
)->GetNext() == m_pOrigPam
)
145 *ppPam
= m_pOrigPam
; // set back to the beginning pam
146 return false; // end of the ring
149 // otherwise copy the next value from the next Pam
150 *ppPam
= (*ppPam
)->GetNext();
152 *m_pCurrentPam
->GetPoint() = *(*ppPam
)->Start();
153 *m_pCurrentPam
->GetMark() = *(*ppPam
)->End();
158 // search the next Bookmark-Position from the Bookmark-Table
160 sal_Int32
Writer::FindPos_Bkmk(const SwPosition
& rPos
) const
162 const IDocumentMarkAccess
* const pMarkAccess
= m_pDoc
->getIDocumentMarkAccess();
163 const IDocumentMarkAccess::const_iterator_t ppBkmk
= pMarkAccess
->findFirstBookmarkStartsAfter(rPos
);
164 if(ppBkmk
!= pMarkAccess
->getBookmarksEnd())
165 return ppBkmk
- pMarkAccess
->getBookmarksBegin();
169 std::shared_ptr
<SwUnoCursor
>
170 Writer::NewUnoCursor(SwDoc
& rDoc
, SwNodeOffset
const nStartIdx
, SwNodeOffset
const nEndIdx
)
172 SwNodes
*const pNds
= &rDoc
.GetNodes();
174 SwNodeIndex
aStt( *pNds
, nStartIdx
);
175 SwContentNode
* pCNode
= aStt
.GetNode().GetContentNode();
176 if( !pCNode
&& nullptr == pNds
->GoNext( &aStt
) )
178 OSL_FAIL( "No more ContentNode at StartPos" );
181 auto const pNew
= rDoc
.CreateUnoCursor(SwPosition(aStt
), false);
184 pCNode
= aStt
.GetNode().GetContentNode();
186 pCNode
= SwNodes::GoPrevious(&aStt
);
187 assert(pCNode
&& "No more ContentNode at StartPos");
188 pNew
->GetPoint()->AssignEndIndex( *pCNode
);
193 SvStream
& Writer::Strm()
195 assert(m_pImpl
->m_pStream
&& "Oh-oh. Writer with no Stream!");
196 return *m_pImpl
->m_pStream
;
199 void Writer::SetStream(SvStream
*const pStream
)
201 m_pImpl
->m_pStream
= pStream
;
204 ErrCode
Writer::Write( SwPaM
& rPaM
, SvStream
& rStrm
, const OUString
* pFName
)
208 ErrCode nResult
= ERRCODE_ABORT
;
211 tools::SvRef
<SotStorage
> aRef
= new SotStorage( rStrm
);
212 nResult
= Write( rPaM
, *aRef
, pFName
);
213 if ( nResult
== ERRCODE_NONE
)
216 catch (const css::ucb::ContentCreationException
&)
218 TOOLS_WARN_EXCEPTION("sw", "Writer::Write caught");
223 m_pDoc
= &rPaM
.GetDoc();
224 m_pOrigFileName
= pFName
;
225 m_pImpl
->m_pStream
= &rStrm
;
227 // Copy PaM, so that it can be modified
228 m_pCurrentPam
= m_pDoc
->CreateUnoCursor(*rPaM
.End(), false);
229 m_pCurrentPam
->SetMark();
230 *m_pCurrentPam
->GetPoint() = *rPaM
.Start();
231 // for comparison secure to the current Pam
234 ErrCode nRet
= WriteStream();
241 void Writer::SetupFilterOptions(SfxMedium
& /*rMedium*/)
244 ErrCode
Writer::Write( SwPaM
& rPam
, SfxMedium
& rMedium
, const OUString
* pFileName
)
246 SetupFilterOptions(rMedium
);
247 // This method must be overridden in SwXMLWriter a storage from medium will be used there.
248 // The microsoft format can write to storage but the storage will be based on the stream.
249 return Write( rPam
, *rMedium
.GetOutStream(), pFileName
);
252 ErrCode
Writer::Write( SwPaM
& /*rPam*/, SotStorage
&, const OUString
* )
254 OSL_ENSURE( false, "Write in Storages on a stream?" );
255 return ERR_SWG_WRITE_ERROR
;
258 ErrCode
Writer::Write( SwPaM
&, const uno::Reference
< embed::XStorage
>&, const OUString
*, SfxMedium
* )
260 OSL_ENSURE( false, "Write in Storages on a stream?" );
261 return ERR_SWG_WRITE_ERROR
;
264 bool Writer::CopyLocalFileToINet( OUString
& rFileNm
)
266 if( !m_pOrigFileName
) // can be happen, by example if we
267 return false; // write into the clipboard
270 INetURLObject
aFileUrl( rFileNm
), aTargetUrl( *m_pOrigFileName
);
272 // this is our old without the Mail-Export
273 if( ! ( INetProtocol::File
== aFileUrl
.GetProtocol() &&
274 INetProtocol::File
!= aTargetUrl
.GetProtocol() &&
275 INetProtocol::Ftp
<= aTargetUrl
.GetProtocol() &&
276 INetProtocol::VndSunStarWebdav
>= aTargetUrl
.GetProtocol() ) )
279 // has the file been moved?
280 std::map
<OUString
, OUString
>::iterator it
= m_pImpl
->maFileNameMap
.find( rFileNm
);
281 if ( it
!= m_pImpl
->maFileNameMap
.end() )
283 rFileNm
= it
->second
;
287 OUString aSrc
= rFileNm
;
288 OUString aDest
= aTargetUrl
.GetPartBeforeLastName() + aFileUrl
.GetLastName();
290 SfxMedium
aSrcFile( aSrc
, StreamMode::READ
);
291 SfxMedium
aDstFile( aDest
, StreamMode::WRITE
| StreamMode::SHARE_DENYNONE
);
293 aDstFile
.GetOutStream()->WriteStream( *aSrcFile
.GetInStream() );
298 bRet
= ERRCODE_NONE
== aDstFile
.GetError();
302 m_pImpl
->maFileNameMap
.insert( std::make_pair( aSrc
, aDest
) );
309 void Writer::PutNumFormatFontsInAttrPool()
311 // then there are a few fonts in the NumRules
312 // These put into the Pool. After this does they have a RefCount > 1
313 // it can be removed - it is already in the Pool
314 SfxItemPool
& rPool
= m_pDoc
->GetAttrPool();
315 const SwNumRuleTable
& rListTable
= m_pDoc
->GetNumRuleTable();
316 const SwNumFormat
* pFormat
;
317 const vcl::Font
* pDefFont
= &numfunc::GetDefBulletFont();
320 for( size_t nGet
= rListTable
.size(); nGet
; )
322 SwNumRule
const*const pRule
= rListTable
[ --nGet
];
323 if (m_pDoc
->IsUsed(*pRule
))
325 for( sal_uInt8 nLvl
= 0; nLvl
< MAXLEVEL
; ++nLvl
)
327 if( SVX_NUM_CHAR_SPECIAL
== (pFormat
= &pRule
->Get( nLvl
))->GetNumberingType() ||
328 SVX_NUM_BITMAP
== pFormat
->GetNumberingType() )
330 std::optional
<vcl::Font
> pFont
= pFormat
->GetBulletFont();
336 if( *pFont
== *pDefFont
)
339 else if( *pFont
== *pDefFont
)
342 AddFontItem( rPool
, SvxFontItem( pFont
->GetFamilyType(),
343 pFont
->GetFamilyName(), pFont
->GetStyleName(),
344 pFont
->GetPitch(), pFont
->GetCharSet(), RES_CHRATR_FONT
));
351 void Writer::PutEditEngFontsInAttrPool()
353 SfxItemPool
& rPool
= m_pDoc
->GetAttrPool();
354 if( rPool
.GetSecondaryPool() )
356 AddFontItems_( rPool
, EE_CHAR_FONTINFO
);
357 AddFontItems_( rPool
, EE_CHAR_FONTINFO_CJK
);
358 AddFontItems_( rPool
, EE_CHAR_FONTINFO_CTL
);
362 void Writer::AddFontItems_( SfxItemPool
& rPool
, sal_uInt16 nW
)
364 const SvxFontItem
* pFont
= static_cast<const SvxFontItem
*>(&rPool
.GetDefaultItem( nW
));
365 AddFontItem( rPool
, *pFont
);
367 pFont
= static_cast<const SvxFontItem
*>(rPool
.GetPoolDefaultItem( nW
));
368 if( nullptr != pFont
)
369 AddFontItem( rPool
, *pFont
);
371 for (const SfxPoolItem
* pItem
: rPool
.GetItemSurrogates(nW
))
372 AddFontItem( rPool
, *static_cast<const SvxFontItem
*>(pItem
) );
375 void Writer::AddFontItem( SfxItemPool
& rPool
, const SvxFontItem
& rFont
)
377 const SvxFontItem
* pItem
;
378 if( RES_CHRATR_FONT
!= rFont
.Which() )
380 SvxFontItem
aFont( rFont
);
381 aFont
.SetWhich( RES_CHRATR_FONT
);
382 pItem
= &rPool
.Put( aFont
);
385 pItem
= &rPool
.Put( rFont
);
387 if( 1 < pItem
->GetRefCount() )
388 rPool
.Remove( *pItem
);
391 m_pImpl
->aFontRemoveLst
.push_back( pItem
);
395 // build a bookmark table, which is sort by the node position. The
396 // OtherPos of the bookmarks also inserted.
397 void Writer::CreateBookmarkTable()
399 const IDocumentMarkAccess
* const pMarkAccess
= m_pDoc
->getIDocumentMarkAccess();
400 for(IDocumentMarkAccess::const_iterator_t ppBkmk
= pMarkAccess
->getBookmarksBegin();
401 ppBkmk
!= pMarkAccess
->getBookmarksEnd();
404 m_pImpl
->InsertBkmk(**ppBkmk
);
408 // search all Bookmarks in the range and return it in the Array
409 bool Writer::GetBookmarks(const SwContentNode
& rNd
, sal_Int32 nStt
,
410 sal_Int32 nEnd
, std::vector
< const ::sw::mark::IMark
* >& rArr
)
412 OSL_ENSURE( rArr
.empty(), "there are still entries available" );
414 SwNodeOffset nNd
= rNd
.GetIndex();
415 std::pair
<SwBookmarkNodeTable::const_iterator
, SwBookmarkNodeTable::const_iterator
> aIterPair
416 = m_pImpl
->aBkmkNodePos
.equal_range( nNd
);
417 if( aIterPair
.first
!= aIterPair
.second
)
419 // there exist some bookmarks, search now all which is in the range
420 if( !nStt
&& nEnd
== rNd
.Len() )
422 for( SwBookmarkNodeTable::const_iterator it
= aIterPair
.first
; it
!= aIterPair
.second
; ++it
)
423 rArr
.push_back( it
->second
);
426 for( SwBookmarkNodeTable::const_iterator it
= aIterPair
.first
; it
!= aIterPair
.second
; ++it
)
428 const ::sw::mark::IMark
& rBkmk
= *(it
->second
);
430 if( rBkmk
.GetMarkPos().GetNode() == rNd
&&
431 (nContent
= rBkmk
.GetMarkPos().GetContentIndex() ) >= nStt
&&
434 rArr
.push_back( &rBkmk
);
436 else if( rBkmk
.IsExpanded() &&
437 (rNd
== rBkmk
.GetOtherMarkPos().GetNode()) &&
438 (nContent
= rBkmk
.GetOtherMarkPos().GetContentIndex()) >= nStt
&&
441 rArr
.push_back( &rBkmk
);
446 return !rArr
.empty();
450 ErrCode
StgWriter::WriteStream()
452 OSL_ENSURE( false, "Write in Storages on a stream?" );
453 return ERR_SWG_WRITE_ERROR
;
456 ErrCode
StgWriter::Write( SwPaM
& rPaM
, SotStorage
& rStg
, const OUString
* pFName
)
460 m_pDoc
= &rPaM
.GetDoc();
461 m_pOrigFileName
= pFName
;
463 // Copy PaM, so that it can be modified
464 m_pCurrentPam
= m_pDoc
->CreateUnoCursor(*rPaM
.End(), false);
465 m_pCurrentPam
->SetMark();
466 *m_pCurrentPam
->GetPoint() = *rPaM
.Start();
467 // for comparison secure to the current Pam
470 ErrCode nRet
= WriteStorage();
478 ErrCode
StgWriter::Write( SwPaM
& rPaM
, const uno::Reference
< embed::XStorage
>& rStg
, const OUString
* pFName
, SfxMedium
* pMedium
)
483 m_pDoc
= &rPaM
.GetDoc();
484 m_pOrigFileName
= pFName
;
486 // Copy PaM, so that it can be modified
487 m_pCurrentPam
= m_pDoc
->CreateUnoCursor(*rPaM
.End(), false);
488 m_pCurrentPam
->SetMark();
489 *m_pCurrentPam
->GetPoint() = *rPaM
.Start();
490 // for comparison secure to the current Pam
493 ErrCode nRet
= pMedium
? WriteMedium( *pMedium
) : WriteStorage();
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */