xref: /trunk/main/sw/source/core/swg/SwXMLTextBlocks.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <com/sun/star/embed/ElementModes.hpp>
32 #include <com/sun/star/embed/XTransactedObject.hpp>
33 #include <tools/urlobj.hxx>
34 #include <sot/stg.hxx>
35 #include <sfx2/docfile.hxx>
36 #include <unotools/localfilehelper.hxx>
37 #include <unotools/ucbstreamhelper.hxx>
38 
39 #include <comphelper/storagehelper.hxx>
40 #include <doc.hxx>
41 #include <IDocumentUndoRedo.hxx>
42 #include <docsh.hxx>
43 #include <pam.hxx>
44 #include <swblocks.hxx>
45 #include <ndtxt.hxx>
46 #include <shellio.hxx>
47 #include <poolfmt.hxx>
48 #include <SwXMLTextBlocks.hxx>
49 #include <errhdl.hxx>
50 #include <SwXMLBlockImport.hxx>
51 #include <SwXMLBlockExport.hxx>
52 #include <swerror.h>
53 
54 #define STREAM_STGREAD  ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE )
55 #define STREAM_STGWRITE ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE )
56 
57 using namespace ::com::sun::star;
58 
59 
60 void SwXMLTextBlocks::InitBlockMode ( const uno::Reference < embed::XStorage >& rStorage )
61 {
62     xBlkRoot = rStorage;
63     xRoot = 0;
64 }
65 
66 void SwXMLTextBlocks::ResetBlockMode ( )
67 {
68     xBlkRoot = 0;
69     xRoot = 0;
70 }
71 
72 SwXMLTextBlocks::SwXMLTextBlocks( const String& rFile )
73 : SwImpBlocks( rFile ), bAutocorrBlock( sal_False ), nFlags ( 0 )
74 {
75     SwDocShell* pDocSh = new SwDocShell ( SFX_CREATE_MODE_INTERNAL );
76     if( !pDocSh->DoInitNew( 0 ) )
77         return;
78     bReadOnly = sal_True;
79     pDoc = pDocSh->GetDoc();
80     xDocShellRef = pDocSh;
81     pDoc->SetOle2Link( Link() );
82     pDoc->GetIDocumentUndoRedo().DoUndo(false);
83     pDoc->acquire();
84     uno::Reference< embed::XStorage > refStg;
85     if( !aDateModified.GetDate() || !aTimeModified.GetTime() )
86         Touch();        // falls neu angelegt -> neuen ZeitStempel besorgen
87     try
88     {
89         refStg  = comphelper::OStorageHelper::GetStorageFromURL( rFile, embed::ElementModes::READWRITE );
90         bReadOnly = sal_False;
91     }
92     catch( const uno::Exception& )
93     {
94         //couldn't open the file - maybe it's readonly
95     }
96     if( !refStg.is())
97     {
98         try
99         {
100             refStg = comphelper::OStorageHelper::GetStorageFromURL( rFile, embed::ElementModes::READ );
101         }
102         catch( const uno::Exception& )
103         {
104             DBG_ERROR("exception while creating AutoText storage");
105         }
106     }
107     InitBlockMode ( refStg );
108     ReadInfo();
109     ResetBlockMode ();
110     bInfoChanged = sal_False;
111 }
112 
113 SwXMLTextBlocks::SwXMLTextBlocks( const uno::Reference < embed::XStorage >& rStg, const String& rName )
114 : SwImpBlocks( rName )
115 , bAutocorrBlock( sal_True )
116 , nFlags ( 0 )
117 {
118     SwDocShell* pDocSh = new SwDocShell ( SFX_CREATE_MODE_INTERNAL );
119     if( !pDocSh->DoInitNew( 0 ) )
120         return;
121     bReadOnly = sal_False;
122     pDoc = pDocSh->GetDoc();
123     xDocShellRef = pDocSh;
124     pDoc->SetOle2Link( Link() );
125     pDoc->GetIDocumentUndoRedo().DoUndo(false);
126     pDoc->acquire();
127 
128     InitBlockMode ( rStg );
129     ReadInfo();
130     bInfoChanged = sal_False;
131 }
132 
133 SwXMLTextBlocks::~SwXMLTextBlocks()
134 {
135     if ( bInfoChanged )
136         WriteInfo();
137     ResetBlockMode ();
138     if(xDocShellRef.Is())
139         xDocShellRef->DoClose();
140     xDocShellRef = 0;
141     if( pDoc && !pDoc->release() )
142         delete pDoc;
143 }
144 
145 void SwXMLTextBlocks::ClearDoc()
146 {
147     SwDocShell * pDocShell = pDoc->GetDocShell();
148     pDocShell->InvalidateModel();
149     pDocShell->ReactivateModel();
150 
151     pDoc->ClearDoc();
152     pDocShell->ClearEmbeddedObjects();
153 }
154 void SwXMLTextBlocks::AddName( const String& rShort, const String& rLong, sal_Bool bOnlyTxt )
155 {
156     sal_uInt16 nIdx = GetIndex( rShort );
157     SwBlockName* pNew = NULL;
158     if( nIdx != (sal_uInt16) -1 )
159         aNames.DeleteAndDestroy( nIdx );
160 
161     GeneratePackageName( rShort, aPackageName );
162     pNew = new SwBlockName( rShort, rLong, aPackageName );
163 
164     pNew->bIsOnlyTxtFlagInit = sal_True;
165     pNew->bIsOnlyTxt = bOnlyTxt;
166     aNames.C40_PTR_INSERT( SwBlockName, pNew );
167     bInfoChanged = sal_True;
168 }
169 void SwXMLTextBlocks::AddName( const String& rShort, const String& rLong,
170                            const String& rPackageName, sal_Bool bOnlyTxt )
171 {
172     sal_uInt16 nIdx = GetIndex( rShort );
173     if( nIdx != (sal_uInt16) -1 )
174         aNames.DeleteAndDestroy( nIdx );
175     SwBlockName* pNew = new SwBlockName( rShort, rLong, rPackageName );
176     pNew->bIsOnlyTxtFlagInit = sal_True;
177     pNew->bIsOnlyTxt = bOnlyTxt;
178     aNames.C40_PTR_INSERT( SwBlockName, pNew );
179     bInfoChanged = sal_True;
180 }
181 
182 sal_uLong SwXMLTextBlocks::Delete( sal_uInt16 n )
183 {
184     String aPckName (aNames[ n ]->aPackageName);
185     uno::Reference < container::XNameAccess > xAccess( xBlkRoot, uno::UNO_QUERY );
186     if ( xAccess.is() &&
187             xAccess->hasByName( aPckName ) && xBlkRoot->isStreamElement( aPckName ) )
188     {
189         try
190         {
191             xBlkRoot->removeElement ( aPckName );
192             uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY );
193             if ( xTrans.is() )
194                 xTrans->commit();
195             return 0;
196         }
197         catch ( uno::Exception)
198         {
199             return ERR_SWG_WRITE_ERROR;
200         }
201     }
202     return 0;
203 }
204 
205 sal_uLong SwXMLTextBlocks::Rename( sal_uInt16 nIdx, const String& rNewShort, const String& )
206 {
207     DBG_ASSERT( xBlkRoot.is(), "No storage set" );
208     if(!xBlkRoot.is())
209         return 0;
210     String aOldName (aNames[ nIdx ]->aPackageName);
211     aShort = rNewShort;
212     GeneratePackageName( aShort, aPackageName );
213     if (IsOnlyTextBlock ( nIdx ) )
214     {
215         String sExt( String::CreateFromAscii( ".xml" ));
216         String aOldStreamName( aOldName ); aOldStreamName += sExt;
217         String aNewStreamName( aPackageName ); aNewStreamName += sExt;
218 
219         xRoot = xBlkRoot->openStorageElement( aOldName, embed::ElementModes::READWRITE );
220         xRoot->renameElement ( aOldStreamName, aNewStreamName );
221         uno::Reference < embed::XTransactedObject > xTrans( xRoot, uno::UNO_QUERY );
222         if ( xTrans.is() )
223             xTrans->commit();
224         xRoot = 0;
225     }
226 
227     if(aOldName != aPackageName)
228     {
229         try
230         {
231             xBlkRoot->renameElement ( aOldName, aPackageName );
232         }
233         catch( const container::ElementExistException& rEx )
234         {
235             (void)rEx;
236         }
237     }
238     uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY );
239     if ( xTrans.is() )
240         xTrans->commit();
241     // No need to commit xBlkRoot here as SwTextBlocks::Rename calls
242     // WriteInfo which does the commit
243     return 0;
244 }
245 
246 sal_uLong SwXMLTextBlocks::CopyBlock( SwImpBlocks& rDestImp, String& rShort,
247                                                     const String& rLong)
248 {
249     sal_uLong nError = 0;
250     OpenFile(sal_True);
251     rDestImp.OpenFile(sal_False);
252     String aGroup( rShort );
253     sal_Bool bTextOnly = IsOnlyTextBlock ( rShort ) ;//pImp->pBlkRoot->IsStream( aGroup );
254     sal_uInt16 nIndex = GetIndex ( rShort );
255     String sDestShortName( GetPackageName (nIndex) );
256     sal_uInt16 nIdx = 0;
257 
258     DBG_ASSERT( xBlkRoot.is(), "No storage set" );
259     if(!xBlkRoot.is())
260         return ERR_SWG_WRITE_ERROR;
261 
262     uno::Reference < container::XNameAccess > xAccess( ((SwXMLTextBlocks&)rDestImp).xBlkRoot, uno::UNO_QUERY );
263     while ( xAccess->hasByName( sDestShortName ) )
264     {
265         ++nIdx;
266         //falls wirklich mal einer so verrueckt ist
267         if(USHRT_MAX == nIdx)
268         {
269             CloseFile();
270             rDestImp.CloseFile();
271             return ERR_SWG_WRITE_ERROR;
272         }
273         sDestShortName += String::CreateFromInt32( nIdx );
274     }
275 
276     try
277     {
278         uno::Reference < embed::XStorage > rSourceRoot = xBlkRoot->openStorageElement( aGroup, embed::ElementModes::READ );
279         uno::Reference < embed::XStorage > rDestRoot = ((SwXMLTextBlocks&)rDestImp).xBlkRoot->openStorageElement( sDestShortName, embed::ElementModes::READWRITE );
280         //if(!rSourceRoot.Is())
281         //    nError = ERR_SWG_READ_ERROR;
282         //else
283         //{
284         rSourceRoot->copyToStorage( rDestRoot );
285     }
286     catch ( uno::Exception& )
287     {
288         nError = ERR_SWG_WRITE_ERROR;
289     }
290 
291     /* I think this should work now that text only blocks are in sub-storages as well
292     else
293     {
294         SvStorageStreamRef rSourceStream = xBlkRoot->OpenStream( aGroup, STREAM_STGREAD );
295         SvStorageStreamRef rDestStream = ((SwXMLTextBlocks&)rDestImp).xBlkRoot-> OpenStream( sDestShortName, STREAM_STGWRITE );
296         if(!rDestStream.Is())
297             nError = ERR_SWG_WRITE_ERROR;
298         else
299         {
300             if(!rSourceStream->CopyTo(&rDestStream))
301                 nError = ERR_SWG_WRITE_ERROR;
302             else
303                 rDestStream->Commit();
304         }
305     }
306     */
307     if(!nError)
308     {
309         rShort = sDestShortName;
310         //((SwXMLTextBlocks&)rDestImp).xBlkRoot->Commit();
311         ((SwXMLTextBlocks&)rDestImp).AddName( rShort, rLong, bTextOnly );
312         ((SwXMLTextBlocks&)rDestImp).MakeBlockList();
313     }
314     CloseFile();
315     rDestImp.CloseFile();
316     return nError;
317 }
318 
319 
320 sal_uLong SwXMLTextBlocks::StartPutBlock( const String& rShort, const String& rPackageName )
321 {
322     DBG_ASSERT( xBlkRoot.is(), "No storage set" );
323     if(!xBlkRoot.is())
324         return 0;
325     GetIndex ( rShort );
326     /*
327     if( xBlkRoot->IsContained( rPackageName ) )
328     {
329         xBlkRoot->Remove( rPackageName );
330         xBlkRoot->Commit();
331     }
332     */
333     try
334     {
335         xRoot = xBlkRoot->openStorageElement( rPackageName, embed::ElementModes::READWRITE );
336 
337         uno::Reference< beans::XPropertySet > xRootProps( xRoot, uno::UNO_QUERY_THROW );
338         ::rtl::OUString aPropName( RTL_CONSTASCII_USTRINGPARAM("MediaType") );
339         ::rtl::OUString aMime( SotExchange::GetFormatMimeType( SOT_FORMATSTR_ID_STARWRITER_8 ) );
340         xRootProps->setPropertyValue( aPropName, uno::makeAny( aMime ) );
341     }
342     catch (uno::Exception&)
343     {
344     }
345     return 0;
346 }
347 sal_uLong SwXMLTextBlocks::BeginPutDoc( const String& rShort, const String& rLong )
348 {
349     // In der Basisklasse ablegen!
350     aShort = rShort;
351     aLong = rLong;
352     GeneratePackageName( rShort, aPackageName );
353     SetIsTextOnly( rShort, sal_False);
354     return StartPutBlock (rShort, aPackageName);
355 }
356 
357 sal_uLong SwXMLTextBlocks::PutBlock( SwPaM& , const String& )
358 {
359     sal_uLong nRes = 0;
360     sal_uInt16 nCommitFlags = nFlags & (SWXML_CONVBLOCK|SWXML_NOROOTCOMMIT);
361 
362     nFlags |= nCommitFlags;
363 
364     WriterRef xWrt;
365     ::GetXMLWriter ( aEmptyStr, GetBaseURL(), xWrt);
366     SwWriter aWriter (xRoot, *pDoc );
367 
368     xWrt->bBlock = sal_True;
369     nRes = aWriter.Write ( xWrt );
370     xWrt->bBlock = sal_False;
371     // Save OLE objects if there are some
372     SwDocShell *pDocSh = pDoc->GetDocShell();
373 
374     sal_Bool bHasChildren = pDocSh && pDocSh->GetEmbeddedObjectContainer().HasEmbeddedObjects();
375     if( !nRes && bHasChildren )
376     {
377         // we have to write to the temporary storage first, since the used below functions are optimized
378         // TODO/LATER: it is only a temporary solution, that should be changed soon, the used methods should be
379         // called without optimization
380 
381         sal_Bool bOK = sal_False;
382 
383         if ( xRoot.is() )
384         {
385             SfxMedium* pTmpMedium = NULL;
386             try
387             {
388                 uno::Reference< embed::XStorage > xTempStorage =
389                     ::comphelper::OStorageHelper::GetTemporaryStorage();
390 
391                 xRoot->copyToStorage( xTempStorage );
392 
393                 // TODO/LATER: no progress bar?!
394                 // TODO/MBA: strange construct
395                 pTmpMedium = new SfxMedium( xTempStorage, GetBaseURL() );
396                 sal_Bool bTmpOK = pDocSh->SaveAsChildren( *pTmpMedium );
397                 if( bTmpOK )
398                     bTmpOK = pDocSh->SaveCompletedChildren( sal_False );
399 
400                 xTempStorage->copyToStorage( xRoot );
401                 bOK = bTmpOK;
402             }
403             catch( uno::Exception& )
404             {
405             }
406 
407             if ( pTmpMedium )
408                 DELETEZ( pTmpMedium );
409         }
410 
411         if( !bOK )
412             nRes = ERR_SWG_WRITE_ERROR;
413     }
414 
415     try
416     {
417         uno::Reference < embed::XTransactedObject > xTrans( xRoot, uno::UNO_QUERY );
418         if ( xTrans.is() )
419             xTrans->commit();
420         xRoot = 0;
421         if ( !nCommitFlags )
422         {
423             uno::Reference < embed::XTransactedObject > xTmpTrans( xBlkRoot, uno::UNO_QUERY );
424             if ( xTmpTrans.is() )
425                 xTmpTrans->commit();
426         }
427     }
428     catch (uno::Exception&)
429     {
430     }
431 
432     //TODO/LATER: error handling
433     /*
434     sal_uLong nErr = xBlkRoot->GetError();
435     if( nErr == SVSTREAM_DISK_FULL )
436         nRes = ERR_W4W_WRITE_FULL;
437     else if( nErr != SVSTREAM_OK )
438         nRes = ERR_SWG_WRITE_ERROR;
439     nFlags |= nCommitFlags;
440     return nErr;*/
441     return 0;
442 }
443 
444 sal_uLong SwXMLTextBlocks::PutDoc()
445 {
446     SwPaM* pPaM = MakePaM();
447     sal_uLong nErr = PutBlock(*pPaM, aLong);
448     delete pPaM;
449     return nErr;
450 }
451 
452 sal_uLong SwXMLTextBlocks::GetText( sal_uInt16 nIdx, String& rText )
453 {
454     return GetBlockText( aNames[ nIdx ]->aShort, rText );
455 }
456 
457 sal_uLong SwXMLTextBlocks::GetText( const String& rShort, String& rText )
458 {
459     return GetBlockText( rShort, rText );
460 }
461 
462 
463 sal_uLong SwXMLTextBlocks::MakeBlockList()
464 {
465     WriteInfo();
466     return 0;
467 }
468 
469 sal_Bool SwXMLTextBlocks::PutMuchEntries( sal_Bool bOn )
470 {
471     sal_Bool bRet = sal_False;
472     if( bOn )
473     {
474         if( bInPutMuchBlocks )
475         {
476             ASSERT( !this, "verschachtelte Aufrufe sind nicht erlaubt" );
477         }
478         else if( !IsFileChanged() )
479         {
480             bRet = 0 == OpenFile( sal_False );
481             if( bRet )
482             {
483                 nFlags |= SWXML_NOROOTCOMMIT;
484                 bInPutMuchBlocks = sal_True;
485             }
486         }
487     }
488     else if( bInPutMuchBlocks )
489     {
490         nFlags &= ~SWXML_NOROOTCOMMIT;
491         if( xBlkRoot.is() )
492         {
493             try
494             {
495                 uno::Reference < embed::XTransactedObject > xTrans( xBlkRoot, uno::UNO_QUERY );
496                 if ( xTrans.is() )
497                     xTrans->commit();
498                 MakeBlockList();
499                 CloseFile();
500                 Touch();
501                 bInPutMuchBlocks = sal_False;
502                 bRet = sal_True;
503             }
504             catch (uno::Exception&)
505             {
506             }
507         }
508     }
509     return bRet;
510 }
511 
512 sal_uLong SwXMLTextBlocks::OpenFile( sal_Bool bRdOnly )
513 {
514     if( bAutocorrBlock )
515         return 0;
516     sal_uLong nRet = 0;
517     try
518     {
519         uno::Reference < embed::XStorage > refStg  = comphelper::OStorageHelper::GetStorageFromURL( aFile,
520                 bRdOnly ? embed::ElementModes::READ : embed::ElementModes::READWRITE );
521         InitBlockMode ( refStg );
522     }
523     catch ( uno::Exception& )
524     {
525         //TODO/LATER: error handling
526         nRet = 1;
527     }
528 
529     return nRet;
530 }
531 
532 void SwXMLTextBlocks::CloseFile()
533 {
534     if ( !bAutocorrBlock )
535     {
536         if (bInfoChanged)
537             WriteInfo();
538         ResetBlockMode();
539     }
540 }
541 
542 void SwXMLTextBlocks::SetIsTextOnly( const String& rShort, sal_Bool bNewValue )
543 {
544     sal_uInt16 nIdx = GetIndex ( rShort );
545     if (nIdx != (sal_uInt16) -1  && nIdx != USHRT_MAX)
546         aNames[nIdx]->bIsOnlyTxt = bNewValue;
547 }
548 
549 void SwXMLTextBlocks::SetIsTextOnly( sal_uInt16 nIdx, sal_Bool bNewValue )
550 {
551     aNames[nIdx]->bIsOnlyTxt = bNewValue;
552 }
553 
554 sal_Bool SwXMLTextBlocks::IsOnlyTextBlock( const String& rShort ) const
555 {
556     sal_uInt16 nIdx = GetIndex ( rShort );
557     sal_Bool bRet = sal_False;
558     if (nIdx != (sal_uInt16) -1  && nIdx != USHRT_MAX)
559     {
560         bRet = aNames[nIdx]->bIsOnlyTxt;
561     }
562     return bRet;
563 }
564 sal_Bool SwXMLTextBlocks::IsOnlyTextBlock( sal_uInt16 nIdx ) const
565 {
566     return aNames[nIdx]->bIsOnlyTxt;
567 }
568 
569 sal_Bool SwXMLTextBlocks::IsFileUCBStorage( const String & rFileName)
570 {
571     String aName( rFileName );
572     INetURLObject aObj( aName );
573     if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
574     {
575         String aURL;
576         ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aName, aURL );
577         aObj.SetURL( aURL );
578         aName = aObj.GetMainURL( INetURLObject::NO_DECODE );
579     }
580 
581     SvStream * pStm = ::utl::UcbStreamHelper::CreateStream( aName, STREAM_STD_READ );
582     sal_Bool bRet = UCBStorage::IsStorageFile( pStm );
583     delete pStm;
584     return bRet;
585 }
586 
587 
588 
589 short SwXMLTextBlocks::GetFileType ( void ) const
590 {
591     return SWBLK_XML;
592 }
593 
594 void SwXMLTextBlocks::GeneratePackageName ( const String& rShort, String& rPackageName )
595 {
596     rPackageName = rShort;
597     xub_StrLen nPos = 0;
598     sal_Unicode pDelims[] = { '!', '/', ':', '.', '\\', 0 };
599     ByteString sByte ( rPackageName, RTL_TEXTENCODING_UTF7);
600     rPackageName = String (sByte, RTL_TEXTENCODING_ASCII_US);
601     while( STRING_NOTFOUND != ( nPos = rPackageName.SearchChar( pDelims, nPos )))
602     {
603         rPackageName.SetChar( nPos, '_' );
604         ++nPos;
605     }
606 }
607 
608 sal_uLong SwXMLTextBlocks::PutText( const String& rShort, const String& rName,
609                                 const String& rText )
610 {
611     sal_uLong nRes = 0;
612     aShort = rShort;
613     aLong = rName;
614     aCur = rText;
615     SetIsTextOnly( aShort, sal_True );
616     GeneratePackageName( rShort, aPackageName );
617     ClearDoc();
618     nRes = PutBlockText( rShort, rName, rText, aPackageName );
619     return nRes;
620 }
621 
622 void SwXMLTextBlocks::MakeBlockText( const String& rText )
623 {
624     SwTxtNode* pTxtNode = pDoc->GetNodes()[ pDoc->GetNodes().GetEndOfContent().
625                                         GetIndex() - 1 ]->GetTxtNode();
626     //JP 18.09.98: Bug 56706 - Standard sollte zumindest gesetzt sein!
627     if( pTxtNode->GetTxtColl() == pDoc->GetDfltTxtFmtColl() )
628         pTxtNode->ChgFmtColl( pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD ));
629 
630     xub_StrLen nPos = 0;
631     do
632     {
633         if ( nPos )
634         {
635             pTxtNode = (SwTxtNode*)pTxtNode->AppendNode( SwPosition( *pTxtNode ) );
636         }
637         SwIndex aIdx( pTxtNode );
638         String sTemp(rText.GetToken( 0, '\015', nPos ) );
639         pTxtNode->InsertText( sTemp, aIdx );
640     } while ( STRING_NOTFOUND != nPos );
641 }
642