Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <hintids.hxx>
21 :
22 : #include <sot/storage.hxx>
23 : #include <sfx2/docfile.hxx>
24 : #include <svl/urihelper.hxx>
25 : #include <vcl/graphicfilter.hxx>
26 : #include <editeng/fontitem.hxx>
27 : #include <editeng/eeitem.hxx>
28 : #include <shellio.hxx>
29 : #include <doc.hxx>
30 : #include <docary.hxx>
31 : #include <IMark.hxx>
32 : #include <IDocumentSettingAccess.hxx>
33 : #include <numrule.hxx>
34 : #include <swerror.h>
35 :
36 : using namespace css;
37 :
38 : namespace
39 : {
40 10664 : SvStream& lcl_OutLongExt( SvStream& rStrm, sal_uLong nVal, bool bNeg )
41 : {
42 : sal_Char aBuf[28];
43 :
44 10664 : int i = SAL_N_ELEMENTS(aBuf);
45 10664 : aBuf[--i] = 0;
46 17764 : do
47 : {
48 17764 : aBuf[--i] = '0' + static_cast<sal_Char>(nVal % 10);
49 17764 : nVal /= 10;
50 : } while (nVal);
51 :
52 10664 : if (bNeg)
53 290 : aBuf[--i] = '-';
54 :
55 10664 : return rStrm.WriteCharPtr( &aBuf[i] );
56 : }
57 : }
58 :
59 : typedef std::multimap<sal_uLong, const ::sw::mark::IMark*> SwBookmarkNodeTable;
60 :
61 : struct Writer_Impl
62 : {
63 : SvStream * m_pStream;
64 :
65 : std::vector<const SvxFontItem*> aFontRemoveLst;
66 : SwBookmarkNodeTable aBkmkNodePos;
67 :
68 : Writer_Impl();
69 : ~Writer_Impl();
70 :
71 : void RemoveFontList( SwDoc& rDoc );
72 : void InsertBkmk( const ::sw::mark::IMark& rBkmk );
73 : };
74 :
75 31184 : Writer_Impl::Writer_Impl()
76 31184 : : m_pStream(0)
77 : {
78 31184 : }
79 :
80 31184 : Writer_Impl::~Writer_Impl()
81 : {
82 31184 : }
83 :
84 15524 : void Writer_Impl::RemoveFontList( SwDoc& rDoc )
85 : {
86 47028 : for( std::vector<const SvxFontItem*>::const_iterator it = aFontRemoveLst.begin();
87 31352 : it != aFontRemoveLst.end(); ++it )
88 : {
89 152 : rDoc.GetAttrPool().Remove( **it );
90 : }
91 15524 : }
92 :
93 14 : void Writer_Impl::InsertBkmk(const ::sw::mark::IMark& rBkmk)
94 : {
95 14 : sal_uLong nNd = rBkmk.GetMarkPos().nNode.GetIndex();
96 :
97 14 : aBkmkNodePos.insert( SwBookmarkNodeTable::value_type( nNd, &rBkmk ) );
98 :
99 14 : if(rBkmk.IsExpanded() && rBkmk.GetOtherMarkPos().nNode != nNd)
100 : {
101 0 : nNd = rBkmk.GetOtherMarkPos().nNode.GetIndex();
102 0 : aBkmkNodePos.insert( SwBookmarkNodeTable::value_type( nNd, &rBkmk ));
103 : }
104 14 : }
105 :
106 : /*
107 : * This module is the central collection point for all writer-filters
108 : * and is a DLL !
109 : *
110 : * So that the Writer can work with different writers, the output-functions
111 : * of the content carrying objects have to be mapped to the various
112 : * output-functions.
113 : *
114 : * For that, to inquire its output function, every object can be gripped
115 : * via the which-value in a table.
116 : * These functions are available in the corresponding Writer-DLL's.
117 : */
118 :
119 15660 : Writer::Writer()
120 15660 : : m_pImpl(new Writer_Impl)
121 31320 : , pOrigPam(0), pOrigFileName(0), pDoc(0), pCurPam(0)
122 : {
123 15660 : bWriteAll = bShowProgress = bUCS2_WithStartChar = true;
124 : bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
125 : bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
126 15660 : bOrganizerMode = false;
127 15660 : bExportPargraphNumbering = true;
128 15660 : }
129 :
130 15660 : Writer::~Writer()
131 : {
132 15660 : }
133 :
134 : /*
135 : * Document Interface Access
136 : */
137 34 : IDocumentSettingAccess* Writer::getIDocumentSettingAccess() { return &pDoc->getIDocumentSettingAccess(); }
138 0 : const IDocumentSettingAccess* Writer::getIDocumentSettingAccess() const { return &pDoc->getIDocumentSettingAccess(); }
139 44 : IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() { return &pDoc->getIDocumentStylePoolAccess(); }
140 0 : const IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() const { return &pDoc->getIDocumentStylePoolAccess(); }
141 :
142 15524 : void Writer::ResetWriter()
143 : {
144 15524 : m_pImpl->RemoveFontList( *pDoc );
145 15524 : m_pImpl.reset(new Writer_Impl);
146 :
147 15524 : if( pCurPam )
148 : {
149 31048 : while( pCurPam->GetNext() != pCurPam )
150 0 : delete pCurPam->GetNext();
151 15524 : delete pCurPam;
152 : }
153 15524 : pCurPam = 0;
154 15524 : pOrigFileName = 0;
155 15524 : pDoc = 0;
156 :
157 15524 : bShowProgress = bUCS2_WithStartChar = true;
158 : bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
159 : bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
160 15524 : bOrganizerMode = false;
161 15524 : }
162 :
163 15950 : bool Writer::CopyNextPam( SwPaM ** ppPam )
164 : {
165 15950 : if( (*ppPam)->GetNext() == pOrigPam )
166 : {
167 15950 : *ppPam = pOrigPam; // set back to the beginning pam
168 15950 : return false; // end of the ring
169 : }
170 :
171 : // otherwise copy the next value from the next Pam
172 0 : *ppPam = ((SwPaM*)(*ppPam)->GetNext() );
173 :
174 0 : *pCurPam->GetPoint() = *(*ppPam)->Start();
175 0 : *pCurPam->GetMark() = *(*ppPam)->End();
176 :
177 0 : return true;
178 : }
179 :
180 : // search the next Bookmark-Position from the Bookmark-Table
181 :
182 1070 : sal_Int32 Writer::FindPos_Bkmk(const SwPosition& rPos) const
183 : {
184 1070 : const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
185 : const IDocumentMarkAccess::const_iterator_t ppBkmk = ::std::lower_bound(
186 1070 : pMarkAccess->getAllMarksBegin(),
187 1070 : pMarkAccess->getAllMarksEnd(),
188 : rPos,
189 2140 : sw::mark::CompareIMarkStartsBefore()); // find the first Mark that does not start before
190 1070 : if(ppBkmk != pMarkAccess->getAllMarksEnd())
191 2 : return ppBkmk - pMarkAccess->getAllMarksBegin();
192 1068 : return -1;
193 : }
194 :
195 : SwPaM *
196 1814 : Writer::NewSwPaM(SwDoc & rDoc, sal_uLong const nStartIdx, sal_uLong const nEndIdx)
197 : {
198 1814 : SwNodes *const pNds = &rDoc.GetNodes();
199 :
200 1814 : SwNodeIndex aStt( *pNds, nStartIdx );
201 1814 : SwCntntNode* pCNode = aStt.GetNode().GetCntntNode();
202 1814 : if( !pCNode && 0 == pNds->GoNext( &aStt ) )
203 : {
204 : OSL_FAIL( "No more ContentNode at StartPos" );
205 : }
206 :
207 1814 : SwPaM* pNew = new SwPaM( aStt );
208 1814 : pNew->SetMark();
209 1814 : aStt = nEndIdx;
210 1814 : pCNode = aStt.GetNode().GetCntntNode();
211 1814 : if (!pCNode)
212 1814 : pCNode = pNds->GoPrevious(&aStt);
213 : assert(pCNode && "No more ContentNode at StartPos");
214 1814 : pCNode->MakeEndIndex( &pNew->GetPoint()->nContent );
215 1814 : pNew->GetPoint()->nNode = aStt;
216 1814 : return pNew;
217 : }
218 :
219 : // Stream-specific
220 141018 : SvStream& Writer::Strm()
221 : {
222 : assert(m_pImpl->m_pStream && "Oh-oh. Writer with no Stream!");
223 141018 : return *m_pImpl->m_pStream;
224 : }
225 :
226 298 : void Writer::SetStream(SvStream *const pStream)
227 : {
228 298 : m_pImpl->m_pStream = pStream;
229 298 : }
230 :
231 1850 : SvStream& Writer::OutLong( SvStream& rStrm, long nVal )
232 : {
233 1850 : const bool bNeg = nVal < 0;
234 1850 : if (bNeg)
235 290 : nVal = -nVal;
236 :
237 1850 : return lcl_OutLongExt(rStrm, static_cast<sal_uLong>(nVal), bNeg);
238 : }
239 :
240 8814 : SvStream& Writer::OutULong( SvStream& rStrm, sal_uLong nVal )
241 : {
242 8814 : return lcl_OutLongExt(rStrm, nVal, false);
243 : }
244 :
245 15464 : sal_uLong Writer::Write( SwPaM& rPaM, SvStream& rStrm, const OUString* pFName )
246 : {
247 15464 : if ( IsStgWriter() )
248 : {
249 34 : sal_uLong nResult = ERRCODE_ABORT;
250 : try
251 : {
252 34 : SotStorageRef aRef = new SotStorage( rStrm );
253 34 : nResult = Write( rPaM, *aRef, pFName );
254 34 : if ( nResult == ERRCODE_NONE )
255 34 : aRef->Commit();
256 : }
257 0 : catch (const css::ucb::ContentCreationException &e)
258 : {
259 : SAL_WARN("sw", "Writer::Write caught " << e.Message);
260 : }
261 34 : return nResult;
262 : }
263 :
264 15430 : pDoc = rPaM.GetDoc();
265 15430 : pOrigFileName = pFName;
266 15430 : m_pImpl->m_pStream = &rStrm;
267 :
268 : // Copy PaM, so that it can be modified
269 15430 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
270 : // for comparison secure to the current Pam
271 15430 : pOrigPam = &rPaM;
272 :
273 15430 : sal_uLong nRet = WriteStream();
274 :
275 15430 : ResetWriter();
276 :
277 15430 : return nRet;
278 : }
279 :
280 36 : void Writer::SetupFilterOptions(SfxMedium& /*rMedium*/)
281 36 : {}
282 :
283 60 : sal_uLong Writer::Write( SwPaM& rPam, SfxMedium& rMedium, const OUString* pFileName )
284 : {
285 60 : SetupFilterOptions(rMedium);
286 : // This method must be overloaded in SwXMLWriter a storage from medium will be used there.
287 : // The microsoft format can write to storage but the storage will be based on the stream.
288 60 : return Write( rPam, *rMedium.GetOutStream(), pFileName );
289 : }
290 :
291 0 : sal_uLong Writer::Write( SwPaM& /*rPam*/, SvStorage&, const OUString* )
292 : {
293 : OSL_ENSURE( false, "Write in Storages on a stream?" );
294 0 : return ERR_SWG_WRITE_ERROR;
295 : }
296 :
297 0 : sal_uLong Writer::Write( SwPaM&, const uno::Reference < embed::XStorage >&, const OUString*, SfxMedium* )
298 : {
299 : OSL_ENSURE( false, "Write in Storages on a stream?" );
300 0 : return ERR_SWG_WRITE_ERROR;
301 : }
302 :
303 60 : void Writer::PutNumFmtFontsInAttrPool()
304 : {
305 : // then there are a few fonts in the NumRules
306 : // These put into the Pool. After this does they have a RefCount > 1
307 : // it can be removed - it is already in the Pool
308 60 : SfxItemPool& rPool = pDoc->GetAttrPool();
309 60 : const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl();
310 : const SwNumRule* pRule;
311 : const SwNumFmt* pFmt;
312 : const vcl::Font* pFont;
313 60 : const vcl::Font* pDefFont = &numfunc::GetDefBulletFont();
314 60 : bool bCheck = false;
315 :
316 264 : for( sal_uInt16 nGet = rListTbl.size(); nGet; )
317 144 : if( pDoc->IsUsed( *(pRule = rListTbl[ --nGet ] )))
318 22 : for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
319 40 : if( SVX_NUM_CHAR_SPECIAL == (pFmt = &pRule->Get( nLvl ))->GetNumberingType() ||
320 20 : SVX_NUM_BITMAP == pFmt->GetNumberingType() )
321 : {
322 0 : if( 0 == ( pFont = pFmt->GetBulletFont() ) )
323 0 : pFont = pDefFont;
324 :
325 0 : if( bCheck )
326 : {
327 0 : if( *pFont == *pDefFont )
328 0 : continue;
329 : }
330 0 : else if( *pFont == *pDefFont )
331 0 : bCheck = true;
332 :
333 : _AddFontItem( rPool, SvxFontItem( pFont->GetFamily(),
334 0 : pFont->GetName(), pFont->GetStyleName(),
335 0 : pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT ));
336 : }
337 60 : }
338 :
339 60 : void Writer::PutEditEngFontsInAttrPool( bool bIncl_CJK_CTL )
340 : {
341 60 : SfxItemPool& rPool = pDoc->GetAttrPool();
342 60 : if( rPool.GetSecondaryPool() )
343 : {
344 60 : _AddFontItems( rPool, EE_CHAR_FONTINFO );
345 60 : if( bIncl_CJK_CTL )
346 : {
347 60 : _AddFontItems( rPool, EE_CHAR_FONTINFO_CJK );
348 60 : _AddFontItems( rPool, EE_CHAR_FONTINFO_CTL );
349 : }
350 : }
351 60 : }
352 :
353 180 : void Writer::_AddFontItems( SfxItemPool& rPool, sal_uInt16 nW )
354 : {
355 180 : const SvxFontItem* pFont = (const SvxFontItem*)&rPool.GetDefaultItem( nW );
356 180 : _AddFontItem( rPool, *pFont );
357 :
358 180 : if( 0 != ( pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem( nW )) )
359 180 : _AddFontItem( rPool, *pFont );
360 :
361 180 : sal_uInt32 nMaxItem = rPool.GetItemCount2( nW );
362 192 : for( sal_uInt32 nGet = 0; nGet < nMaxItem; ++nGet )
363 12 : if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem2( nW, nGet )) )
364 12 : _AddFontItem( rPool, *pFont );
365 180 : }
366 :
367 372 : void Writer::_AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
368 : {
369 : const SvxFontItem* pItem;
370 372 : if( RES_CHRATR_FONT != rFont.Which() )
371 : {
372 372 : SvxFontItem aFont( rFont );
373 372 : aFont.SetWhich( RES_CHRATR_FONT );
374 372 : pItem = (SvxFontItem*)&rPool.Put( aFont );
375 : }
376 : else
377 0 : pItem = (SvxFontItem*)&rPool.Put( rFont );
378 :
379 372 : if( 1 < pItem->GetRefCount() )
380 220 : rPool.Remove( *pItem );
381 : else
382 : {
383 152 : m_pImpl->aFontRemoveLst.push_back( pItem );
384 : }
385 372 : }
386 :
387 : // build a bookmark table, which is sort by the node position. The
388 : // OtherPos of the bookmarks also inserted.
389 34 : void Writer::CreateBookmarkTbl()
390 : {
391 34 : const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
392 144 : for(IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getBookmarksBegin();
393 96 : ppBkmk != pMarkAccess->getBookmarksEnd();
394 : ++ppBkmk)
395 : {
396 14 : m_pImpl->InsertBkmk(**ppBkmk);
397 : }
398 34 : }
399 :
400 : // search alle Bookmarks in the range and return it in the Array
401 1474 : sal_uInt16 Writer::GetBookmarks(const SwCntntNode& rNd, sal_Int32 nStt,
402 : sal_Int32 nEnd, std::vector< const ::sw::mark::IMark* >& rArr)
403 : {
404 : OSL_ENSURE( rArr.empty(), "there are still entries available" );
405 :
406 1474 : sal_uLong nNd = rNd.GetIndex();
407 : std::pair<SwBookmarkNodeTable::const_iterator, SwBookmarkNodeTable::const_iterator> aIterPair
408 1474 : = m_pImpl->aBkmkNodePos.equal_range( nNd );
409 1474 : if( aIterPair.first != aIterPair.second )
410 : {
411 : // there exist some bookmarks, search now all which is in the range
412 30 : if( !nStt && nEnd == rNd.Len() )
413 : // all
414 12 : for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
415 6 : rArr.push_back( it->second );
416 : else
417 : {
418 66 : for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
419 : {
420 42 : const ::sw::mark::IMark& rBkmk = *(it->second);
421 : sal_Int32 nCntnt;
422 126 : if( rBkmk.GetMarkPos().nNode == nNd &&
423 58 : (nCntnt = rBkmk.GetMarkPos().nContent.GetIndex() ) >= nStt &&
424 : nCntnt < nEnd )
425 : {
426 8 : rArr.push_back( &rBkmk );
427 : }
428 98 : else if( rBkmk.IsExpanded() && nNd ==
429 60 : rBkmk.GetOtherMarkPos().nNode.GetIndex() && (nCntnt =
430 82 : rBkmk.GetOtherMarkPos().nContent.GetIndex() ) >= nStt &&
431 : nCntnt < nEnd )
432 : {
433 10 : rArr.push_back( &rBkmk );
434 : }
435 : }
436 : }
437 : }
438 1474 : return rArr.size();
439 : }
440 :
441 : // Storage-specific
442 0 : sal_uLong StgWriter::WriteStream()
443 : {
444 : OSL_ENSURE( false, "Write in Storages on a stream?" );
445 0 : return ERR_SWG_WRITE_ERROR;
446 : }
447 :
448 34 : sal_uLong StgWriter::Write( SwPaM& rPaM, SvStorage& rStg, const OUString* pFName )
449 : {
450 34 : SetStream(0);
451 34 : pStg = &rStg;
452 34 : pDoc = rPaM.GetDoc();
453 34 : pOrigFileName = pFName;
454 :
455 : // Copy PaM, so that it can be modified
456 34 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
457 : // for comparison secure to the current Pam
458 34 : pOrigPam = &rPaM;
459 :
460 34 : sal_uLong nRet = WriteStorage();
461 :
462 34 : pStg = NULL;
463 34 : ResetWriter();
464 :
465 34 : return nRet;
466 : }
467 :
468 60 : sal_uLong StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const OUString* pFName, SfxMedium* pMedium )
469 : {
470 60 : SetStream(0);
471 60 : pStg = 0;
472 60 : xStg = rStg;
473 60 : pDoc = rPaM.GetDoc();
474 60 : pOrigFileName = pFName;
475 :
476 : // Copy PaM, so that it can be modified
477 60 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
478 : // for comparison secure to the current Pam
479 60 : pOrigPam = &rPaM;
480 :
481 60 : sal_uLong nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
482 :
483 60 : pStg = NULL;
484 60 : ResetWriter();
485 :
486 60 : return nRet;
487 270 : }
488 :
489 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|