Update ooo320-m1
[ooovba.git] / sw / source / core / undo / docundo.cxx
blob0d7e260be17fa68320e3e19e8fdb16f73b24d4df
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: docundo.cxx,v $
10 * $Revision: 1.26 $
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"
34 #include <svx/svdmodel.hxx>
36 #include <vcl/wrkwin.hxx>
37 #include <doc.hxx>
38 #include <pam.hxx>
39 #include <ndtxt.hxx>
40 #include <swundo.hxx> // fuer die UndoIds
41 #include <undobj.hxx>
42 #include <rolbck.hxx>
43 #include <docary.hxx>
44 #ifndef _UNDO_HRC
45 #include <undo.hrc>
46 #endif
49 using namespace ::com::sun::star;
52 USHORT SwDoc::nUndoActions = UNDO_ACTION_COUNT; // anzahl von Undo-Action
54 // the undo array should never grow beyond this limit:
55 #define UNDO_ACTION_LIMIT (USHRT_MAX - 1000)
58 SV_IMPL_PTRARR( SwUndoIds, SwUndoIdAndNamePtr )
60 //#define _SHOW_UNDORANGE
61 #ifdef _SHOW_UNDORANGE
64 class UndoArrStatus : public WorkWindow
66 USHORT nUndo, nUndoNds;
67 virtual void Paint( const Rectangle& );
68 public:
69 UndoArrStatus();
70 void Set( USHORT, USHORT );
72 static UndoArrStatus* pUndoMsgWin = 0;
75 UndoArrStatus::UndoArrStatus()
76 : WorkWindow( APP_GETAPPWINDOW() ), nUndo(0), nUndoNds(0)
78 SetSizePixel( Size( 200, 100 ));
79 SetFont( Font( "Courier", Size( 0, 10 )) );
80 Show();
84 void UndoArrStatus::Set( USHORT n1, USHORT n2 )
86 nUndo = n1; nUndoNds = n2;
87 Invalidate();
91 void UndoArrStatus::Paint( const Rectangle& )
93 String s;
94 DrawRect( Rectangle( Point(0,0), GetOutputSize() ));
95 ( s = "Undos: " ) += nUndo;
96 DrawText( Point( 0, 0 ), s );
97 ( s = "UndoNodes: " ) += nUndoNds;
98 DrawText( Point( 0, 15 ), s );
101 #endif
103 void SwDoc::SetUndoNoResetModified()
105 nUndoSavePos = USHRT_MAX;
108 bool SwDoc::IsUndoNoResetModified() const
110 return USHRT_MAX == nUndoSavePos;
113 void SwDoc::DoUndo(bool bUn)
115 mbUndo = bUn;
117 SdrModel* pSdrModel = GetDrawModel();
118 if( pSdrModel )
119 pSdrModel->EnableUndo(bUn);
122 bool SwDoc::DoesUndo() const
124 return mbUndo;
127 void SwDoc::DoGroupUndo(bool bUn)
129 mbGroupUndo = bUn;
132 bool SwDoc::DoesGroupUndo() const
134 return mbGroupUndo;
137 sal_uInt16 SwDoc::GetUndoActionCount()
139 return nUndoActions;
142 void SwDoc::SetUndoActionCount( sal_uInt16 nNew )
144 nUndoActions = nNew;
147 const SwNodes* SwDoc::GetUndoNds() const
149 return &aUndoNodes;
152 void SwDoc::AppendUndo( SwUndo* pUndo )
154 if( nsRedlineMode_t::REDLINE_NONE == pUndo->GetRedlineMode() )
155 pUndo->SetRedlineMode( GetRedlineMode() );
157 // Unfortunately, the silly SvPtrArr can only store a little less than
158 // USHRT_MAX elements. Of course it doesn't see any necessity for asserting
159 // or even doing error handling. pUndos should definitely be replaced by an
160 // STL container that doesn't have this problem. cf #95884#
161 DBG_ASSERT( pUndos->Count() < USHRT_MAX - 16,
162 "Writer will crash soon. I apologize for the inconvenience." );
164 pUndos->Insert( pUndo, nUndoPos );
165 ++nUndoPos;
166 switch( pUndo->GetId() )
168 case UNDO_START: ++nUndoSttEnd;
169 break;
171 case UNDO_END: ASSERT( nUndoSttEnd, "Undo-Ende ohne Start" );
172 --nUndoSttEnd;
173 // kein break !!!
174 default:
175 if( pUndos->Count() != nUndoPos && UNDO_END != pUndo->GetId() )
176 ClearRedo();
177 else {
178 ASSERT( pUndos->Count() == nUndoPos || UNDO_END == pUndo->GetId(),
179 "Redo history not deleted!" );
181 if( !nUndoSttEnd )
182 ++nUndoCnt;
183 break;
186 #ifdef _SHOW_UNDORANGE
187 // zur Anzeige der aktuellen Undo-Groessen
188 if( !pUndoMsgWin )
189 pUndoMsgWin = new UndoArrStatus;
190 pUndoMsgWin->Set( pUndos->Count(), aUndoNodes.Count() );
191 #endif
193 // noch eine offene Klammerung, kann man sich den Rest schenken
194 if( nUndoSttEnd )
195 return;
197 // folgende Array-Grenzen muessen ueberwacht werden:
198 // - Undo, Grenze: fester Wert oder USHRT_MAX - 1000
199 // - UndoNodes, Grenze: USHRT_MAX - 1000
200 // - AttrHistory Grenze: USHRT_MAX - 1000
201 // (defined in UNDO_ACTION_LIMIT at the top of this file)
203 USHORT nEnde = UNDO_ACTION_LIMIT;
205 // nur zum Testen der neuen DOC-Member
206 #ifndef PRODUCT
208 SwUndoId nId = UNDO_EMPTY;
209 USHORT nUndosCnt = 0, nSttEndCnt = 0;
210 for( USHORT nCnt = 0; nCnt < nUndoPos; ++nCnt )
212 if( UNDO_START == ( nId = (*pUndos)[ nCnt ]->GetId()) )
213 ++nSttEndCnt;
214 else if( UNDO_END == nId )
215 --nSttEndCnt;
216 if( !nSttEndCnt )
217 ++nUndosCnt;
219 ASSERT( nSttEndCnt == nUndoSttEnd, "Start-Ende Count ungleich" );
220 ASSERT( nUndosCnt == nUndoCnt, "Undo Count ungleich" );
222 #endif
224 if( SwDoc::nUndoActions < nUndoCnt )
225 // immer 1/10 loeschen
226 //JP 23.09.95: oder wenn neu eingestellt wurde um die Differenz
227 //JP 29.5.2001: Task #83891#: remove only the overlapping actions
228 DelUndoObj( nUndoCnt - SwDoc::nUndoActions );
229 else
231 USHORT nUndosCnt = nUndoCnt;
232 // immer 1/10 loeschen bis der "Ausloeser" behoben ist
233 while( aUndoNodes.Count() && nEnde < aUndoNodes.Count() )
234 DelUndoObj( nUndosCnt / 10 );
240 void SwDoc::ClearRedo()
242 if( DoesUndo() && nUndoPos != pUndos->Count() )
244 //?? why ?? if( !nUndoSttEnd )
246 // setze UndoCnt auf den neuen Wert
247 SwUndo* pUndo;
248 for( USHORT nCnt = pUndos->Count(); nUndoPos < nCnt; --nUndoCnt )
249 // Klammerung ueberspringen
250 if( UNDO_END == (pUndo = (*pUndos)[ --nCnt ])->GetId() )
251 nCnt = nCnt - ((SwUndoEnd*)pUndo)->GetSttOffset();
254 // loesche die Undo-Aktionen (immer von hinten !)
255 pUndos->DeleteAndDestroy( nUndoPos, pUndos->Count() - nUndoPos );
260 // loescht die gesamten UndoObjecte
261 void SwDoc::DelAllUndoObj()
263 ClearRedo();
265 DoUndo( FALSE );
267 // Offene Undo-Klammerungen erhalten !!
268 SwUndo* pUndo;
269 USHORT nSize = pUndos->Count();
270 while( nSize )
271 if( UNDO_START != ( pUndo = (*pUndos)[ --nSize ] )->GetId() ||
272 ((SwUndoStart*)pUndo)->GetEndOffset() )
273 // keine offenen Gruppierung ?
274 pUndos->DeleteAndDestroy( nSize, 1 );
276 nUndoCnt = 0;
277 nUndoPos = pUndos->Count();
280 while( nUndoPos )
281 aUndos.DelDtor( --nUndoPos, 1 );
282 nUndoCnt = nUndoSttEnd = nUndoPos = 0;
284 nUndoSavePos = USHRT_MAX;
285 DoUndo( TRUE );
289 // loescht alle UndoObjecte vom Anfang bis zum angegebenen Ende
290 BOOL SwDoc::DelUndoObj( USHORT nEnde )
292 if( !nEnde ) // sollte mal 0 uebergeben werden,
294 if( !pUndos->Count() )
295 return FALSE;
296 ++nEnde; // dann korrigiere es auf 1
299 DoUndo( FALSE );
301 // pruefe erstmal, wo das Ende steht
302 SwUndoId nId = UNDO_EMPTY;
303 USHORT nSttEndCnt = 0;
304 USHORT nCnt;
306 for( nCnt = 0; nEnde && nCnt < nUndoPos; ++nCnt )
308 if( UNDO_START == ( nId = (*pUndos)[ nCnt ]->GetId() ))
309 ++nSttEndCnt;
310 else if( UNDO_END == nId )
311 --nSttEndCnt;
312 if( !nSttEndCnt )
313 --nEnde, --nUndoCnt;
316 ASSERT( nCnt < nUndoPos || nUndoPos == pUndos->Count(),
317 "Undo-Del-Ende liegt in einer Redo-Aktion" );
319 // dann setze ab Ende bis Undo-Ende bei allen Undo-Objecte die Werte um
320 nSttEndCnt = nCnt; // Position merken
321 if( nUndoSavePos < nSttEndCnt ) // SavePos wird aufgegeben
322 nUndoSavePos = USHRT_MAX;
323 else if( nUndoSavePos != USHRT_MAX )
324 nUndoSavePos = nUndoSavePos - nSttEndCnt;
326 while( nSttEndCnt )
327 pUndos->DeleteAndDestroy( --nSttEndCnt, 1 );
328 nUndoPos = pUndos->Count();
330 DoUndo( TRUE );
331 return TRUE;
334 /**************** UNDO ******************/
336 void SwDoc::setUndoNoModifiedPosition( SwUndoNoModifiedPosition nNew )
338 nUndoSavePos = nNew;
339 if( !pUndos->Count() || nUndoSavePos > pUndos->Count() - 1 )
340 nUndoSavePos = USHRT_MAX;
343 SwUndoNoModifiedPosition SwDoc::getUndoNoModifiedPosition() const
345 return nUndoSavePos;
349 bool SwDoc::HasUndoId(SwUndoId eId) const
351 USHORT nSize = nUndoPos;
352 SwUndo * pUndo;
353 while( nSize-- )
354 if( ( pUndo = (*pUndos)[nSize])->GetId() == eId ||
355 ( UNDO_START == pUndo->GetId() &&
356 ((SwUndoStart*)pUndo)->GetUserId() == eId )
357 || ( UNDO_END == pUndo->GetId() &&
358 ((SwUndoEnd*)pUndo)->GetUserId() == eId ) )
360 return TRUE;
363 return FALSE;
367 bool SwDoc::Undo( SwUndoIter& rUndoIter )
369 if ( (rUndoIter.GetId()!=0) && (!HasUndoId(rUndoIter.GetId())) )
371 rUndoIter.bWeiter = FALSE;
372 return FALSE;
374 if( !nUndoPos )
376 rUndoIter.bWeiter = FALSE;
377 return FALSE;
380 SwUndo *pUndo = (*pUndos)[ --nUndoPos ];
382 RedlineMode_t eOld = GetRedlineMode();
383 RedlineMode_t eTmpMode = (RedlineMode_t)pUndo->GetRedlineMode();
384 if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eOld) &&
385 UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() )
386 SetRedlineMode( eTmpMode );
388 SetRedlineMode_intern((RedlineMode_t)(eTmpMode | nsRedlineMode_t::REDLINE_IGNORE));
389 // Undo ausfuehren
391 // zum spaeteren ueberpruefen
392 SwUndoId nAktId = pUndo->GetId();
393 //JP 11.05.98: FlyFormate ueber die EditShell selektieren, nicht aus dem
394 // Undo heraus
395 switch( nAktId )
397 case UNDO_START:
398 case UNDO_END:
399 case UNDO_INSDRAWFMT:
400 break;
402 default:
403 rUndoIter.ClearSelections();
406 pUndo->Undo( rUndoIter );
408 SetRedlineMode( eOld );
410 // Besonderheit von Undo-Replace (interne History)
411 if( UNDO_REPLACE == nAktId && ((SwUndoReplace*)pUndo)->nAktPos )
413 ++nUndoPos;
414 return TRUE;
417 // Objekt aus History entfernen und zerstoeren
418 if( nUndoPos && !rUndoIter.bWeiter &&
419 UNDO_START == ( pUndo = (*pUndos)[ nUndoPos-1 ] )->GetId() )
420 --nUndoPos;
422 // JP 29.10.96: Start und End setzen kein Modify-Flag.
423 // Sonst gibt es Probleme mit der autom. Aufnahme von Ausnahmen
424 // bei der Autokorrektur
425 if( UNDO_START != nAktId && UNDO_END != nAktId )
426 SetModified(); // default: immer setzen, kann zurueck gesetzt werden
428 // ist die History leer und wurde nicht wegen Speichermangel
429 // verworfen, so kann das Dokument als unveraendert gelten
430 if( nUndoSavePos == nUndoPos )
431 ResetModified();
433 return TRUE;
437 // setzt Undoklammerung auf, liefert nUndoId der Klammerung
440 SwUndoId SwDoc::StartUndo( SwUndoId eUndoId, const SwRewriter * pRewriter )
442 if( !mbUndo )
443 return UNDO_EMPTY;
445 if( !eUndoId )
446 eUndoId = UNDO_START;
448 SwUndoStart * pUndo = new SwUndoStart( eUndoId );
450 if (pRewriter)
451 pUndo->SetRewriter(*pRewriter);
453 AppendUndo(pUndo);
455 return eUndoId;
457 // schliesst Klammerung der nUndoId, nicht vom UI benutzt
460 SwUndoId SwDoc::EndUndo(SwUndoId eUndoId, const SwRewriter * pRewriter)
462 USHORT nSize = nUndoPos;
463 if( !mbUndo || !nSize-- )
464 return UNDO_EMPTY;
466 if( UNDO_START == eUndoId || !eUndoId )
467 eUndoId = UNDO_END;
469 SwUndo* pUndo = (*pUndos)[ nSize ];
470 if( UNDO_START == pUndo->GetId() )
472 // leere Start/End-Klammerung ??
473 pUndos->DeleteAndDestroy( nSize );
474 --nUndoPos;
475 --nUndoSttEnd;
476 return UNDO_EMPTY;
479 // exist above any redo objects? If yes, delete them
480 if( nUndoPos != pUndos->Count() )
482 // setze UndoCnt auf den neuen Wert
483 for( USHORT nCnt = pUndos->Count(); nUndoPos < nCnt; --nUndoCnt )
484 // Klammerung ueberspringen
485 if( UNDO_END == (pUndo = (*pUndos)[ --nCnt ])->GetId() )
486 nCnt = nCnt - ((SwUndoEnd*)pUndo)->GetSttOffset();
488 pUndos->DeleteAndDestroy( nUndoPos, pUndos->Count() - nUndoPos );
491 // suche den Anfang dieser Klammerung
492 SwUndoId nId = UNDO_EMPTY;
493 while( nSize )
494 if( UNDO_START == ( nId = (pUndo = (*pUndos)[ --nSize ] )->GetId()) &&
495 !((SwUndoStart*)pUndo)->GetEndOffset() )
496 break; // Start gefunden
498 if( nId != UNDO_START )
500 // kann eigentlich nur beim Abspielen von Macros passieren, die
501 // Undo/Redo/Repeat benutzen und die eine exitierende Selection
502 // durch Einfuegen loeschen
503 ASSERT( !this, "kein entsprechendes Ende gefunden" );
504 // kein entsprechenden Start gefunden -> Ende nicht einfuegen
505 // und die Member am Doc updaten
507 nUndoSttEnd = 0;
508 nUndoCnt = 0;
509 // setze UndoCnt auf den neuen Wert
510 SwUndo* pTmpUndo;
511 for( USHORT nCnt = 0; nCnt < pUndos->Count(); ++nCnt, ++nUndoCnt )
512 // Klammerung ueberspringen
513 if( UNDO_START == (pTmpUndo = (*pUndos)[ nCnt ])->GetId() )
514 nCnt = nCnt + ((SwUndoStart*)pTmpUndo)->GetEndOffset();
515 return UNDO_EMPTY;
519 // Klammerung um eine einzelne Action muss nicht sein!
520 // Aussnahme: es ist eine eigene ID definiert
521 if( 2 == pUndos->Count() - nSize &&
522 (UNDO_END == eUndoId || eUndoId == (*pUndos)[ nSize+1 ]->GetId() ))
524 pUndos->DeleteAndDestroy( nSize );
525 nUndoPos = pUndos->Count();
526 if( !--nUndoSttEnd )
528 ++nUndoCnt;
529 if( SwDoc::nUndoActions < nUndoCnt )
530 // immer 1/10 loeschen
531 //JP 23.09.95: oder wenn neu eingestellt wurde um die Differenz
532 //JP 29.5.2001: Task #83891#: remove only the overlapping actions
533 DelUndoObj( nUndoCnt - SwDoc::nUndoActions );
534 else
536 USHORT nEnde = USHRT_MAX - 1000;
537 USHORT nUndosCnt = nUndoCnt;
538 // immer 1/10 loeschen bis der "Ausloeser" behoben ist
539 while( aUndoNodes.Count() && nEnde < aUndoNodes.Count() )
540 DelUndoObj( nUndosCnt / 10 );
543 return eUndoId;
546 // setze die Klammerung am Start/End-Undo
547 nSize = pUndos->Count() - nSize;
548 ((SwUndoStart*)pUndo)->SetEndOffset( nSize );
550 SwUndoEnd* pUndoEnd = new SwUndoEnd( eUndoId );
551 pUndoEnd->SetSttOffset( nSize );
553 // nur zum Testen der Start/End-Verpointerung vom Start/End Undo
554 #ifndef PRODUCT
556 USHORT nEndCnt = 1, nCnt = pUndos->Count();
557 SwUndoId nTmpId = UNDO_EMPTY;
558 while( nCnt )
560 if( UNDO_START == ( nTmpId = (*pUndos)[ --nCnt ]->GetId()) )
562 if( !nEndCnt ) // falls mal ein Start ohne Ende vorhanden ist
563 continue;
564 --nEndCnt;
565 if( !nEndCnt ) // hier ist der Anfang
566 break;
568 else if( UNDO_END == nTmpId )
569 ++nEndCnt;
570 else if( !nEndCnt )
571 break;
573 ASSERT( nCnt == pUndos->Count() - nSize,
574 "Start-Ende falsch geklammert" );
576 #endif
578 if (pRewriter)
580 ((SwUndoStart *) pUndo)->SetRewriter(*pRewriter);
581 pUndoEnd->SetRewriter(*pRewriter);
583 else
584 pUndoEnd->SetRewriter(((SwUndoStart *) pUndo)->GetRewriter());
586 AppendUndo( pUndoEnd );
587 return eUndoId;
590 // liefert die Id der letzten Undofaehigen Aktion zurueck oder 0
591 // fuellt ggf. VARARR mit User-UndoIds
593 String SwDoc::GetUndoIdsStr( String* pStr, SwUndoIds *pUndoIds) const
595 String aTmpStr;
597 if (pStr != NULL)
599 GetUndoIds( pStr, pUndoIds);
600 aTmpStr = *pStr;
602 else
603 GetUndoIds( &aTmpStr, pUndoIds);
605 return aTmpStr;
608 /*-- 24.11.2004 16:11:21---------------------------------------------------
610 -----------------------------------------------------------------------*/
611 sal_Bool SwDoc::RestoreInvisibleContent()
613 sal_Bool bRet = sal_False;
614 if(nUndoPos > 0 )
616 SwUndo * pUndo = (*pUndos)[ nUndoPos - 1 ];
617 if( ( pUndo->GetId() == UNDO_END &&
618 static_cast<SwUndoEnd *>(pUndo)->GetUserId() == UNDO_UI_DELETE_INVISIBLECNTNT) )
620 SwPaM aPam( GetNodes().GetEndOfPostIts() );
621 SwUndoIter aUndoIter( &aPam );
624 Undo( aUndoIter );
626 while ( aUndoIter.IsNextUndo() );
627 ClearRedo();
628 bRet = sal_True;
631 return bRet;
636 Returns id and comment for a certain undo object in an undo stack.
638 Remark: In the following the object type referred to is always the
639 effective object type. If an UNDO_START or UNDO_END has a user type
640 it is referred to as this type.
642 If the queried object is an UNDO_END and has no user id the result
643 is taken from the first object that is not an UNDO_END nor an
644 UNDO_START preceeding the queried object.
646 If the queried object is an UNDO_START and has no user id the
647 result is taken from the first object that is not an UNDO_END nor
648 an UNDO_START preceeding the UNDO_END object belonging to the
649 queried object.
651 In all other cases the result is taken from the queried object.
653 @param rUndos the undo stack
654 @param nPos position of the undo object to query
656 @return SwUndoIdAndName object containing the query result
658 SwUndoIdAndName * lcl_GetUndoIdAndName(const SwUndos & rUndos, sal_uInt16 nPos )
660 SwUndo * pUndo = rUndos[ nPos ];
661 SwUndoId nId = UNDO_EMPTY;
662 String sStr("??", RTL_TEXTENCODING_ASCII_US);
664 ASSERT( nPos < rUndos.Count(), "nPos out of range");
666 switch (pUndo->GetId())
668 case UNDO_START:
670 SwUndoStart * pUndoStart = (SwUndoStart *) pUndo;
671 nId = pUndoStart->GetUserId();
673 if (nId <= UNDO_END)
676 Start at the according UNDO_END. Search backwards
677 for first objects that is not a UNDO_END.
679 int nTmpPos = nPos + pUndoStart->GetEndOffset();
680 int nSubstitute = -1;
682 SwUndo * pTmpUndo;
685 nTmpPos--;
686 pTmpUndo = rUndos[ static_cast<USHORT>(nTmpPos) ];
688 if (pTmpUndo->GetEffectiveId() > UNDO_END)
689 nSubstitute = nTmpPos;
691 while (nSubstitute < 0 && nTmpPos > nPos);
693 if (nSubstitute >= 0)
695 SwUndo * pSubUndo = rUndos[ static_cast<USHORT>(nSubstitute) ];
696 nId = pSubUndo->GetEffectiveId();
697 sStr = pSubUndo->GetComment();
700 else
701 sStr = pUndo->GetComment();
704 break;
706 case UNDO_END:
708 SwUndoEnd * pUndoEnd = (SwUndoEnd *) pUndo;
709 nId = pUndoEnd->GetUserId();
711 if (nId <= UNDO_END)
714 Start at this UNDO_END. Search backwards
715 for first objects that is not a UNDO_END.
718 int nTmpPos = nPos;
719 int nUndoStart = nTmpPos - pUndoEnd->GetSttOffset();
720 int nSubstitute = -1;
722 if (nTmpPos > 0)
724 SwUndo * pTmpUndo;
728 nTmpPos--;
729 pTmpUndo = rUndos[ static_cast<USHORT>(nTmpPos) ];
731 if (pTmpUndo->GetEffectiveId() > UNDO_END)
732 nSubstitute = nTmpPos;
734 while (nSubstitute < 0 && nTmpPos > nUndoStart);
736 if (nSubstitute >= 0)
738 SwUndo * pSubUndo = rUndos[ static_cast<USHORT>(nSubstitute) ];
739 nId = pSubUndo->GetEffectiveId();
740 sStr = pSubUndo->GetComment();
744 else
745 sStr = pUndo->GetComment();
748 break;
750 default:
751 nId = pUndo->GetId();
752 sStr = pUndo->GetComment();
755 return new SwUndoIdAndName(nId, &sStr);
758 SwUndoId SwDoc::GetUndoIds( String* pStr, SwUndoIds *pUndoIds) const
760 int nTmpPos = nUndoPos - 1;
761 SwUndoId nId = UNDO_EMPTY;
763 while (nTmpPos >= 0)
765 SwUndo * pUndo = (*pUndos)[ static_cast<USHORT>(nTmpPos) ];
767 SwUndoIdAndName * pIdAndName = lcl_GetUndoIdAndName( *pUndos, static_cast<sal_uInt16>(nTmpPos) );
769 if (nTmpPos == nUndoPos - 1)
771 nId = pIdAndName->GetUndoId();
773 if (pStr)
774 *pStr = *pIdAndName->GetUndoStr();
777 if (pUndoIds)
778 pUndoIds->Insert(pIdAndName, pUndoIds->Count());
779 else
780 break;
782 if (pUndo->GetId() == UNDO_END)
783 nTmpPos -= ((SwUndoEnd *) pUndo)->GetSttOffset();
785 nTmpPos--;
788 return nId;
791 bool SwDoc::HasTooManyUndos() const
793 // AppendUndo checks the UNDO_ACTION_LIMIT, unless there's a nested undo.
794 // So HasTooManyUndos() may only occur when undos are nested; else
795 // AppendUndo has some sort of bug.
796 DBG_ASSERT( (nUndoSttEnd != 0) || (pUndos->Count() < UNDO_ACTION_LIMIT),
797 "non-nested undos should have been handled in AppendUndo" );
798 return (pUndos->Count() >= UNDO_ACTION_LIMIT);
802 /**************** REDO ******************/
805 bool SwDoc::Redo( SwUndoIter& rUndoIter )
807 if( rUndoIter.GetId() && !HasUndoId( rUndoIter.GetId() ) )
809 rUndoIter.bWeiter = FALSE;
810 return FALSE;
812 if( nUndoPos == pUndos->Count() )
814 rUndoIter.bWeiter = FALSE;
815 return FALSE;
818 SwUndo *pUndo = (*pUndos)[ nUndoPos++ ];
820 RedlineMode_t eOld = GetRedlineMode();
821 RedlineMode_t eTmpMode = (RedlineMode_t)pUndo->GetRedlineMode();
822 if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eOld) &&
823 UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() )
824 SetRedlineMode( eTmpMode );
825 SetRedlineMode_intern( (RedlineMode_t)(eTmpMode | nsRedlineMode_t::REDLINE_IGNORE));
827 //JP 11.05.98: FlyFormate ueber die EditShell selektieren, nicht aus dem
828 // Undo heraus
829 if( UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() )
830 rUndoIter.ClearSelections();
832 pUndo->Redo( rUndoIter );
834 SetRedlineMode( eOld );
836 // Besonderheit von Undo-Replace (interne History)
837 if( UNDO_REPLACE == pUndo->GetId() &&
838 USHRT_MAX != ((SwUndoReplace*)pUndo)->nAktPos )
840 --nUndoPos;
841 return TRUE;
844 if( rUndoIter.bWeiter && nUndoPos >= pUndos->Count() )
845 rUndoIter.bWeiter = FALSE;
847 // ist die History leer und wurde nicht wegen Speichermangel
848 // verworfen, so kann das Dokument als unveraendert gelten
849 if( nUndoSavePos == nUndoPos )
850 ResetModified();
851 else
852 SetModified();
853 return TRUE;
857 // liefert die Id der letzten Redofaehigen Aktion zurueck oder 0
858 // fuellt ggf. VARARR mit User-RedoIds
860 String SwDoc::GetRedoIdsStr( String* pStr, SwUndoIds *pRedoIds ) const
862 String aTmpStr;
864 if (pStr != NULL)
866 GetRedoIds( pStr, pRedoIds );
867 aTmpStr = *pStr;
869 else
870 GetRedoIds( &aTmpStr, pRedoIds );
873 return aTmpStr;
877 SwUndoId SwDoc::GetRedoIds( String* pStr, SwUndoIds *pRedoIds ) const
879 sal_uInt16 nTmpPos = nUndoPos;
880 SwUndoId nId = UNDO_EMPTY;
882 while (nTmpPos < pUndos->Count())
884 SwUndo * pUndo = (*pUndos)[nTmpPos];
886 SwUndoIdAndName * pIdAndName = lcl_GetUndoIdAndName(*pUndos, nTmpPos);
888 if (nTmpPos == nUndoPos)
890 nId = pIdAndName->GetUndoId();
892 if (pStr)
893 *pStr = *pIdAndName->GetUndoStr();
896 if (pRedoIds)
897 pRedoIds->Insert(pIdAndName, pRedoIds->Count());
898 else
899 break;
901 if (pUndo->GetId() == UNDO_START)
902 nTmpPos = nTmpPos + ((SwUndoStart *) pUndo)->GetEndOffset();
904 nTmpPos++;
907 return nId;
910 /**************** REPEAT ******************/
913 bool SwDoc::Repeat( SwUndoIter& rUndoIter, sal_uInt16 nRepeatCnt )
915 if( rUndoIter.GetId() && !HasUndoId( rUndoIter.GetId() ) )
917 rUndoIter.bWeiter = FALSE;
918 return FALSE;
920 USHORT nSize = nUndoPos;
921 if( !nSize )
923 rUndoIter.bWeiter = FALSE;
924 return FALSE;
927 // dann suche jetzt ueber die End/Start-Gruppen die gueltige Repeat-Aktion
928 SwUndo *pUndo = (*pUndos)[ --nSize ];
929 if( UNDO_END == pUndo->GetId() )
930 nSize = nSize - ((SwUndoEnd*)pUndo)->GetSttOffset();
932 USHORT nEndCnt = nUndoPos;
933 BOOL bOneUndo = nSize + 1 == nUndoPos;
935 SwPaM* pTmpCrsr = rUndoIter.pAktPam;
936 SwUndoId nId = UNDO_EMPTY;
938 if( pTmpCrsr != pTmpCrsr->GetNext() || !bOneUndo ) // Undo-Klammerung aufbauen
940 if (pUndo->GetId() == UNDO_END)
942 SwUndoStart * pStartUndo =
943 (SwUndoStart *) (*pUndos)[nSize];
945 nId = pStartUndo->GetUserId();
948 StartUndo( nId, NULL );
950 do { // dann durchlaufe mal den gesamten Ring
951 for( USHORT nRptCnt = nRepeatCnt; nRptCnt > 0; --nRptCnt )
953 rUndoIter.pLastUndoObj = 0;
954 for( USHORT nCnt = nSize; nCnt < nEndCnt; ++nCnt )
955 (*pUndos)[ nCnt ]->Repeat( rUndoIter ); // Repeat ausfuehren
957 } while( pTmpCrsr !=
958 ( rUndoIter.pAktPam = (SwPaM*)rUndoIter.pAktPam->GetNext() ));
959 if( pTmpCrsr != pTmpCrsr->GetNext() || !bOneUndo )
960 EndUndo( nId, NULL );
962 return TRUE;
965 // liefert die Id der letzten Repeatfaehigen Aktion zurueck oder 0
966 // fuellt ggf. VARARR mit User-RedoIds
968 String SwDoc::GetRepeatIdsStr(String* pStr, SwUndoIds *pRepeatIds) const
970 String aTmpStr;
971 SwUndoId nId;
973 if ( pStr != NULL)
975 nId = GetRepeatIds(pStr, pRepeatIds);
976 aTmpStr = *pStr;
978 else
979 nId = GetRepeatIds(&aTmpStr, pRepeatIds);
981 if (nId <= UNDO_END)
982 return String();
984 return aTmpStr;
987 SwUndoId SwDoc::GetRepeatIds(String* pStr, SwUndoIds *pRepeatIds) const
989 SwUndoId nRepeatId = GetUndoIds( pStr, pRepeatIds );
990 if( REPEAT_START <= nRepeatId && REPEAT_END > nRepeatId )
991 return nRepeatId;
992 return UNDO_EMPTY;
996 SwUndo* SwDoc::RemoveLastUndo( SwUndoId eUndoId )
998 SwUndo* pUndo = (*pUndos)[ nUndoPos - 1 ];
999 if( eUndoId == pUndo->GetId() && nUndoPos == pUndos->Count() )
1001 if( !nUndoSttEnd )
1002 --nUndoCnt;
1003 --nUndoPos;
1004 pUndos->Remove( nUndoPos, 1 );
1006 else
1008 pUndo = 0;
1009 ASSERT( !this, "falsches Undo-Object" );
1011 return pUndo;
1014 SwUndoIdAndName::SwUndoIdAndName( SwUndoId nId, const String* pStr )
1015 : eUndoId( nId ), pUndoStr( pStr ? new String( *pStr ) : 0 )
1019 SwUndoIdAndName::~SwUndoIdAndName()
1021 delete pUndoStr;