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: undobj.cxx,v $
10 * $Revision: 1.29.52.1 $
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"
36 #include <fmtanchr.hxx>
41 #include <swundo.hxx> // fuer die UndoIds
46 #include <ndnotxt.hxx>
49 #include <redline.hxx>
50 #include <crossrefbookmark.hxx>
55 #include <comcore.hrc>
59 class SwRedlineSaveData
: public SwUndRng
, public SwRedlineData
,
60 private SwUndoSaveSection
63 SwRedlineSaveData( SwComparePosition eCmpPos
,
64 const SwPosition
& rSttPos
, const SwPosition
& rEndPos
,
65 SwRedline
& rRedl
, BOOL bCopyNext
);
67 void RedlineToDoc( SwPaM
& rPam
);
68 SwNodeIndex
* GetMvSttIdx() const
69 { return SwUndoSaveSection::GetMvSttIdx(); }
76 SV_IMPL_PTRARR( SwUndos
, SwUndo
*)
77 SV_IMPL_PTRARR( SwRedlineSaveDatas
, SwRedlineSaveDataPtr
)
79 SwUndoIter::SwUndoIter( SwPaM
* pPam
, SwUndoId nId
)
82 bWeiter
= nId
? TRUE
: FALSE
;
89 inline SwDoc
& SwUndoIter::GetDoc() const { return *pAktPam
->GetDoc(); }
91 //------------------------------------------------------------
93 // Diese Klasse speichert den Pam als USHORT's und kann diese wieder zu
95 // einem PaM zusammensetzen
97 : nSttNode( 0 ), nEndNode( 0 ), nSttCntnt( 0 ), nEndCntnt( 0 )
101 SwUndRng::SwUndRng( const SwPaM
& rPam
)
106 void SwUndRng::SetValues( const SwPaM
& rPam
)
108 const SwPosition
*pStt
= rPam
.Start();
111 const SwPosition
*pEnd
= rPam
.GetPoint() == pStt
114 nEndNode
= pEnd
->nNode
.GetIndex();
115 nEndCntnt
= pEnd
->nContent
.GetIndex();
118 // keine Selektion !!
119 nEndNode
= 0, nEndCntnt
= STRING_MAXLEN
;
121 nSttNode
= pStt
->nNode
.GetIndex();
122 nSttCntnt
= pStt
->nContent
.GetIndex();
125 void SwUndRng::SetPaM( SwPaM
& rPam
, BOOL bCorrToCntnt
) const
128 rPam
.GetPoint()->nNode
= nSttNode
;
129 SwNode
* pNd
= rPam
.GetNode();
130 if( pNd
->IsCntntNode() )
131 rPam
.GetPoint()->nContent
.Assign( pNd
->GetCntntNode(), nSttCntnt
);
132 else if( bCorrToCntnt
)
133 rPam
.Move( fnMoveForward
, fnGoCntnt
);
135 rPam
.GetPoint()->nContent
.Assign( 0, 0 );
137 if( !nEndNode
&& STRING_MAXLEN
== nEndCntnt
) // keine Selection
141 if( nSttNode
== nEndNode
&& nSttCntnt
== nEndCntnt
)
142 return; // nichts mehr zu tun
144 rPam
.GetPoint()->nNode
= nEndNode
;
145 if( (pNd
= rPam
.GetNode())->IsCntntNode() )
146 rPam
.GetPoint()->nContent
.Assign( pNd
->GetCntntNode(), nEndCntnt
);
147 else if( bCorrToCntnt
)
148 rPam
.Move( fnMoveBackward
, fnGoCntnt
);
150 rPam
.GetPoint()->nContent
.Assign( 0, 0 );
153 void SwUndRng::SetPaM( SwUndoIter
& rIter
, BOOL bCorrToCntnt
) const
156 SetPaM( *rIter
.pAktPam
, bCorrToCntnt
);
159 //------------------------------------------------------------
162 void SwUndo::RemoveIdxFromSection( SwDoc
& rDoc
, ULONG nSttIdx
,
165 SwNodeIndex
aIdx( rDoc
.GetNodes(), nSttIdx
);
166 SwNodeIndex
aEndIdx( rDoc
.GetNodes(), pEndIdx
? *pEndIdx
167 : aIdx
.GetNode().EndOfSectionIndex() );
168 SwPosition
aPos( rDoc
.GetNodes().GetEndOfPostIts() );
169 rDoc
.CorrAbs( aIdx
, aEndIdx
, aPos
, TRUE
);
172 void SwUndo::RemoveIdxFromRange( SwPaM
& rPam
, BOOL bMoveNext
)
174 const SwPosition
* pEnd
= rPam
.End();
177 if( pEnd
!= rPam
.GetPoint() )
180 SwNodeIndex
aStt( rPam
.GetMark()->nNode
);
181 SwNodeIndex
aEnd( rPam
.GetPoint()->nNode
);
183 if( !rPam
.Move( fnMoveForward
) )
186 if( !rPam
.Move( fnMoveBackward
) )
188 rPam
.GetPoint()->nNode
= rPam
.GetDoc()->GetNodes().GetEndOfPostIts();
189 rPam
.GetPoint()->nContent
.Assign( 0, 0 );
193 rPam
.GetDoc()->CorrAbs( aStt
, aEnd
, *rPam
.GetPoint(), TRUE
);
196 rPam
.GetDoc()->CorrAbs( rPam
, *pEnd
, TRUE
);
199 void SwUndo::RemoveIdxRel( ULONG nIdx
, const SwPosition
& rPos
)
201 // nur die Crsr verschieben; die Bookmarks/TOXMarks/.. werden vom
202 // entsp. JoinNext/JoinPrev erledigt!
203 SwNodeIndex
aIdx( rPos
.nNode
.GetNode().GetNodes(), nIdx
);
204 ::PaMCorrRel( aIdx
, rPos
);
207 SwUndo::SwUndo( SwUndoId nI
)
208 : nId(nI
), nOrigRedlineMode(nsRedlineMode_t::REDLINE_NONE
),
209 bCacheComment(true), pComment(NULL
)
213 bool SwUndo::IsDelBox() const
215 return GetId() == UNDO_COL_DELETE
|| GetId() == UNDO_ROW_DELETE
||
216 GetId() == UNDO_TABLE_DELBOX
;
224 void SwUndo::Repeat( SwUndoIter
& rIter
)
226 rIter
.pLastUndoObj
= this;
229 String
SwUndo::GetComment() const
237 pComment
= new String(SW_RES(UNDO_BASE
+ nId
));
239 SwRewriter aRewriter
= GetRewriter();
241 *pComment
= aRewriter
.Apply(*pComment
);
248 aResult
= String(SW_RES(UNDO_BASE
+ nId
));
250 SwRewriter aRewriter
= GetRewriter();
252 aResult
= aRewriter
.Apply(aResult
);
258 SwUndoId
SwUndo::GetEffectiveId() const
263 SwRewriter
SwUndo::GetRewriter() const
270 //------------------------------------------------------------
272 SwUndoSaveCntnt::SwUndoSaveCntnt()
276 SwUndoSaveCntnt::~SwUndoSaveCntnt()
281 // wird fuer das Loeschen von Inhalt benoetigt. Fuer das ReDo werden
282 // Inhalte in das UndoNodesArray verschoben. Diese Methoden fuegen
283 // am Ende eines TextNodes fuer die Attribute einen Trenner ein.
284 // Dadurch werden die Attribute nicht expandiert.
285 // MoveTo.. verschiebt aus dem NodesArray in das UndoNodesArray
286 // MoveFrom.. verschiebt aus dem UndoNodesArray in das NodesArray
288 // 2.8.93: ist pEndNdIdx angebenen, wird vom Undo/Redo -Ins/DelFly
289 // aufgerufen. Dann soll die gesamte Section verschoben werden.
291 void SwUndoSaveCntnt::MoveToUndoNds( SwPaM
& rPaM
, SwNodeIndex
* pNodeIdx
,
292 SwIndex
* pCntIdx
, ULONG
* pEndNdIdx
, xub_StrLen
* pEndCntIdx
)
294 SwDoc
& rDoc
= *rPaM
.GetDoc();
295 BOOL bUndo
= rDoc
.DoesUndo();
296 rDoc
.DoUndo( FALSE
);
298 SwNoTxtNode
* pCpyNd
= rPaM
.GetNode()->GetNoTxtNode();
300 // jetzt kommt das eigentliche Loeschen(Verschieben)
301 SwNodes
& rNds
= (SwNodes
&)*rDoc
.GetUndoNds();
302 SwPosition
aPos( pEndNdIdx
? rNds
.GetEndOfPostIts()
303 : rNds
.GetEndOfExtras() );
306 const SwPosition
* pStt
= rPaM
.Start(), *pEnd
= rPaM
.End();
308 if( pCpyNd
|| pEndNdIdx
|| !aPos
.nNode
.GetNode().GetCntntNode() ||
309 (!pStt
->nContent
.GetIndex() && (pStt
->nNode
!= pEnd
->nNode
||
310 (!pStt
->nNode
.GetNode().GetCntntNode() ||
311 pStt
->nNode
.GetNode().GetCntntNode()->Len() ==
312 pEnd
->nContent
.GetIndex() ) ) ) )
318 aPos
.nNode
.GetNode().GetCntntNode()->MakeEndIndex( &aPos
.nContent
);
320 // als USHORT merken; die Indizies verschieben sich !!
321 ULONG nTmpMvNode
= aPos
.nNode
.GetIndex();
322 xub_StrLen nTmpMvCntnt
= aPos
.nContent
.GetIndex();
324 if( pCpyNd
|| pEndNdIdx
)
326 SwNodeRange
aRg( pStt
->nNode
, 0, pEnd
->nNode
, 1 );
327 rDoc
.GetNodes()._MoveNodes( aRg
, rNds
, aPos
.nNode
, FALSE
);
333 rDoc
.GetNodes().MoveRange( rPaM
, aPos
, rNds
);
335 SwTxtNode
* pTxtNd
= aPos
.nNode
.GetNode().GetTxtNode();
336 if( pTxtNd
) // fuege einen Trenner fuer die Attribute ein !
338 // weil aber beim Insert die Attribute angefasst/sprich
339 // aus dem Array geloescht und wieder eingefuegt werden, koennen
340 // dadurch Attribute verschwinden (z.B "Fett aus" von 10-20,
341 // "Fett an" von 12-15, dann wird durchs Insert/Delete das
342 // "Fett an" geloescht !! Ist hier aber nicht erwuenscht !!)
343 // DARUM: nicht die Hints anfassen, direct den String manipulieren
345 String
& rStr
= (String
&)pTxtNd
->GetTxt();
346 // Zur Sicherheit lieber nur wenn wirklich am Ende steht
347 if( rStr
.Len() == aPos
.nContent
.GetIndex() )
354 pTxtNd
->InsertText( sal_Unicode(' '), aPos
.nContent
,
355 IDocumentContentOperations::INS_NOHINTEXPAND
);
360 *pEndNdIdx
= aPos
.nNode
.GetIndex();
362 *pEndCntIdx
= aPos
.nContent
.GetIndex();
365 aPos
.nNode
= nTmpMvNode
;
367 *pNodeIdx
= aPos
.nNode
;
371 SwCntntNode
* pCNd
= aPos
.nNode
.GetNode().GetCntntNode();
373 pCntIdx
->Assign( pCNd
, nTmpMvCntnt
);
375 pCntIdx
->Assign( 0, 0 );
378 rDoc
.DoUndo( bUndo
);
381 void SwUndoSaveCntnt::MoveFromUndoNds( SwDoc
& rDoc
, ULONG nNodeIdx
,
382 xub_StrLen nCntIdx
, SwPosition
& rInsPos
,
383 ULONG
* pEndNdIdx
, xub_StrLen
* pEndCntIdx
)
385 // jetzt kommt das wiederherstellen
386 SwNodes
& rNds
= (SwNodes
&)*rDoc
.GetUndoNds();
387 if( nNodeIdx
== rNds
.GetEndOfPostIts().GetIndex() )
388 return; // nichts gespeichert
390 BOOL bUndo
= rDoc
.DoesUndo();
391 rDoc
.DoUndo( FALSE
);
393 SwPaM
aPaM( rInsPos
);
394 if( pEndNdIdx
) // dann hole aus diesem den Bereich
395 aPaM
.GetPoint()->nNode
.Assign( rNds
, *pEndNdIdx
);
398 aPaM
.GetPoint()->nNode
= rNds
.GetEndOfExtras();
399 GoInCntnt( aPaM
, fnMoveBackward
);
402 SwTxtNode
* pTxtNd
= aPaM
.GetNode()->GetTxtNode();
403 if( !pEndNdIdx
&& pTxtNd
) // loesche den Trenner wieder
406 aPaM
.GetPoint()->nContent
.Assign( pTxtNd
, *pEndCntIdx
);
407 if( pTxtNd
->GetTxt().Len() )
409 GoInCntnt( aPaM
, fnMoveBackward
);
410 pTxtNd
->EraseText( aPaM
.GetPoint()->nContent
, 1 );
414 aPaM
.GetPoint()->nNode
= nNodeIdx
;
415 aPaM
.GetPoint()->nContent
.Assign( aPaM
.GetCntntNode(), nCntIdx
);
417 _SaveRedlEndPosForRestore
aRedlRest( rInsPos
.nNode
, rInsPos
.nContent
.GetIndex() );
419 rNds
.MoveRange( aPaM
, rInsPos
, rDoc
.GetNodes() );
421 // noch den letzen Node loeschen.
422 if( !aPaM
.GetPoint()->nContent
.GetIndex() ||
423 ( aPaM
.GetPoint()->nNode
++ && // noch leere Nodes am Ende ??
424 &rNds
.GetEndOfExtras() != &aPaM
.GetPoint()->nNode
.GetNode() ))
426 aPaM
.GetPoint()->nContent
.Assign( 0, 0 );
428 rNds
.Delete( aPaM
.GetPoint()->nNode
,
429 rNds
.GetEndOfExtras().GetIndex() -
430 aPaM
.GetPoint()->nNode
.GetIndex() );
435 else if( pEndNdIdx
|| !pTxtNd
)
437 SwNodeRange
aRg( rNds
, nNodeIdx
, rNds
, (pEndNdIdx
439 : rNds
.GetEndOfExtras().GetIndex() ) );
440 rNds
._MoveNodes( aRg
, rDoc
.GetNodes(), rInsPos
.nNode
, 0 == pEndNdIdx
);
444 ASSERT( FALSE
, "was ist es denn nun?" );
447 rDoc
.DoUndo( bUndo
);
450 // diese beiden Methoden bewegen den Point vom Pam zurueck/vor. Damit
451 // kann fuer ein Undo/Redo ein Bereich aufgespannt werden. (Der
452 // Point liegt dann vor dem manipuliertem Bereich !!)
453 // Das Flag gibt an, ob noch vorm Point Inhalt steht.
455 BOOL
SwUndoSaveCntnt::MovePtBackward( SwPaM
& rPam
)
458 if( rPam
.Move( fnMoveBackward
))
461 // gibt es nach vorne keinen Inhalt mehr, so setze den Point einfach
462 // auf die vorherige Position (Node und Content, damit der Content
463 // abgemeldet wird !!)
464 rPam
.GetPoint()->nNode
--;
465 rPam
.GetPoint()->nContent
.Assign( 0, 0 );
469 void SwUndoSaveCntnt::MovePtForward( SwPaM
& rPam
, BOOL bMvBkwrd
)
471 // gab es noch Inhalt vor der Position ?
473 rPam
.Move( fnMoveForward
);
475 { // setzen Point auf die naechste Position
476 rPam
.GetPoint()->nNode
++;
477 SwCntntNode
* pCNd
= rPam
.GetCntntNode();
479 pCNd
->MakeStartIndex( &rPam
.GetPoint()->nContent
);
481 rPam
.Move( fnMoveForward
);
487 JP 21.03.94: loesche alle Objecte, die ContentIndizies auf den ang.
489 Zur Zeit gibts folgende Objecte
495 // --> OD 2007-10-17 #i81002# - extending method:
496 // delete certain (not all) cross-reference bookmarks at text node of <rMark>
497 // and at text node of <rPoint>, if these text nodes aren't the same.
498 void SwUndoSaveCntnt::DelCntntIndex( const SwPosition
& rMark
,
499 const SwPosition
& rPoint
,
500 DelCntntType nDelCntntType
)
502 const SwPosition
*pStt
= rMark
< rPoint
? &rMark
: &rPoint
,
503 *pEnd
= &rMark
== pStt
? &rPoint
: &rMark
;
505 SwDoc
* pDoc
= rMark
.nNode
.GetNode().GetDoc();
507 BOOL bDoesUndo
= pDoc
->DoesUndo();
508 pDoc
->DoUndo( FALSE
);
511 if( nsDelCntntType::DELCNT_FTN
& nDelCntntType
)
513 SwFtnIdxs
& rFtnArr
= pDoc
->GetFtnIdxs();
514 if( rFtnArr
.Count() )
516 const SwNode
* pFtnNd
;
518 rFtnArr
.SeekEntry( pStt
->nNode
, &nPos
);
521 // loesche erstmal alle, die dahinter stehen
522 while( nPos
< rFtnArr
.Count() && ( pFtnNd
=
523 &( pSrch
= rFtnArr
[ nPos
] )->GetTxtNode())->GetIndex()
524 <= pEnd
->nNode
.GetIndex() )
526 xub_StrLen nFtnSttIdx
= *pSrch
->GetStart();
527 if( (nsDelCntntType::DELCNT_CHKNOCNTNT
& nDelCntntType
)
528 ? (&pEnd
->nNode
.GetNode() == pFtnNd
)
529 : (( &pStt
->nNode
.GetNode() == pFtnNd
&&
530 pStt
->nContent
.GetIndex() > nFtnSttIdx
) ||
531 ( &pEnd
->nNode
.GetNode() == pFtnNd
&&
532 nFtnSttIdx
>= pEnd
->nContent
.GetIndex() )) )
534 ++nPos
; // weiter suchen
538 // es muss leider ein Index angelegt werden. Sonst knallts im
539 // TextNode, weil im DTOR der SwFtn dieser geloescht wird !!
540 SwTxtNode
* pTxtNd
= (SwTxtNode
*)pFtnNd
;
542 pHistory
= new SwHistory
;
543 SwTxtAttr
* const pFtnHnt
=
544 pTxtNd
->GetTxtAttrForCharAt( nFtnSttIdx
);
545 ASSERT( pFtnHnt
, "kein FtnAttribut" );
546 SwIndex
aIdx( pTxtNd
, nFtnSttIdx
);
547 pHistory
->Add( pFtnHnt
, pTxtNd
->GetIndex(), false );
548 pTxtNd
->EraseText( aIdx
, 1 );
551 while( nPos
-- && ( pFtnNd
= &( pSrch
= rFtnArr
[ nPos
] )->
552 GetTxtNode())->GetIndex() >= pStt
->nNode
.GetIndex() )
554 xub_StrLen nFtnSttIdx
= *pSrch
->GetStart();
555 if( !(nsDelCntntType::DELCNT_CHKNOCNTNT
& nDelCntntType
) && (
556 ( &pStt
->nNode
.GetNode() == pFtnNd
&&
557 pStt
->nContent
.GetIndex() > nFtnSttIdx
) ||
558 ( &pEnd
->nNode
.GetNode() == pFtnNd
&&
559 nFtnSttIdx
>= pEnd
->nContent
.GetIndex() )))
560 continue; // weiter suchen
562 // es muss leider ein Index angelegt werden. Sonst knallts im
563 // TextNode, weil im DTOR der SwFtn dieser geloescht wird !!
564 SwTxtNode
* pTxtNd
= (SwTxtNode
*)pFtnNd
;
566 pHistory
= new SwHistory
;
567 SwTxtAttr
* const pFtnHnt
=
568 pTxtNd
->GetTxtAttrForCharAt( nFtnSttIdx
);
569 ASSERT( pFtnHnt
, "kein FtnAttribut" );
570 SwIndex
aIdx( pTxtNd
, nFtnSttIdx
);
571 pHistory
->Add( pFtnHnt
, pTxtNd
->GetIndex(), false );
572 pTxtNd
->EraseText( aIdx
, 1 );
578 if( nsDelCntntType::DELCNT_FLY
& nDelCntntType
)
580 USHORT nChainInsPos
= pHistory
? pHistory
->Count() : 0;
581 const SwSpzFrmFmts
& rSpzArr
= *pDoc
->GetSpzFrmFmts();
582 if( rSpzArr
.Count() )
584 const BOOL bDelFwrd
= rMark
.nNode
.GetIndex() <= rPoint
.nNode
.GetIndex();
586 const SwFmtAnchor
* pAnchor
;
587 USHORT n
= rSpzArr
.Count();
588 const SwPosition
* pAPos
;
590 while( n
&& rSpzArr
.Count() )
592 pFmt
= (SwFlyFrmFmt
*)rSpzArr
[--n
];
593 pAnchor
= &pFmt
->GetAnchor();
594 switch( pAnchor
->GetAnchorId() )
597 if( 0 != (pAPos
= pAnchor
->GetCntntAnchor() ) &&
598 (( nsDelCntntType::DELCNT_CHKNOCNTNT
& nDelCntntType
)
599 ? ( pStt
->nNode
<= pAPos
->nNode
&&
600 pAPos
->nNode
< pEnd
->nNode
)
601 : ( *pStt
<= *pAPos
&& *pAPos
< *pEnd
)) )
604 pHistory
= new SwHistory
;
605 SwTxtNode
* pTxtNd
= pDoc
->GetNodes()[ pAPos
->nNode
]->GetTxtNode();
606 SwTxtAttr
* const pFlyHnt
= pTxtNd
->GetTxtAttrForCharAt(
607 pAPos
->nContent
.GetIndex());
608 ASSERT( pFlyHnt
, "kein FlyAttribut" );
609 pHistory
->Add( pFlyHnt
, 0, false );
610 // n wieder zurueck, damit nicht ein Format uebesprungen wird !
611 n
= n
>= rSpzArr
.Count() ? rSpzArr
.Count() : n
+1;
616 pAPos
= pAnchor
->GetCntntAnchor();
620 if( nsDelCntntType::DELCNT_CHKNOCNTNT
& nDelCntntType
)
621 bTmp
= pStt
->nNode
<= pAPos
->nNode
&& pAPos
->nNode
< pEnd
->nNode
;
625 bTmp
= rMark
.nNode
< pAPos
->nNode
&&
626 pAPos
->nNode
<= rPoint
.nNode
;
628 bTmp
= rPoint
.nNode
<= pAPos
->nNode
&&
629 pAPos
->nNode
< rMark
.nNode
;
635 pHistory
= new SwHistory
;
637 // Moving the anchor?
638 if( !( nsDelCntntType::DELCNT_CHKNOCNTNT
& nDelCntntType
) &&
639 ( rPoint
.nNode
.GetIndex() == pAPos
->nNode
.GetIndex() ) )
641 // Do not try to move the anchor to a table!
642 if( rMark
.nNode
.GetNode().GetTxtNode() )
644 pHistory
->Add( *pFmt
);
645 SwFmtAnchor
aAnch( *pAnchor
);
646 SwPosition
aPos( rMark
.nNode
);
647 aAnch
.SetAnchor( &aPos
);
648 pFmt
->SetFmtAttr( aAnch
);
653 pHistory
->Add( *pFmt
, nChainInsPos
);
654 // n wieder zurueck, damit nicht ein
655 // Format uebesprungen wird !
656 n
= n
>= rSpzArr
.Count() ?
657 rSpzArr
.Count() : n
+1;
664 if( 0 != (pAPos
= pAnchor
->GetCntntAnchor() ) &&
665 ( pStt
->nNode
<= pAPos
->nNode
&& pAPos
->nNode
<= pEnd
->nNode
) )
668 pHistory
= new SwHistory
;
669 if( pAPos
->nNode
< pEnd
->nNode
&&
670 ( ( nsDelCntntType::DELCNT_CHKNOCNTNT
& nDelCntntType
) ||
671 ( pStt
->nNode
< pAPos
->nNode
|| !pStt
->nContent
.GetIndex() ) ) )
673 // Here we identified the objects to destroy:
674 // - anchored between start and end of the selection
675 // - anchored in start of the selection with "CheckNoContent"
676 // - anchored in start of sel. and the selection start at pos 0
677 pHistory
->Add( *pFmt
, nChainInsPos
);
678 n
= n
>= rSpzArr
.Count() ? rSpzArr
.Count() : n
+1;
680 else if( !( nsDelCntntType::DELCNT_CHKNOCNTNT
& nDelCntntType
) )
682 if( *pStt
<= *pAPos
&& *pAPos
< *pEnd
)
684 // These are the objects anchored
685 // between section start and end position
686 // Do not try to move the anchor to a table!
687 if( rMark
.nNode
.GetNode().GetTxtNode() )
689 pHistory
->Add( *pFmt
);
690 SwFmtAnchor
aAnch( *pAnchor
);
691 aAnch
.SetAnchor( &rMark
);
692 pFmt
->SetFmtAttr( aAnch
);
700 if( 0 != (pAPos
= pAnchor
->GetCntntAnchor() ) &&
701 pStt
->nNode
== pAPos
->nNode
)
704 pHistory
= new SwHistory
;
706 pHistory
->Add( *pFmt
, nChainInsPos
);
708 // n wieder zurueck, damit nicht ein Format uebesprungen wird !
709 n
= n
>= rSpzArr
.Count() ? rSpzArr
.Count() : n
+1;
719 if( nsDelCntntType::DELCNT_BKM
& nDelCntntType
)
721 IDocumentMarkAccess
* const pMarkAccess
= pDoc
->getIDocumentMarkAccess();
722 if( pMarkAccess
->getMarksCount() )
725 for( USHORT n
= 0; n
< pMarkAccess
->getMarksCount(); ++n
)
727 // --> OD 2007-10-17 #i81002#
728 bool bSavePos
= false;
729 bool bSaveOtherPos
= false;
730 const ::sw::mark::IMark
* pBkmk
= (pMarkAccess
->getMarksBegin() + n
)->get();
731 if( nsDelCntntType::DELCNT_CHKNOCNTNT
& nDelCntntType
)
733 if( pStt
->nNode
<= pBkmk
->GetMarkPos().nNode
&&
734 pBkmk
->GetMarkPos().nNode
< pEnd
->nNode
)
736 if( pBkmk
->IsExpanded() &&
737 pStt
->nNode
<= pBkmk
->GetOtherMarkPos().nNode
&&
738 pBkmk
->GetOtherMarkPos().nNode
< pEnd
->nNode
)
739 bSaveOtherPos
= true;
743 // --> OD 2009-08-06 #i92125#
744 bool bKeepCrossRefBkmk( false );
746 if ( rMark
.nNode
== rPoint
.nNode
&&
747 ( IDocumentMarkAccess::GetType(*pBkmk
) ==
748 IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK
||
749 IDocumentMarkAccess::GetType(*pBkmk
) ==
750 IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK
) )
752 bKeepCrossRefBkmk
= true;
755 if ( !bKeepCrossRefBkmk
)
758 if ( *pStt
<= pBkmk
->GetMarkPos() && pBkmk
->GetMarkPos() <= *pEnd
)
760 if( pBkmk
->GetMarkPos() == *pEnd
||
761 ( *pStt
== pBkmk
->GetMarkPos() && pBkmk
->IsExpanded() ) )
766 if( pBkmk
->IsExpanded() &&
767 *pStt
<= pBkmk
->GetOtherMarkPos() && pBkmk
->GetOtherMarkPos() <= *pEnd
)
769 if( bSavePos
|| bSaveOtherPos
||
770 ( pBkmk
->GetOtherMarkPos() < *pEnd
&& pBkmk
->GetOtherMarkPos() > *pStt
) )
774 bSaveOtherPos
= true;
780 // --> OD 2007-10-17 #i81002#
781 const bool bDifferentTxtNodesAtMarkAndPoint(
782 rMark
.nNode
!= rPoint
.nNode
&&
783 rMark
.nNode
.GetNode().GetTxtNode() &&
784 rPoint
.nNode
.GetNode().GetTxtNode() );
786 if( !bSavePos
&& !bSaveOtherPos
&& bDifferentTxtNodesAtMarkAndPoint
&&
787 dynamic_cast< const ::sw::mark::CrossRefBookmark
* >(pBkmk
))
789 // delete cross-reference bookmark at <pStt>, if only part of
790 // <pEnd> text node content is deleted.
791 if( pStt
->nNode
== pBkmk
->GetMarkPos().nNode
&&
792 pEnd
->nContent
.GetIndex() !=
793 pEnd
->nNode
.GetNode().GetTxtNode()->Len() )
796 bSaveOtherPos
= false;
798 // delete cross-reference bookmark at <pEnd>, if only part of
799 // <pStt> text node content is deleted.
800 else if( pEnd
->nNode
== pBkmk
->GetMarkPos().nNode
&&
801 pStt
->nContent
.GetIndex() != 0 )
804 bSaveOtherPos
= false;
808 if( bSavePos
|| bSaveOtherPos
)
811 pHistory
= new SwHistory
;
813 pHistory
->Add( *pBkmk
, bSavePos
, bSaveOtherPos
);
815 (bSaveOtherPos
|| !pBkmk
->IsExpanded()))
817 pMarkAccess
->deleteMark(pMarkAccess
->getMarksBegin()+n
);
825 pDoc
->DoUndo( bDoesUndo
);
829 // sicher eine vollstaendige Section im Undo-Nodes-Array
831 SwUndoSaveSection::SwUndoSaveSection()
832 : pMvStt( 0 ), pRedlSaveData( 0 ), nMvLen( 0 ), nStartPos( ULONG_MAX
)
836 SwUndoSaveSection::~SwUndoSaveSection()
838 if( pMvStt
) // loesche noch den Bereich aus dem UndoNodes Array
840 // SaveSection speichert den Inhalt in der PostIt-Section
841 SwNodes
& rUNds
= pMvStt
->GetNode().GetNodes();
842 rUNds
.Delete( *pMvStt
, nMvLen
);
846 delete pRedlSaveData
;
849 void SwUndoSaveSection::SaveSection( SwDoc
* pDoc
, const SwNodeIndex
& rSttIdx
)
851 SwNodeRange
aRg( rSttIdx
.GetNode(), *rSttIdx
.GetNode().EndOfSectionNode() );
852 SaveSection( pDoc
, aRg
);
856 void SwUndoSaveSection::SaveSection( SwDoc
* , const SwNodeRange
& rRange
)
858 SwPaM
aPam( rRange
.aStart
, rRange
.aEnd
);
860 // loesche alle Fussnoten / FlyFrames / Bookmarks / Verzeichnisse
861 DelCntntIndex( *aPam
.GetMark(), *aPam
.GetPoint() );
863 pRedlSaveData
= new SwRedlineSaveDatas
;
864 if( !SwUndo::FillSaveData( aPam
, *pRedlSaveData
, TRUE
, TRUE
))
865 delete pRedlSaveData
, pRedlSaveData
= 0;
867 nStartPos
= rRange
.aStart
.GetIndex();
869 aPam
.GetPoint()->nNode
--;
870 aPam
.GetMark()->nNode
++;
872 SwCntntNode
* pCNd
= aPam
.GetCntntNode( FALSE
);
874 aPam
.GetMark()->nContent
.Assign( pCNd
, 0 );
875 if( 0 != ( pCNd
= aPam
.GetCntntNode( TRUE
)) )
876 aPam
.GetPoint()->nContent
.Assign( pCNd
, pCNd
->Len() );
878 // Positionen als SwIndex merken, damit im DTOR dieser Bereich
879 // entfernt werden kann !!
881 pMvStt
= new SwNodeIndex( rRange
.aStart
);
882 MoveToUndoNds( aPam
, pMvStt
, 0, &nEnd
, 0 );
883 nMvLen
= nEnd
- pMvStt
->GetIndex() + 1;
886 void SwUndoSaveSection::RestoreSection( SwDoc
* pDoc
, SwNodeIndex
* pIdx
,
889 if( ULONG_MAX
!= nStartPos
) // gab es ueberhaupt Inhalt ?
891 // ueberpruefe, ob der Inhalt an der alten Position steht
892 SwNodeIndex
aSttIdx( pDoc
->GetNodes(), nStartPos
);
893 ASSERT( !pDoc
->GetNodes()[ aSttIdx
]->GetCntntNode(),
894 "Position in irgendeiner Section" );
896 // move den Inhalt aus dem UndoNodes-Array in den Fly
897 SwStartNode
* pSttNd
= pDoc
->GetNodes().MakeEmptySection( aSttIdx
,
898 (SwStartNodeType
)nSectType
);
900 RestoreSection( pDoc
, SwNodeIndex( *pSttNd
->EndOfSectionNode() ));
907 void SwUndoSaveSection::RestoreSection( SwDoc
* pDoc
, const SwNodeIndex
& rInsPos
)
909 if( ULONG_MAX
!= nStartPos
) // gab es ueberhaupt Inhalt ?
911 SwPosition
aInsPos( rInsPos
);
912 ULONG nEnd
= pMvStt
->GetIndex() + nMvLen
- 1;
913 MoveFromUndoNds( *pDoc
, pMvStt
->GetIndex(), 0, aInsPos
, &nEnd
, 0 );
915 // Indizies wieder zerstoren, Inhalt ist aus dem UndoNodes-Array
922 SwUndo::SetSaveData( *pDoc
, *pRedlSaveData
);
923 delete pRedlSaveData
, pRedlSaveData
= 0;
929 SwUndoStart::SwUndoStart( SwUndoId nInitId
)
930 : SwUndo( UNDO_START
), nUserId( nInitId
), nEndOffset( 0 )
934 void SwUndoStart::Undo( SwUndoIter
& rUndoIter
)
936 if( !( --rUndoIter
.nEndCnt
) && rUndoIter
.bWeiter
&&
937 ( rUndoIter
.GetId() ? ( rUndoIter
.GetId() == nUserId
||
938 ( UNDO_END
== rUndoIter
.GetId() && UNDO_START
== GetId() )) : TRUE
))
939 rUndoIter
.bWeiter
= FALSE
;
942 void SwUndoStart::Redo( SwUndoIter
& rUndoIter
)
944 rUndoIter
.bWeiter
= TRUE
;
948 void SwUndoStart::Repeat( SwUndoIter
& rUndoIter
)
950 rUndoIter
.bWeiter
= FALSE
;
953 String
SwUndoStart::GetComment() const
961 sResult
= String("??", RTL_TEXTENCODING_ASCII_US
);
966 sResult
= String(SW_RES(UNDO_BASE
+ nUserId
));
967 sResult
= GetRewriter().Apply(sResult
);
973 SwRewriter
SwUndoStart::GetRewriter() const
978 SwUndoId
SwUndoStart::GetEffectiveId() const
983 void SwUndoStart::SetRewriter(const SwRewriter
& rRewriter
)
985 mRewriter
= rRewriter
;
989 SwUndoEnd::SwUndoEnd( SwUndoId nInitId
)
990 : SwUndo( UNDO_END
), nUserId( nInitId
), nSttOffset( 0 )
994 void SwUndoEnd::Undo( SwUndoIter
& rUndoIter
)
996 if( rUndoIter
.GetId() == GetId() || !rUndoIter
.GetId() )
997 rUndoIter
.bWeiter
= TRUE
;
998 if( rUndoIter
.bWeiter
)
1002 void SwUndoEnd::Redo( SwUndoIter
& rUndoIter
)
1004 if( !( --rUndoIter
.nEndCnt
) && rUndoIter
.bWeiter
&&
1005 ( rUndoIter
.GetId() ? ( rUndoIter
.GetId() == nUserId
||
1006 ( UNDO_END
== rUndoIter
.GetId() && UNDO_START
== GetId() )) : TRUE
))
1007 rUndoIter
.bWeiter
= FALSE
;
1010 void SwUndoEnd::Repeat( SwUndoIter
& rUndoIter
)
1012 rUndoIter
.bWeiter
= FALSE
;
1015 String
SwUndoEnd::GetComment() const
1023 sResult
= String("??", RTL_TEXTENCODING_ASCII_US
);
1027 sResult
= SW_RES(UNDO_BASE
+ nUserId
);
1028 sResult
= GetRewriter().Apply(sResult
);
1034 void SwUndoEnd::SetRewriter(const SwRewriter
& rRewriter
)
1036 mRewriter
= rRewriter
;
1039 SwUndoId
SwUndoEnd::GetEffectiveId() const
1044 SwRewriter
SwUndoEnd::GetRewriter() const
1050 // sicher und setze die RedlineDaten
1052 SwRedlineSaveData::SwRedlineSaveData( SwComparePosition eCmpPos
,
1053 const SwPosition
& rSttPos
,
1054 const SwPosition
& rEndPos
,
1057 : SwUndRng( rRedl
),
1058 SwRedlineData( rRedl
.GetRedlineData(), bCopyNext
)
1060 ASSERT( POS_OUTSIDE
== eCmpPos
||
1061 !rRedl
.GetContentIdx(), "Redline mit Content" );
1065 case POS_OVERLAP_BEFORE
: // Pos1 ueberlappt Pos2 am Anfang
1066 nEndNode
= rEndPos
.nNode
.GetIndex();
1067 nEndCntnt
= rEndPos
.nContent
.GetIndex();
1069 case POS_OVERLAP_BEHIND
: // Pos1 ueberlappt Pos2 am Ende
1070 nSttNode
= rSttPos
.nNode
.GetIndex();
1071 nSttCntnt
= rSttPos
.nContent
.GetIndex();
1074 case POS_INSIDE
: // Pos1 liegt vollstaendig in Pos2
1075 nSttNode
= rSttPos
.nNode
.GetIndex();
1076 nSttCntnt
= rSttPos
.nContent
.GetIndex();
1077 nEndNode
= rEndPos
.nNode
.GetIndex();
1078 nEndCntnt
= rEndPos
.nContent
.GetIndex();
1081 case POS_OUTSIDE
: // Pos2 liegt vollstaendig in Pos1
1082 if( rRedl
.GetContentIdx() )
1084 // dann den Bereich ins UndoArray verschieben und merken
1085 SaveSection( rRedl
.GetDoc(), *rRedl
.GetContentIdx() );
1086 rRedl
.SetContentIdx( 0 );
1090 case POS_EQUAL
: // Pos1 ist genauso gross wie Pos2
1094 ASSERT( !this, "keine gueltigen Daten!" )
1098 nRedlineCount
= rSttPos
.nNode
.GetNode().GetDoc()->GetRedlineTbl().Count();
1102 SwRedlineSaveData::~SwRedlineSaveData()
1106 void SwRedlineSaveData::RedlineToDoc( SwPaM
& rPam
)
1108 SwDoc
& rDoc
= *rPam
.GetDoc();
1109 SwRedline
* pRedl
= new SwRedline( *this, rPam
);
1113 SwNodeIndex
aIdx( rDoc
.GetNodes() );
1114 RestoreSection( &rDoc
, &aIdx
, SwNormalStartNode
);
1116 GetHistory()->Rollback( &rDoc
);
1117 pRedl
->SetContentIdx( &aIdx
);
1120 // erstmal die "alten" entfernen, damit im Append keine unerwarteten
1121 // Dinge passieren, wie z.B. eine Delete in eigenen Insert. Dann wird
1122 // naehmlich das gerade restaurierte wieder geloescht - nicht das gewollte
1123 rDoc
.DeleteRedline( *pRedl
, false, USHRT_MAX
);
1125 RedlineMode_t eOld
= rDoc
.GetRedlineMode();
1126 rDoc
.SetRedlineMode_intern((RedlineMode_t
)(eOld
| nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES
));
1127 //#i92154# let UI know about a new redline with comment
1128 if (rDoc
.GetDocShell() && (pRedl
->GetComment() != String(::rtl::OUString::createFromAscii(""))) )
1129 rDoc
.GetDocShell()->Broadcast(SwRedlineHint(pRedl
,SWREDLINE_INSERTED
));
1131 rDoc
.AppendRedline( pRedl
, true );
1132 rDoc
.SetRedlineMode_intern( eOld
);
1135 BOOL
SwUndo::FillSaveData( const SwPaM
& rRange
, SwRedlineSaveDatas
& rSData
,
1136 BOOL bDelRange
, BOOL bCopyNext
)
1138 if( rSData
.Count() )
1139 rSData
.DeleteAndDestroy( 0, rSData
.Count() );
1141 SwRedlineSaveData
* pNewData
;
1142 const SwPosition
*pStt
= rRange
.Start(), *pEnd
= rRange
.End();
1143 const SwRedlineTbl
& rTbl
= rRange
.GetDoc()->GetRedlineTbl();
1145 rRange
.GetDoc()->GetRedline( *pStt
, &n
);
1146 for( ; n
< rTbl
.Count(); ++n
)
1148 SwRedline
* pRedl
= rTbl
[ n
];
1149 const SwPosition
*pRStt
= pRedl
->Start(), *pREnd
= pRedl
->End();
1151 SwComparePosition eCmpPos
= ComparePosition( *pStt
, *pEnd
, *pRStt
, *pREnd
);
1152 if( POS_BEFORE
!= eCmpPos
&& POS_BEHIND
!= eCmpPos
&&
1153 POS_COLLIDE_END
!= eCmpPos
&& POS_COLLIDE_START
!= eCmpPos
)
1155 pNewData
= new SwRedlineSaveData( eCmpPos
, *pStt
, *pEnd
,
1156 *pRedl
, bCopyNext
);
1157 rSData
.Insert( pNewData
, rSData
.Count() );
1160 if( rSData
.Count() && bDelRange
)
1161 rRange
.GetDoc()->DeleteRedline( rRange
, false, USHRT_MAX
);
1162 return 0 != rSData
.Count();
1165 BOOL
SwUndo::FillSaveDataForFmt( const SwPaM
& rRange
, SwRedlineSaveDatas
& rSData
)
1167 if( rSData
.Count() )
1168 rSData
.DeleteAndDestroy( 0, rSData
.Count() );
1170 SwRedlineSaveData
* pNewData
;
1171 const SwPosition
*pStt
= rRange
.Start(), *pEnd
= rRange
.End();
1172 const SwRedlineTbl
& rTbl
= rRange
.GetDoc()->GetRedlineTbl();
1174 rRange
.GetDoc()->GetRedline( *pStt
, &n
);
1175 for( ; n
< rTbl
.Count(); ++n
)
1177 SwRedline
* pRedl
= rTbl
[ n
];
1178 if( nsRedlineType_t::REDLINE_FORMAT
== pRedl
->GetType() )
1180 const SwPosition
*pRStt
= pRedl
->Start(), *pREnd
= pRedl
->End();
1182 SwComparePosition eCmpPos
= ComparePosition( *pStt
, *pEnd
, *pRStt
, *pREnd
);
1183 if( POS_BEFORE
!= eCmpPos
&& POS_BEHIND
!= eCmpPos
&&
1184 POS_COLLIDE_END
!= eCmpPos
&& POS_COLLIDE_START
!= eCmpPos
)
1186 pNewData
= new SwRedlineSaveData( eCmpPos
, *pStt
, *pEnd
,
1188 rSData
.Insert( pNewData
, rSData
.Count() );
1194 return 0 != rSData
.Count();
1197 void SwUndo::SetSaveData( SwDoc
& rDoc
, const SwRedlineSaveDatas
& rSData
)
1199 RedlineMode_t eOld
= rDoc
.GetRedlineMode();
1200 rDoc
.SetRedlineMode_intern( (RedlineMode_t
)(( eOld
& ~nsRedlineMode_t::REDLINE_IGNORE
) | nsRedlineMode_t::REDLINE_ON
));
1201 SwPaM
aPam( rDoc
.GetNodes().GetEndOfContent() );
1203 for( USHORT n
= rSData
.Count(); n
; )
1204 rSData
[ --n
]->RedlineToDoc( aPam
);
1206 // check redline count against count saved in RedlineSaveData object
1207 DBG_ASSERT( (rSData
.Count() == 0) ||
1208 (rSData
[0]->nRedlineCount
== rDoc
.GetRedlineTbl().Count()),
1209 "redline count not restored properly" );
1211 rDoc
.SetRedlineMode_intern( eOld
);
1214 BOOL
SwUndo::HasHiddenRedlines( const SwRedlineSaveDatas
& rSData
)
1216 for( USHORT n
= rSData
.Count(); n
; )
1217 if( rSData
[ --n
]->GetMvSttIdx() )
1222 BOOL
SwUndo::CanRedlineGroup( SwRedlineSaveDatas
& rCurr
,
1223 const SwRedlineSaveDatas
& rCheck
, BOOL bCurrIsEnd
)
1228 if( rCurr
.Count() == rCheck
.Count() )
1231 for( n
= 0; n
< rCurr
.Count(); ++n
)
1233 const SwRedlineSaveData
& rSet
= *rCurr
[ n
];
1234 const SwRedlineSaveData
& rGet
= *rCheck
[ n
];
1235 if( rSet
.nSttNode
!= rGet
.nSttNode
||
1236 rSet
.GetMvSttIdx() || rGet
.GetMvSttIdx() ||
1237 ( bCurrIsEnd
? rSet
.nSttCntnt
!= rGet
.nEndCntnt
1238 : rSet
.nEndCntnt
!= rGet
.nSttCntnt
) ||
1239 !rGet
.CanCombine( rSet
) )
1247 for( n
= 0; n
< rCurr
.Count(); ++n
)
1249 SwRedlineSaveData
& rSet
= *rCurr
[ n
];
1250 const SwRedlineSaveData
& rGet
= *rCheck
[ n
];
1252 rSet
.nSttCntnt
= rGet
.nSttCntnt
;
1254 rSet
.nEndCntnt
= rGet
.nEndCntnt
;
1261 String
ShortenString(const String
& rStr
, xub_StrLen nLength
, const String
& rFillStr
)
1263 ASSERT( nLength
- rFillStr
.Len() >= 2, "improper arguments")
1267 if (rStr
.Len() <= nLength
)
1271 long nTmpLength
= nLength
- rFillStr
.Len();
1272 if ( nTmpLength
< 2 )
1275 nLength
= static_cast<xub_StrLen
>(nTmpLength
);
1277 const xub_StrLen nFrontLen
= nLength
- nLength
/ 2;
1278 const xub_StrLen nBackLen
= nLength
- nFrontLen
;
1280 aResult
+= rStr
.Copy(0, nFrontLen
);
1281 aResult
+= rFillStr
;
1282 aResult
+= rStr
.Copy(rStr
.Len() - nBackLen
, nBackLen
);
1288 static bool lcl_IsSpecialCharacter(sal_Unicode nChar
)
1292 case CH_TXTATR_BREAKWORD
:
1293 case CH_TXTATR_INWORD
:
1295 case CH_TXTATR_NEWLINE
:
1305 static String
lcl_DenotedPortion(String rStr
, xub_StrLen nStart
,
1310 if (nEnd
- nStart
> 0)
1312 sal_Unicode cLast
= rStr
.GetChar(nEnd
- 1);
1313 if (lcl_IsSpecialCharacter(cLast
))
1318 aResult
+= String(SW_RES(STR_UNDO_TABS
));
1321 case CH_TXTATR_NEWLINE
:
1322 aResult
+= String(SW_RES(STR_UNDO_NLS
));
1326 case CH_TXTATR_INWORD
:
1327 case CH_TXTATR_BREAKWORD
:
1328 aResult
+= UNDO_ARG2
;
1333 SwRewriter aRewriter
;
1334 aRewriter
.AddRule(UNDO_ARG1
,
1335 String::CreateFromInt32(nEnd
- nStart
));
1336 aResult
= aRewriter
.Apply(aResult
);
1340 aResult
= String(SW_RES(STR_START_QUOTE
));
1341 aResult
+= rStr
.Copy(nStart
, nEnd
- nStart
);
1342 aResult
+= String(SW_RES(STR_END_QUOTE
));
1349 String
DenoteSpecialCharacters(const String
& rStr
)
1355 bool bStart
= false;
1356 xub_StrLen nStart
= 0;
1357 sal_Unicode cLast
= 0;
1359 for (xub_StrLen i
= 0; i
< rStr
.Len(); i
++)
1361 if (lcl_IsSpecialCharacter(rStr
.GetChar(i
)))
1363 if (cLast
!= rStr
.GetChar(i
))
1369 if (lcl_IsSpecialCharacter(cLast
))
1375 aResult
+= lcl_DenotedPortion(rStr
, nStart
, i
);
1381 cLast
= rStr
.GetChar(i
);
1384 aResult
+= lcl_DenotedPortion(rStr
, nStart
, rStr
.Len());
1387 aResult
= UNDO_ARG2
;