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 <svtools/filter.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 <numrule.hxx>
33 : #include <swerror.h>
34 : #include <boost/bind.hpp>
35 : #include <boost/scoped_ptr.hpp>
36 :
37 : using namespace ::com::sun::star;
38 :
39 :
40 : // Stringbuffer fuer die umgewandelten Zahlen
41 : static sal_Char aNToABuf[] = "0000000000000000000000000";
42 : #define NTOABUFLEN (sizeof(aNToABuf))
43 :
44 : typedef std::multimap<sal_uLong, const ::sw::mark::IMark*> SwBookmarkNodeTable;
45 :
46 : struct Writer_Impl
47 : {
48 : SvStream * m_pStream;
49 :
50 : boost::scoped_ptr< std::map<String, String> > pFileNameMap;
51 : std::vector<const SvxFontItem*> aFontRemoveLst;
52 : SwBookmarkNodeTable aBkmkNodePos;
53 :
54 : Writer_Impl();
55 : ~Writer_Impl();
56 :
57 : void RemoveFontList( SwDoc& rDoc );
58 : void InsertBkmk( const ::sw::mark::IMark& rBkmk );
59 : };
60 :
61 75 : Writer_Impl::Writer_Impl()
62 75 : : m_pStream(0)
63 : {
64 75 : }
65 :
66 75 : Writer_Impl::~Writer_Impl()
67 : {
68 75 : }
69 :
70 23 : void Writer_Impl::RemoveFontList( SwDoc& rDoc )
71 : {
72 90 : for( std::vector<const SvxFontItem*>::const_iterator it = aFontRemoveLst.begin();
73 60 : it != aFontRemoveLst.end(); ++it )
74 : {
75 7 : rDoc.GetAttrPool().Remove( **it );
76 : }
77 23 : }
78 :
79 0 : void Writer_Impl::InsertBkmk(const ::sw::mark::IMark& rBkmk)
80 : {
81 :
82 0 : sal_uLong nNd = rBkmk.GetMarkPos().nNode.GetIndex();
83 :
84 0 : aBkmkNodePos.insert( SwBookmarkNodeTable::value_type( nNd, &rBkmk ) );
85 :
86 0 : if(rBkmk.IsExpanded() && rBkmk.GetOtherMarkPos().nNode != nNd)
87 : {
88 0 : nNd = rBkmk.GetOtherMarkPos().nNode.GetIndex();
89 0 : aBkmkNodePos.insert( SwBookmarkNodeTable::value_type( nNd, &rBkmk ));
90 : }
91 0 : }
92 :
93 : /*
94 : * Dieses Modul ist die Zentrale-Sammelstelle fuer alle Write-Filter
95 : * und ist eine DLL !
96 : *
97 : * Damit der Writer mit den unterschiedlichen Writern arbeiten kann,
98 : * muessen fuer diese die Ausgabe-Funktionen der Inhalts tragenden
99 : * Objecte auf die verschiedenen Ausgabe-Funktionen gemappt werden.
100 : *
101 : * Dazu kann fuer jedes Object ueber den Which-Wert in einen Tabelle ge-
102 : * griffen werden, um seine Ausgabe-Funktion zu erfragen.
103 : * Diese Funktionen stehen in den entsprechenden Writer-DLL's.
104 : */
105 :
106 52 : Writer::Writer()
107 52 : : m_pImpl(new Writer_Impl)
108 104 : , pOrigPam(0), pOrigFileName(0), pDoc(0), pCurPam(0)
109 : {
110 52 : bWriteAll = bShowProgress = bUCS2_WithStartChar = true;
111 : bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
112 : bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
113 52 : bOrganizerMode = false;
114 52 : bExportPargraphNumbering = sal_True;
115 52 : }
116 :
117 52 : Writer::~Writer()
118 : {
119 52 : }
120 :
121 : /*
122 : * Document Interface Access
123 : */
124 0 : IDocumentSettingAccess* Writer::getIDocumentSettingAccess() { return pDoc; }
125 0 : const IDocumentSettingAccess* Writer::getIDocumentSettingAccess() const { return pDoc; }
126 0 : IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() { return pDoc; }
127 0 : const IDocumentStylePoolAccess* Writer::getIDocumentStylePoolAccess() const { return pDoc; }
128 :
129 23 : void Writer::ResetWriter()
130 : {
131 23 : m_pImpl->RemoveFontList( *pDoc );
132 23 : m_pImpl.reset(new Writer_Impl);
133 :
134 23 : if( pCurPam )
135 : {
136 46 : while( pCurPam->GetNext() != pCurPam )
137 0 : delete pCurPam->GetNext();
138 23 : delete pCurPam;
139 : }
140 23 : pCurPam = 0;
141 23 : pOrigFileName = 0;
142 23 : pDoc = 0;
143 :
144 23 : bShowProgress = bUCS2_WithStartChar = sal_True;
145 : bASCII_NoLastLineEnd = bASCII_ParaAsBlanc = bASCII_ParaAsCR =
146 : bWriteClipboardDoc = bWriteOnlyFirstTable = bBlock =
147 23 : bOrganizerMode = sal_False;
148 23 : }
149 :
150 21 : sal_Bool Writer::CopyNextPam( SwPaM ** ppPam )
151 : {
152 21 : if( (*ppPam)->GetNext() == pOrigPam )
153 : {
154 21 : *ppPam = pOrigPam; // wieder auf den Anfangs-Pam setzen
155 21 : return sal_False; // Ende vom Ring
156 : }
157 :
158 : // ansonsten kopiere den die Werte aus dem naechsten Pam
159 0 : *ppPam = ((SwPaM*)(*ppPam)->GetNext() );
160 :
161 0 : *pCurPam->GetPoint() = *(*ppPam)->Start();
162 0 : *pCurPam->GetMark() = *(*ppPam)->End();
163 :
164 0 : return sal_True;
165 : }
166 :
167 : // suche die naechste Bookmark-Position aus der Bookmark-Tabelle
168 :
169 0 : sal_Int32 Writer::FindPos_Bkmk(const SwPosition& rPos) const
170 : {
171 0 : const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
172 : const IDocumentMarkAccess::const_iterator_t ppBkmk = ::std::lower_bound(
173 0 : pMarkAccess->getMarksBegin(),
174 0 : pMarkAccess->getMarksEnd(),
175 : rPos,
176 0 : ::boost::bind(&::sw::mark::IMark::StartsBefore, _1, _2)); // find the first Mark that does not start before
177 0 : if(ppBkmk != pMarkAccess->getMarksEnd())
178 0 : return ppBkmk - pMarkAccess->getMarksBegin();
179 0 : return -1;
180 : }
181 :
182 :
183 : SwPaM *
184 5 : Writer::NewSwPaM(SwDoc & rDoc, sal_uLong const nStartIdx, sal_uLong const nEndIdx)
185 : {
186 5 : SwNodes *const pNds = &rDoc.GetNodes();
187 :
188 5 : SwNodeIndex aStt( *pNds, nStartIdx );
189 5 : SwCntntNode* pCNode = aStt.GetNode().GetCntntNode();
190 5 : if( !pCNode && 0 == ( pCNode = pNds->GoNext( &aStt )) )
191 : {
192 : OSL_FAIL( "An StartPos kein ContentNode mehr" );
193 : }
194 :
195 5 : SwPaM* pNew = new SwPaM( aStt );
196 5 : pNew->SetMark();
197 5 : aStt = nEndIdx;
198 5 : if( 0 == (pCNode = aStt.GetNode().GetCntntNode()) &&
199 : 0 == (pCNode = pNds->GoPrevious( &aStt )) )
200 : {
201 : OSL_FAIL( "An StartPos kein ContentNode mehr" );
202 : }
203 5 : pCNode->MakeEndIndex( &pNew->GetPoint()->nContent );
204 5 : pNew->GetPoint()->nNode = aStt;
205 5 : return pNew;
206 : }
207 :
208 : /////////////////////////////////////////////////////////////////////////////
209 :
210 : // Stream-spezifisches
211 5601 : SvStream& Writer::Strm()
212 : {
213 : OSL_ENSURE( m_pImpl->m_pStream, "Oh-oh. Writer with no Stream!" );
214 5601 : return *m_pImpl->m_pStream;
215 : }
216 :
217 31 : void Writer::SetStream(SvStream *const pStream)
218 31 : { m_pImpl->m_pStream = pStream; }
219 :
220 209 : SvStream& Writer::OutLong( SvStream& rStrm, long nVal )
221 : {
222 : // Pointer an das Bufferende setzen
223 209 : sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
224 :
225 209 : int bNeg = nVal < 0;
226 209 : if( bNeg )
227 0 : nVal = -nVal;
228 :
229 569 : do {
230 569 : *(--pStr) = (sal_Char)(nVal % 10 ) + 48;
231 569 : nVal /= 10;
232 : } while( nVal );
233 :
234 : // Ist Zahl negativ, dann noch -
235 209 : if( bNeg )
236 0 : *(--pStr) = '-';
237 :
238 209 : return rStrm << pStr;
239 : }
240 :
241 1655 : SvStream& Writer::OutULong( SvStream& rStrm, sal_uLong nVal )
242 : {
243 : // Pointer an das Bufferende setzen
244 1655 : sal_Char* pStr = aNToABuf + (NTOABUFLEN-1);
245 :
246 2328 : do {
247 2328 : *(--pStr) = (sal_Char)(nVal % 10 ) + 48;
248 2328 : nVal /= 10;
249 : } while ( nVal );
250 1655 : return rStrm << pStr;
251 : }
252 :
253 :
254 21 : sal_uLong Writer::Write( SwPaM& rPaM, SvStream& rStrm, const String* pFName )
255 : {
256 21 : if ( IsStgWriter() )
257 : {
258 0 : SotStorageRef aRef = new SotStorage( rStrm );
259 0 : sal_uLong nResult = Write( rPaM, *aRef, pFName );
260 0 : if ( nResult == ERRCODE_NONE )
261 0 : aRef->Commit();
262 0 : return nResult;
263 : }
264 :
265 21 : pDoc = rPaM.GetDoc();
266 21 : pOrigFileName = pFName;
267 21 : m_pImpl->m_pStream = &rStrm;
268 :
269 : // PaM kopieren, damit er veraendert werden kann
270 21 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
271 : // zum Vergleich auf den akt. Pam sichern
272 21 : pOrigPam = &rPaM;
273 :
274 21 : sal_uLong nRet = WriteStream();
275 :
276 21 : ResetWriter();
277 :
278 21 : return nRet;
279 : }
280 :
281 1 : sal_uLong Writer::Write( SwPaM& rPam, SfxMedium& rMed, const String* pFileName )
282 : {
283 : // This method must be overloaded in SwXMLWriter a storage from medium will be used there.
284 : // The microsoft format can write to storage but the storage will be based on the stream.
285 1 : return Write( rPam, *rMed.GetOutStream(), pFileName );
286 : }
287 :
288 0 : sal_uLong Writer::Write( SwPaM& /*rPam*/, SvStorage&, const String* )
289 : {
290 : OSL_ENSURE( !this, "Schreiben in Storages auf einem Stream?" );
291 0 : return ERR_SWG_WRITE_ERROR;
292 : }
293 :
294 0 : sal_uLong Writer::Write( SwPaM&, const uno::Reference < embed::XStorage >&, const String*, SfxMedium* )
295 : {
296 : OSL_ENSURE( !this, "Schreiben in Storages auf einem Stream?" );
297 0 : return ERR_SWG_WRITE_ERROR;
298 : }
299 :
300 0 : sal_Bool Writer::CopyLocalFileToINet( String& rFileNm )
301 : {
302 0 : if( !pOrigFileName ) // can be happen, by example if we
303 0 : return sal_False; // write into the clipboard
304 :
305 0 : sal_Bool bRet = sal_False;
306 0 : INetURLObject aFileUrl( rFileNm ), aTargetUrl( *pOrigFileName );
307 :
308 : // this is our old without the Mail-Export
309 0 : if( ! ( INET_PROT_FILE == aFileUrl.GetProtocol() &&
310 0 : INET_PROT_FILE != aTargetUrl.GetProtocol() &&
311 0 : INET_PROT_FTP <= aTargetUrl.GetProtocol() &&
312 0 : INET_PROT_NEWS >= aTargetUrl.GetProtocol() ) )
313 0 : return bRet;
314 :
315 0 : if (m_pImpl->pFileNameMap)
316 : {
317 : // wurde die Datei schon verschoben
318 0 : std::map<String, String>::iterator it = m_pImpl->pFileNameMap->find( rFileNm );
319 0 : if ( it != m_pImpl->pFileNameMap->end() )
320 : {
321 0 : rFileNm = it->second;
322 0 : return sal_True;
323 : }
324 : }
325 : else
326 : {
327 0 : m_pImpl->pFileNameMap.reset( new std::map<String, String>() );
328 : }
329 :
330 0 : String aSrc = rFileNm;
331 0 : String aDest = aTargetUrl.GetPartBeforeLastName();
332 0 : aDest += String(aFileUrl.GetName());
333 :
334 0 : SfxMedium aSrcFile( aSrc, STREAM_READ );
335 0 : SfxMedium aDstFile( aDest, STREAM_WRITE | STREAM_SHARE_DENYNONE );
336 :
337 0 : *aDstFile.GetOutStream() << *aSrcFile.GetInStream();
338 :
339 0 : aSrcFile.Close();
340 0 : aDstFile.Commit();
341 :
342 0 : bRet = 0 == aDstFile.GetError();
343 :
344 0 : if( bRet )
345 : {
346 0 : m_pImpl->pFileNameMap->insert( std::make_pair( aSrc, aDest ) );
347 0 : rFileNm = aDest;
348 : }
349 :
350 0 : return bRet;
351 : }
352 :
353 2 : void Writer::PutNumFmtFontsInAttrPool()
354 : {
355 : // dann gibt es noch in den NumRules ein paar Fonts
356 : // Diese in den Pool putten. Haben sie danach einen RefCount > 1
357 : // kann es wieder entfernt werden - ist schon im Pool
358 2 : SfxItemPool& rPool = pDoc->GetAttrPool();
359 2 : const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl();
360 : const SwNumRule* pRule;
361 : const SwNumFmt* pFmt;
362 : const Font* pFont;
363 2 : const Font* pDefFont = &numfunc::GetDefBulletFont();
364 2 : sal_Bool bCheck = sal_False;
365 :
366 6 : for( sal_uInt16 nGet = rListTbl.size(); nGet; )
367 2 : if( pDoc->IsUsed( *(pRule = rListTbl[ --nGet ] )))
368 0 : for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
369 0 : if( SVX_NUM_CHAR_SPECIAL == (pFmt = &pRule->Get( nLvl ))->GetNumberingType() ||
370 0 : SVX_NUM_BITMAP == pFmt->GetNumberingType() )
371 : {
372 0 : if( 0 == ( pFont = pFmt->GetBulletFont() ) )
373 0 : pFont = pDefFont;
374 :
375 0 : if( bCheck )
376 : {
377 0 : if( *pFont == *pDefFont )
378 0 : continue;
379 : }
380 0 : else if( *pFont == *pDefFont )
381 0 : bCheck = sal_True;
382 :
383 : _AddFontItem( rPool, SvxFontItem( pFont->GetFamily(),
384 0 : pFont->GetName(), pFont->GetStyleName(),
385 0 : pFont->GetPitch(), pFont->GetCharSet(), RES_CHRATR_FONT ));
386 : }
387 2 : }
388 :
389 2 : void Writer::PutEditEngFontsInAttrPool( sal_Bool bIncl_CJK_CTL )
390 : {
391 2 : SfxItemPool& rPool = pDoc->GetAttrPool();
392 2 : if( rPool.GetSecondaryPool() )
393 : {
394 2 : _AddFontItems( rPool, EE_CHAR_FONTINFO );
395 2 : if( bIncl_CJK_CTL )
396 : {
397 2 : _AddFontItems( rPool, EE_CHAR_FONTINFO_CJK );
398 2 : _AddFontItems( rPool, EE_CHAR_FONTINFO_CTL );
399 : }
400 : }
401 2 : }
402 :
403 6 : void Writer::_AddFontItems( SfxItemPool& rPool, sal_uInt16 nW )
404 : {
405 6 : const SvxFontItem* pFont = (const SvxFontItem*)&rPool.GetDefaultItem( nW );
406 6 : _AddFontItem( rPool, *pFont );
407 :
408 6 : if( 0 != ( pFont = (const SvxFontItem*)rPool.GetPoolDefaultItem( nW )) )
409 6 : _AddFontItem( rPool, *pFont );
410 :
411 6 : sal_uInt32 nMaxItem = rPool.GetItemCount2( nW );
412 9 : for( sal_uInt32 nGet = 0; nGet < nMaxItem; ++nGet )
413 3 : if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem2( nW, nGet )) )
414 3 : _AddFontItem( rPool, *pFont );
415 6 : }
416 :
417 15 : void Writer::_AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
418 : {
419 : const SvxFontItem* pItem;
420 15 : if( RES_CHRATR_FONT != rFont.Which() )
421 : {
422 15 : SvxFontItem aFont( rFont );
423 15 : aFont.SetWhich( RES_CHRATR_FONT );
424 15 : pItem = (SvxFontItem*)&rPool.Put( aFont );
425 : }
426 : else
427 0 : pItem = (SvxFontItem*)&rPool.Put( rFont );
428 :
429 15 : if( 1 < pItem->GetRefCount() )
430 8 : rPool.Remove( *pItem );
431 : else
432 : {
433 7 : m_pImpl->aFontRemoveLst.push_back( pItem );
434 : }
435 15 : }
436 :
437 : // build a bookmark table, which is sort by the node position. The
438 : // OtherPos of the bookmarks also inserted.
439 0 : void Writer::CreateBookmarkTbl()
440 : {
441 0 : const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
442 0 : for(IDocumentMarkAccess::const_iterator_t ppBkmk = pMarkAccess->getBookmarksBegin();
443 0 : ppBkmk != pMarkAccess->getBookmarksEnd();
444 : ++ppBkmk)
445 : {
446 0 : m_pImpl->InsertBkmk(**ppBkmk);
447 : }
448 0 : }
449 :
450 :
451 : // search alle Bookmarks in the range and return it in the Array
452 0 : sal_uInt16 Writer::GetBookmarks(const SwCntntNode& rNd, xub_StrLen nStt,
453 : xub_StrLen nEnd, std::vector< const ::sw::mark::IMark* >& rArr)
454 : {
455 : OSL_ENSURE( rArr.empty(), "es sind noch Eintraege vorhanden" );
456 :
457 0 : sal_uLong nNd = rNd.GetIndex();
458 : std::pair<SwBookmarkNodeTable::const_iterator, SwBookmarkNodeTable::const_iterator> aIterPair
459 0 : = m_pImpl->aBkmkNodePos.equal_range( nNd );
460 0 : if( aIterPair.first != aIterPair.second )
461 : {
462 : // there exist some bookmarks, search now all which is in the range
463 0 : if( !nStt && nEnd == rNd.Len() )
464 : // all
465 0 : for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
466 0 : rArr.push_back( it->second );
467 : else
468 : {
469 0 : for( SwBookmarkNodeTable::const_iterator it = aIterPair.first; it != aIterPair.second; ++it )
470 : {
471 0 : const ::sw::mark::IMark& rBkmk = *(it->second);
472 : xub_StrLen nCntnt;
473 0 : if( rBkmk.GetMarkPos().nNode == nNd &&
474 0 : (nCntnt = rBkmk.GetMarkPos().nContent.GetIndex() ) >= nStt &&
475 : nCntnt < nEnd )
476 : {
477 0 : rArr.push_back( &rBkmk );
478 : }
479 0 : else if( rBkmk.IsExpanded() && nNd ==
480 0 : rBkmk.GetOtherMarkPos().nNode.GetIndex() && (nCntnt =
481 0 : rBkmk.GetOtherMarkPos().nContent.GetIndex() ) >= nStt &&
482 : nCntnt < nEnd )
483 : {
484 0 : rArr.push_back( &rBkmk );
485 : }
486 : }
487 : }
488 : }
489 0 : return rArr.size();
490 : }
491 :
492 : ////////////////////////////////////////////////////////////////////////////
493 :
494 : // Storage-spezifisches
495 :
496 0 : sal_uLong StgWriter::WriteStream()
497 : {
498 : OSL_ENSURE( !this, "Schreiben in Streams auf einem Storage?" );
499 0 : return ERR_SWG_WRITE_ERROR;
500 : }
501 :
502 0 : sal_uLong StgWriter::Write( SwPaM& rPaM, SvStorage& rStg, const String* pFName )
503 : {
504 0 : SetStream(0);
505 0 : pStg = &rStg;
506 0 : pDoc = rPaM.GetDoc();
507 0 : pOrigFileName = pFName;
508 :
509 : // PaM kopieren, damit er veraendert werden kann
510 0 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
511 : // zum Vergleich auf den akt. Pam sichern
512 0 : pOrigPam = &rPaM;
513 :
514 0 : sal_uLong nRet = WriteStorage();
515 :
516 0 : pStg = NULL;
517 0 : ResetWriter();
518 :
519 0 : return nRet;
520 : }
521 :
522 2 : sal_uLong StgWriter::Write( SwPaM& rPaM, const uno::Reference < embed::XStorage >& rStg, const String* pFName, SfxMedium* pMedium )
523 : {
524 2 : SetStream(0);
525 2 : pStg = 0;
526 2 : xStg = rStg;
527 2 : pDoc = rPaM.GetDoc();
528 2 : pOrigFileName = pFName;
529 :
530 : // PaM kopieren, damit er veraendert werden kann
531 2 : pCurPam = new SwPaM( *rPaM.End(), *rPaM.Start() );
532 : // zum Vergleich auf den akt. Pam sichern
533 2 : pOrigPam = &rPaM;
534 :
535 2 : sal_uLong nRet = pMedium ? WriteMedium( *pMedium ) : WriteStorage();
536 :
537 2 : pStg = NULL;
538 2 : ResetWriter();
539 :
540 2 : return nRet;
541 30 : }
542 :
543 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|