summaryrefslogtreecommitdiff
path: root/sw/source/core/undo/docundo.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/undo/docundo.cxx')
-rw-r--r--sw/source/core/undo/docundo.cxx1027
1 files changed, 1027 insertions, 0 deletions
diff --git a/sw/source/core/undo/docundo.cxx b/sw/source/core/undo/docundo.cxx
new file mode 100644
index 000000000000..85adbd1c7138
--- /dev/null
+++ b/sw/source/core/undo/docundo.cxx
@@ -0,0 +1,1027 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include <svx/svdmodel.hxx>
+
+#include <vcl/wrkwin.hxx>
+#include <doc.hxx>
+#include <pam.hxx>
+#include <ndtxt.hxx>
+#include <swundo.hxx> // fuer die UndoIds
+#include <undobj.hxx>
+#include <rolbck.hxx>
+#include <docary.hxx>
+#ifndef _UNDO_HRC
+#include <undo.hrc>
+#endif
+
+
+using namespace ::com::sun::star;
+
+
+USHORT SwDoc::nUndoActions = UNDO_ACTION_COUNT; // anzahl von Undo-Action
+
+// the undo array should never grow beyond this limit:
+#define UNDO_ACTION_LIMIT (USHRT_MAX - 1000)
+
+
+SV_IMPL_PTRARR( SwUndoIds, SwUndoIdAndNamePtr )
+
+//#define _SHOW_UNDORANGE
+#ifdef _SHOW_UNDORANGE
+
+
+class UndoArrStatus : public WorkWindow
+{
+ USHORT nUndo, nUndoNds;
+ virtual void Paint( const Rectangle& );
+public:
+ UndoArrStatus();
+ void Set( USHORT, USHORT );
+};
+static UndoArrStatus* pUndoMsgWin = 0;
+
+
+UndoArrStatus::UndoArrStatus()
+ : WorkWindow( APP_GETAPPWINDOW() ), nUndo(0), nUndoNds(0)
+{
+ SetSizePixel( Size( 200, 100 ));
+ SetFont( Font( "Courier", Size( 0, 10 )) );
+ Show();
+}
+
+
+void UndoArrStatus::Set( USHORT n1, USHORT n2 )
+{
+ nUndo = n1; nUndoNds = n2;
+ Invalidate();
+}
+
+
+void UndoArrStatus::Paint( const Rectangle& )
+{
+ String s;
+ DrawRect( Rectangle( Point(0,0), GetOutputSize() ));
+ ( s = "Undos: " ) += nUndo;
+ DrawText( Point( 0, 0 ), s );
+ ( s = "UndoNodes: " ) += nUndoNds;
+ DrawText( Point( 0, 15 ), s );
+}
+
+#endif
+
+void SwDoc::SetUndoNoResetModified()
+{
+ nUndoSavePos = USHRT_MAX;
+}
+
+bool SwDoc::IsUndoNoResetModified() const
+{
+ return USHRT_MAX == nUndoSavePos;
+}
+
+void SwDoc::DoUndo(bool bUn)
+{
+ mbUndo = bUn;
+
+ SdrModel* pSdrModel = GetDrawModel();
+ if( pSdrModel )
+ pSdrModel->EnableUndo(bUn);
+}
+
+bool SwDoc::DoesUndo() const
+{
+ return mbUndo;
+}
+
+void SwDoc::DoGroupUndo(bool bUn)
+{
+ mbGroupUndo = bUn;
+}
+
+bool SwDoc::DoesGroupUndo() const
+{
+ return mbGroupUndo;
+}
+
+sal_uInt16 SwDoc::GetUndoActionCount()
+{
+ return nUndoActions;
+}
+
+void SwDoc::SetUndoActionCount( sal_uInt16 nNew )
+{
+ nUndoActions = nNew;
+}
+
+const SwNodes* SwDoc::GetUndoNds() const
+{
+ return &aUndoNodes;
+}
+
+void SwDoc::AppendUndo( SwUndo* pUndo )
+{
+ if( nsRedlineMode_t::REDLINE_NONE == pUndo->GetRedlineMode() )
+ pUndo->SetRedlineMode( GetRedlineMode() );
+
+ // Unfortunately, the silly SvPtrArr can only store a little less than
+ // USHRT_MAX elements. Of course it doesn't see any necessity for asserting
+ // or even doing error handling. pUndos should definitely be replaced by an
+ // STL container that doesn't have this problem. cf #95884#
+ DBG_ASSERT( pUndos->Count() < USHRT_MAX - 16,
+ "Writer will crash soon. I apologize for the inconvenience." );
+
+ pUndos->Insert( pUndo, nUndoPos );
+ ++nUndoPos;
+ switch( pUndo->GetId() )
+ {
+ case UNDO_START: ++nUndoSttEnd;
+ break;
+
+ case UNDO_END: ASSERT( nUndoSttEnd, "Undo-Ende ohne Start" );
+ --nUndoSttEnd;
+ // kein break !!!
+ default:
+ if( pUndos->Count() != nUndoPos && UNDO_END != pUndo->GetId() )
+ ClearRedo();
+ else {
+ ASSERT( pUndos->Count() == nUndoPos || UNDO_END == pUndo->GetId(),
+ "Redo history not deleted!" );
+ }
+ if( !nUndoSttEnd )
+ ++nUndoCnt;
+ break;
+ }
+
+#ifdef _SHOW_UNDORANGE
+ // zur Anzeige der aktuellen Undo-Groessen
+ if( !pUndoMsgWin )
+ pUndoMsgWin = new UndoArrStatus;
+ pUndoMsgWin->Set( pUndos->Count(), aUndoNodes.Count() );
+#endif
+
+ // noch eine offene Klammerung, kann man sich den Rest schenken
+ if( nUndoSttEnd )
+ return;
+
+ // folgende Array-Grenzen muessen ueberwacht werden:
+ // - Undo, Grenze: fester Wert oder USHRT_MAX - 1000
+ // - UndoNodes, Grenze: USHRT_MAX - 1000
+ // - AttrHistory Grenze: USHRT_MAX - 1000
+ // (defined in UNDO_ACTION_LIMIT at the top of this file)
+
+ USHORT nEnde = UNDO_ACTION_LIMIT;
+
+// nur zum Testen der neuen DOC-Member
+#ifdef DBG_UTIL
+{
+ SwUndoId nId = UNDO_EMPTY;
+ USHORT nUndosCnt = 0, nSttEndCnt = 0;
+ for( USHORT nCnt = 0; nCnt < nUndoPos; ++nCnt )
+ {
+ if( UNDO_START == ( nId = (*pUndos)[ nCnt ]->GetId()) )
+ ++nSttEndCnt;
+ else if( UNDO_END == nId )
+ --nSttEndCnt;
+ if( !nSttEndCnt )
+ ++nUndosCnt;
+ }
+ ASSERT( nSttEndCnt == nUndoSttEnd, "Start-Ende Count ungleich" );
+ ASSERT( nUndosCnt == nUndoCnt, "Undo Count ungleich" );
+}
+#endif
+
+ if( SwDoc::nUndoActions < nUndoCnt )
+ // immer 1/10 loeschen
+ //JP 23.09.95: oder wenn neu eingestellt wurde um die Differenz
+ //JP 29.5.2001: Task #83891#: remove only the overlapping actions
+ DelUndoObj( nUndoCnt - SwDoc::nUndoActions );
+ else
+ {
+ USHORT nUndosCnt = nUndoCnt;
+ // immer 1/10 loeschen bis der "Ausloeser" behoben ist
+ while( aUndoNodes.Count() && nEnde < aUndoNodes.Count() )
+ DelUndoObj( nUndosCnt / 10 );
+ }
+}
+
+
+
+void SwDoc::ClearRedo()
+{
+ if( DoesUndo() && nUndoPos != pUndos->Count() )
+ {
+//?? why ?? if( !nUndoSttEnd )
+ {
+ // setze UndoCnt auf den neuen Wert
+ SwUndo* pUndo;
+ for( USHORT nCnt = pUndos->Count(); nUndoPos < nCnt; --nUndoCnt )
+ // Klammerung ueberspringen
+ if( UNDO_END == (pUndo = (*pUndos)[ --nCnt ])->GetId() )
+ nCnt = nCnt - ((SwUndoEnd*)pUndo)->GetSttOffset();
+ }
+
+ // loesche die Undo-Aktionen (immer von hinten !)
+ pUndos->DeleteAndDestroy( nUndoPos, pUndos->Count() - nUndoPos );
+ }
+}
+
+
+ // loescht die gesamten UndoObjecte
+void SwDoc::DelAllUndoObj()
+{
+ ClearRedo();
+
+ DoUndo( FALSE );
+
+ // Offene Undo-Klammerungen erhalten !!
+ SwUndo* pUndo;
+ USHORT nSize = pUndos->Count();
+ while( nSize )
+ if( UNDO_START != ( pUndo = (*pUndos)[ --nSize ] )->GetId() ||
+ ((SwUndoStart*)pUndo)->GetEndOffset() )
+ // keine offenen Gruppierung ?
+ pUndos->DeleteAndDestroy( nSize, 1 );
+
+ nUndoCnt = 0;
+ nUndoPos = pUndos->Count();
+
+/*
+ while( nUndoPos )
+ aUndos.DelDtor( --nUndoPos, 1 );
+ nUndoCnt = nUndoSttEnd = nUndoPos = 0;
+*/
+ nUndoSavePos = USHRT_MAX;
+ DoUndo( TRUE );
+}
+
+
+ // loescht alle UndoObjecte vom Anfang bis zum angegebenen Ende
+BOOL SwDoc::DelUndoObj( USHORT nEnde )
+{
+ if( !nEnde ) // sollte mal 0 uebergeben werden,
+ {
+ if( !pUndos->Count() )
+ return FALSE;
+ ++nEnde; // dann korrigiere es auf 1
+ }
+
+ DoUndo( FALSE );
+
+ // pruefe erstmal, wo das Ende steht
+ SwUndoId nId = UNDO_EMPTY;
+ USHORT nSttEndCnt = 0;
+ USHORT nCnt;
+
+ for( nCnt = 0; nEnde && nCnt < nUndoPos; ++nCnt )
+ {
+ if( UNDO_START == ( nId = (*pUndos)[ nCnt ]->GetId() ))
+ ++nSttEndCnt;
+ else if( UNDO_END == nId )
+ --nSttEndCnt;
+ if( !nSttEndCnt )
+ --nEnde, --nUndoCnt;
+ }
+
+ ASSERT( nCnt < nUndoPos || nUndoPos == pUndos->Count(),
+ "Undo-Del-Ende liegt in einer Redo-Aktion" );
+
+ // dann setze ab Ende bis Undo-Ende bei allen Undo-Objecte die Werte um
+ nSttEndCnt = nCnt; // Position merken
+ if( nUndoSavePos < nSttEndCnt ) // SavePos wird aufgegeben
+ nUndoSavePos = USHRT_MAX;
+ else if( nUndoSavePos != USHRT_MAX )
+ nUndoSavePos = nUndoSavePos - nSttEndCnt;
+
+ while( nSttEndCnt )
+ pUndos->DeleteAndDestroy( --nSttEndCnt, 1 );
+ nUndoPos = pUndos->Count();
+
+ DoUndo( TRUE );
+ return TRUE;
+}
+
+/**************** UNDO ******************/
+
+void SwDoc::setUndoNoModifiedPosition( SwUndoNoModifiedPosition nNew )
+{
+ nUndoSavePos = nNew;
+ if( !pUndos->Count() || nUndoSavePos > pUndos->Count() - 1 )
+ nUndoSavePos = USHRT_MAX;
+}
+
+SwUndoNoModifiedPosition SwDoc::getUndoNoModifiedPosition() const
+{
+ return nUndoSavePos;
+}
+
+
+bool SwDoc::HasUndoId(SwUndoId eId) const
+{
+ USHORT nSize = nUndoPos;
+ SwUndo * pUndo;
+ while( nSize-- )
+ if( ( pUndo = (*pUndos)[nSize])->GetId() == eId ||
+ ( UNDO_START == pUndo->GetId() &&
+ ((SwUndoStart*)pUndo)->GetUserId() == eId )
+ || ( UNDO_END == pUndo->GetId() &&
+ ((SwUndoEnd*)pUndo)->GetUserId() == eId ) )
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+bool SwDoc::Undo( SwUndoIter& rUndoIter )
+{
+ if ( (rUndoIter.GetId()!=0) && (!HasUndoId(rUndoIter.GetId())) )
+ {
+ rUndoIter.bWeiter = FALSE;
+ return FALSE;
+ }
+ if( !nUndoPos )
+ {
+ rUndoIter.bWeiter = FALSE;
+ return FALSE;
+ }
+
+ SwUndo *pUndo = (*pUndos)[ --nUndoPos ];
+
+ RedlineMode_t eOld = GetRedlineMode();
+ RedlineMode_t eTmpMode = (RedlineMode_t)pUndo->GetRedlineMode();
+ if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eOld) &&
+ UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() )
+ SetRedlineMode( eTmpMode );
+
+ SetRedlineMode_intern((RedlineMode_t)(eTmpMode | nsRedlineMode_t::REDLINE_IGNORE));
+ // Undo ausfuehren
+
+ // zum spaeteren ueberpruefen
+ SwUndoId nAktId = pUndo->GetId();
+ //JP 11.05.98: FlyFormate ueber die EditShell selektieren, nicht aus dem
+ // Undo heraus
+ switch( nAktId )
+ {
+ case UNDO_START:
+ case UNDO_END:
+ case UNDO_INSDRAWFMT:
+ break;
+
+ default:
+ rUndoIter.ClearSelections();
+ }
+
+ pUndo->Undo( rUndoIter );
+
+ SetRedlineMode( eOld );
+
+ // Besonderheit von Undo-Replace (interne History)
+ if( UNDO_REPLACE == nAktId && ((SwUndoReplace*)pUndo)->nAktPos )
+ {
+ ++nUndoPos;
+ return TRUE;
+ }
+
+ // Objekt aus History entfernen und zerstoeren
+ if( nUndoPos && !rUndoIter.bWeiter &&
+ UNDO_START == ( pUndo = (*pUndos)[ nUndoPos-1 ] )->GetId() )
+ --nUndoPos;
+
+ // JP 29.10.96: Start und End setzen kein Modify-Flag.
+ // Sonst gibt es Probleme mit der autom. Aufnahme von Ausnahmen
+ // bei der Autokorrektur
+ if( UNDO_START != nAktId && UNDO_END != nAktId )
+ SetModified(); // default: immer setzen, kann zurueck gesetzt werden
+
+ // ist die History leer und wurde nicht wegen Speichermangel
+ // verworfen, so kann das Dokument als unveraendert gelten
+ if( nUndoSavePos == nUndoPos )
+ ResetModified();
+
+ return TRUE;
+}
+
+
+// setzt Undoklammerung auf, liefert nUndoId der Klammerung
+
+
+SwUndoId SwDoc::StartUndo( SwUndoId eUndoId, const SwRewriter * pRewriter )
+{
+ if( !mbUndo )
+ return UNDO_EMPTY;
+
+ if( !eUndoId )
+ eUndoId = UNDO_START;
+
+ SwUndoStart * pUndo = new SwUndoStart( eUndoId );
+
+ if (pRewriter)
+ pUndo->SetRewriter(*pRewriter);
+
+ AppendUndo(pUndo);
+
+ return eUndoId;
+}
+// schliesst Klammerung der nUndoId, nicht vom UI benutzt
+
+
+SwUndoId SwDoc::EndUndo(SwUndoId eUndoId, const SwRewriter * pRewriter)
+{
+ USHORT nSize = nUndoPos;
+ if( !mbUndo || !nSize-- )
+ return UNDO_EMPTY;
+
+ if( UNDO_START == eUndoId || !eUndoId )
+ eUndoId = UNDO_END;
+
+ SwUndo* pUndo = (*pUndos)[ nSize ];
+ if( UNDO_START == pUndo->GetId() )
+ {
+ // leere Start/End-Klammerung ??
+ pUndos->DeleteAndDestroy( nSize );
+ --nUndoPos;
+ --nUndoSttEnd;
+ return UNDO_EMPTY;
+ }
+
+ // exist above any redo objects? If yes, delete them
+ if( nUndoPos != pUndos->Count() )
+ {
+ // setze UndoCnt auf den neuen Wert
+ for( USHORT nCnt = pUndos->Count(); nUndoPos < nCnt; --nUndoCnt )
+ // Klammerung ueberspringen
+ if( UNDO_END == (pUndo = (*pUndos)[ --nCnt ])->GetId() )
+ nCnt = nCnt - ((SwUndoEnd*)pUndo)->GetSttOffset();
+
+ pUndos->DeleteAndDestroy( nUndoPos, pUndos->Count() - nUndoPos );
+ }
+
+ // suche den Anfang dieser Klammerung
+ SwUndoId nId = UNDO_EMPTY;
+ while( nSize )
+ if( UNDO_START == ( nId = (pUndo = (*pUndos)[ --nSize ] )->GetId()) &&
+ !((SwUndoStart*)pUndo)->GetEndOffset() )
+ break; // Start gefunden
+
+ if( nId != UNDO_START )
+ {
+ // kann eigentlich nur beim Abspielen von Macros passieren, die
+ // Undo/Redo/Repeat benutzen und die eine exitierende Selection
+ // durch Einfuegen loeschen
+ ASSERT( !this, "kein entsprechendes Ende gefunden" );
+ // kein entsprechenden Start gefunden -> Ende nicht einfuegen
+ // und die Member am Doc updaten
+
+ nUndoSttEnd = 0;
+ nUndoCnt = 0;
+ // setze UndoCnt auf den neuen Wert
+ SwUndo* pTmpUndo;
+ for( USHORT nCnt = 0; nCnt < pUndos->Count(); ++nCnt, ++nUndoCnt )
+ // Klammerung ueberspringen
+ if( UNDO_START == (pTmpUndo = (*pUndos)[ nCnt ])->GetId() )
+ nCnt = nCnt + ((SwUndoStart*)pTmpUndo)->GetEndOffset();
+ return UNDO_EMPTY;
+
+ }
+
+ // Klammerung um eine einzelne Action muss nicht sein!
+ // Aussnahme: es ist eine eigene ID definiert
+ if( 2 == pUndos->Count() - nSize &&
+ (UNDO_END == eUndoId || eUndoId == (*pUndos)[ nSize+1 ]->GetId() ))
+ {
+ pUndos->DeleteAndDestroy( nSize );
+ nUndoPos = pUndos->Count();
+ if( !--nUndoSttEnd )
+ {
+ ++nUndoCnt;
+ if( SwDoc::nUndoActions < nUndoCnt )
+ // immer 1/10 loeschen
+ //JP 23.09.95: oder wenn neu eingestellt wurde um die Differenz
+ //JP 29.5.2001: Task #83891#: remove only the overlapping actions
+ DelUndoObj( nUndoCnt - SwDoc::nUndoActions );
+ else
+ {
+ USHORT nEnde = USHRT_MAX - 1000;
+ USHORT nUndosCnt = nUndoCnt;
+ // immer 1/10 loeschen bis der "Ausloeser" behoben ist
+ while( aUndoNodes.Count() && nEnde < aUndoNodes.Count() )
+ DelUndoObj( nUndosCnt / 10 );
+ }
+ }
+ return eUndoId;
+ }
+
+ // setze die Klammerung am Start/End-Undo
+ nSize = pUndos->Count() - nSize;
+ ((SwUndoStart*)pUndo)->SetEndOffset( nSize );
+
+ SwUndoEnd* pUndoEnd = new SwUndoEnd( eUndoId );
+ pUndoEnd->SetSttOffset( nSize );
+
+// nur zum Testen der Start/End-Verpointerung vom Start/End Undo
+#ifdef DBG_UTIL
+ {
+ USHORT nEndCnt = 1, nCnt = pUndos->Count();
+ SwUndoId nTmpId = UNDO_EMPTY;
+ while( nCnt )
+ {
+ if( UNDO_START == ( nTmpId = (*pUndos)[ --nCnt ]->GetId()) )
+ {
+ if( !nEndCnt ) // falls mal ein Start ohne Ende vorhanden ist
+ continue;
+ --nEndCnt;
+ if( !nEndCnt ) // hier ist der Anfang
+ break;
+ }
+ else if( UNDO_END == nTmpId )
+ ++nEndCnt;
+ else if( !nEndCnt )
+ break;
+ }
+ ASSERT( nCnt == pUndos->Count() - nSize,
+ "Start-Ende falsch geklammert" );
+ }
+#endif
+
+ if (pRewriter)
+ {
+ ((SwUndoStart *) pUndo)->SetRewriter(*pRewriter);
+ pUndoEnd->SetRewriter(*pRewriter);
+ }
+ else
+ pUndoEnd->SetRewriter(((SwUndoStart *) pUndo)->GetRewriter());
+
+ AppendUndo( pUndoEnd );
+ return eUndoId;
+}
+
+// liefert die Id der letzten Undofaehigen Aktion zurueck oder 0
+// fuellt ggf. VARARR mit User-UndoIds
+
+String SwDoc::GetUndoIdsStr( String* pStr, SwUndoIds *pUndoIds) const
+{
+ String aTmpStr;
+
+ if (pStr != NULL)
+ {
+ GetUndoIds( pStr, pUndoIds);
+ aTmpStr = *pStr;
+ }
+ else
+ GetUndoIds( &aTmpStr, pUndoIds);
+
+ return aTmpStr;
+}
+
+/*-- 24.11.2004 16:11:21---------------------------------------------------
+
+ -----------------------------------------------------------------------*/
+sal_Bool SwDoc::RestoreInvisibleContent()
+{
+ sal_Bool bRet = sal_False;
+ if(nUndoPos > 0 )
+ {
+ SwUndo * pUndo = (*pUndos)[ nUndoPos - 1 ];
+ if( ( pUndo->GetId() == UNDO_END &&
+ static_cast<SwUndoEnd *>(pUndo)->GetUserId() == UNDO_UI_DELETE_INVISIBLECNTNT) )
+ {
+ SwPaM aPam( GetNodes().GetEndOfPostIts() );
+ SwUndoIter aUndoIter( &aPam );
+ do
+ {
+ Undo( aUndoIter );
+ }
+ while ( aUndoIter.IsNextUndo() );
+ ClearRedo();
+ bRet = sal_True;
+ }
+ }
+ return bRet;
+}
+
+
+/**
+ Returns id and comment for a certain undo object in an undo stack.
+
+ Remark: In the following the object type referred to is always the
+ effective object type. If an UNDO_START or UNDO_END has a user type
+ it is referred to as this type.
+
+ If the queried object is an UNDO_END and has no user id the result
+ is taken from the first object that is not an UNDO_END nor an
+ UNDO_START preceeding the queried object.
+
+ If the queried object is an UNDO_START and has no user id the
+ result is taken from the first object that is not an UNDO_END nor
+ an UNDO_START preceeding the UNDO_END object belonging to the
+ queried object.
+
+ In all other cases the result is taken from the queried object.
+
+ @param rUndos the undo stack
+ @param nPos position of the undo object to query
+
+ @return SwUndoIdAndName object containing the query result
+ */
+SwUndoIdAndName * lcl_GetUndoIdAndName(const SwUndos & rUndos, sal_uInt16 nPos )
+{
+ SwUndo * pUndo = rUndos[ nPos ];
+ SwUndoId nId = UNDO_EMPTY;
+ String sStr("??", RTL_TEXTENCODING_ASCII_US);
+
+ ASSERT( nPos < rUndos.Count(), "nPos out of range");
+
+ switch (pUndo->GetId())
+ {
+ case UNDO_START:
+ {
+ SwUndoStart * pUndoStart = (SwUndoStart *) pUndo;
+ nId = pUndoStart->GetUserId();
+
+ if (nId <= UNDO_END)
+ {
+ /**
+ Start at the according UNDO_END. Search backwards
+ for first objects that is not a UNDO_END.
+ */
+ int nTmpPos = nPos + pUndoStart->GetEndOffset();
+ int nSubstitute = -1;
+
+ // --> OD 2009-09-30 #i105457#
+ if ( nTmpPos > 0 )
+ // <--
+ {
+ SwUndo * pTmpUndo;
+ do
+ {
+ nTmpPos--;
+ pTmpUndo = rUndos[ static_cast<USHORT>(nTmpPos) ];
+
+ if (pTmpUndo->GetEffectiveId() > UNDO_END)
+ nSubstitute = nTmpPos;
+ }
+ while (nSubstitute < 0 && nTmpPos > nPos);
+
+ if (nSubstitute >= 0)
+ {
+ SwUndo * pSubUndo = rUndos[ static_cast<USHORT>(nSubstitute) ];
+ nId = pSubUndo->GetEffectiveId();
+ sStr = pSubUndo->GetComment();
+ }
+ }
+ }
+ else
+ sStr = pUndo->GetComment();
+ }
+
+ break;
+
+ case UNDO_END:
+ {
+ SwUndoEnd * pUndoEnd = (SwUndoEnd *) pUndo;
+ nId = pUndoEnd->GetUserId();
+
+ if (nId <= UNDO_END)
+ {
+ /**
+ Start at this UNDO_END. Search backwards
+ for first objects that is not a UNDO_END.
+ */
+
+ int nTmpPos = nPos;
+ int nUndoStart = nTmpPos - pUndoEnd->GetSttOffset();
+ int nSubstitute = -1;
+
+ if (nTmpPos > 0)
+ {
+ SwUndo * pTmpUndo;
+
+ do
+ {
+ nTmpPos--;
+ pTmpUndo = rUndos[ static_cast<USHORT>(nTmpPos) ];
+
+ if (pTmpUndo->GetEffectiveId() > UNDO_END)
+ nSubstitute = nTmpPos;
+ }
+ while (nSubstitute < 0 && nTmpPos > nUndoStart);
+
+ if (nSubstitute >= 0)
+ {
+ SwUndo * pSubUndo = rUndos[ static_cast<USHORT>(nSubstitute) ];
+ nId = pSubUndo->GetEffectiveId();
+ sStr = pSubUndo->GetComment();
+ }
+ }
+ }
+ else
+ sStr = pUndo->GetComment();
+ }
+
+ break;
+
+ default:
+ nId = pUndo->GetId();
+ sStr = pUndo->GetComment();
+ }
+
+ return new SwUndoIdAndName(nId, &sStr);
+}
+
+SwUndoId SwDoc::GetUndoIds( String* pStr, SwUndoIds *pUndoIds) const
+{
+ int nTmpPos = nUndoPos - 1;
+ SwUndoId nId = UNDO_EMPTY;
+
+ while (nTmpPos >= 0)
+ {
+ SwUndo * pUndo = (*pUndos)[ static_cast<USHORT>(nTmpPos) ];
+
+ SwUndoIdAndName * pIdAndName = lcl_GetUndoIdAndName( *pUndos, static_cast<sal_uInt16>(nTmpPos) );
+
+ if (nTmpPos == nUndoPos - 1)
+ {
+ nId = pIdAndName->GetUndoId();
+
+ if (pStr)
+ *pStr = *pIdAndName->GetUndoStr();
+ }
+
+ if (pUndoIds)
+ pUndoIds->Insert(pIdAndName, pUndoIds->Count());
+ else
+ break;
+
+ if (pUndo->GetId() == UNDO_END)
+ nTmpPos -= ((SwUndoEnd *) pUndo)->GetSttOffset();
+
+ nTmpPos--;
+ }
+
+ return nId;
+}
+
+bool SwDoc::HasTooManyUndos() const
+{
+ // AppendUndo checks the UNDO_ACTION_LIMIT, unless there's a nested undo.
+ // So HasTooManyUndos() may only occur when undos are nested; else
+ // AppendUndo has some sort of bug.
+ DBG_ASSERT( (nUndoSttEnd != 0) || (pUndos->Count() < UNDO_ACTION_LIMIT),
+ "non-nested undos should have been handled in AppendUndo" );
+ return (pUndos->Count() >= UNDO_ACTION_LIMIT);
+}
+
+
+/**************** REDO ******************/
+
+
+bool SwDoc::Redo( SwUndoIter& rUndoIter )
+{
+ if( rUndoIter.GetId() && !HasUndoId( rUndoIter.GetId() ) )
+ {
+ rUndoIter.bWeiter = FALSE;
+ return FALSE;
+ }
+ if( nUndoPos == pUndos->Count() )
+ {
+ rUndoIter.bWeiter = FALSE;
+ return FALSE;
+ }
+
+ SwUndo *pUndo = (*pUndos)[ nUndoPos++ ];
+
+ RedlineMode_t eOld = GetRedlineMode();
+ RedlineMode_t eTmpMode = (RedlineMode_t)pUndo->GetRedlineMode();
+ if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eOld) &&
+ UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() )
+ SetRedlineMode( eTmpMode );
+ SetRedlineMode_intern( (RedlineMode_t)(eTmpMode | nsRedlineMode_t::REDLINE_IGNORE));
+
+ //JP 11.05.98: FlyFormate ueber die EditShell selektieren, nicht aus dem
+ // Undo heraus
+ if( UNDO_START != pUndo->GetId() && UNDO_END != pUndo->GetId() )
+ rUndoIter.ClearSelections();
+
+ pUndo->Redo( rUndoIter );
+
+ SetRedlineMode( eOld );
+
+ // Besonderheit von Undo-Replace (interne History)
+ if( UNDO_REPLACE == pUndo->GetId() &&
+ USHRT_MAX != ((SwUndoReplace*)pUndo)->nAktPos )
+ {
+ --nUndoPos;
+ return TRUE;
+ }
+
+ if( rUndoIter.bWeiter && nUndoPos >= pUndos->Count() )
+ rUndoIter.bWeiter = FALSE;
+
+ // ist die History leer und wurde nicht wegen Speichermangel
+ // verworfen, so kann das Dokument als unveraendert gelten
+ if( nUndoSavePos == nUndoPos )
+ ResetModified();
+ else
+ SetModified();
+ return TRUE;
+}
+
+
+// liefert die Id der letzten Redofaehigen Aktion zurueck oder 0
+// fuellt ggf. VARARR mit User-RedoIds
+
+String SwDoc::GetRedoIdsStr( String* pStr, SwUndoIds *pRedoIds ) const
+{
+ String aTmpStr;
+
+ if (pStr != NULL)
+ {
+ GetRedoIds( pStr, pRedoIds );
+ aTmpStr = *pStr;
+ }
+ else
+ GetRedoIds( &aTmpStr, pRedoIds );
+
+
+ return aTmpStr;
+}
+
+
+SwUndoId SwDoc::GetRedoIds( String* pStr, SwUndoIds *pRedoIds ) const
+{
+ sal_uInt16 nTmpPos = nUndoPos;
+ SwUndoId nId = UNDO_EMPTY;
+
+ while (nTmpPos < pUndos->Count())
+ {
+ SwUndo * pUndo = (*pUndos)[nTmpPos];
+
+ SwUndoIdAndName * pIdAndName = lcl_GetUndoIdAndName(*pUndos, nTmpPos);
+
+ if (nTmpPos == nUndoPos)
+ {
+ nId = pIdAndName->GetUndoId();
+
+ if (pStr)
+ *pStr = *pIdAndName->GetUndoStr();
+ }
+
+ if (pRedoIds)
+ pRedoIds->Insert(pIdAndName, pRedoIds->Count());
+ else
+ break;
+
+ if (pUndo->GetId() == UNDO_START)
+ nTmpPos = nTmpPos + ((SwUndoStart *) pUndo)->GetEndOffset();
+
+ nTmpPos++;
+ }
+
+ return nId;
+}
+
+/**************** REPEAT ******************/
+
+
+bool SwDoc::Repeat( SwUndoIter& rUndoIter, sal_uInt16 nRepeatCnt )
+{
+ if( rUndoIter.GetId() && !HasUndoId( rUndoIter.GetId() ) )
+ {
+ rUndoIter.bWeiter = FALSE;
+ return FALSE;
+ }
+ USHORT nSize = nUndoPos;
+ if( !nSize )
+ {
+ rUndoIter.bWeiter = FALSE;
+ return FALSE;
+ }
+
+ // dann suche jetzt ueber die End/Start-Gruppen die gueltige Repeat-Aktion
+ SwUndo *pUndo = (*pUndos)[ --nSize ];
+ if( UNDO_END == pUndo->GetId() )
+ nSize = nSize - ((SwUndoEnd*)pUndo)->GetSttOffset();
+
+ USHORT nEndCnt = nUndoPos;
+ BOOL bOneUndo = nSize + 1 == nUndoPos;
+
+ SwPaM* pTmpCrsr = rUndoIter.pAktPam;
+ SwUndoId nId = UNDO_EMPTY;
+
+ if( pTmpCrsr != pTmpCrsr->GetNext() || !bOneUndo ) // Undo-Klammerung aufbauen
+ {
+ if (pUndo->GetId() == UNDO_END)
+ {
+ SwUndoStart * pStartUndo =
+ (SwUndoStart *) (*pUndos)[nSize];
+
+ nId = pStartUndo->GetUserId();
+ }
+
+ StartUndo( nId, NULL );
+ }
+ do { // dann durchlaufe mal den gesamten Ring
+ for( USHORT nRptCnt = nRepeatCnt; nRptCnt > 0; --nRptCnt )
+ {
+ rUndoIter.pLastUndoObj = 0;
+ for( USHORT nCnt = nSize; nCnt < nEndCnt; ++nCnt )
+ (*pUndos)[ nCnt ]->Repeat( rUndoIter ); // Repeat ausfuehren
+ }
+ } while( pTmpCrsr !=
+ ( rUndoIter.pAktPam = (SwPaM*)rUndoIter.pAktPam->GetNext() ));
+ if( pTmpCrsr != pTmpCrsr->GetNext() || !bOneUndo )
+ EndUndo( nId, NULL );
+
+ return TRUE;
+}
+
+// liefert die Id der letzten Repeatfaehigen Aktion zurueck oder 0
+// fuellt ggf. VARARR mit User-RedoIds
+
+String SwDoc::GetRepeatIdsStr(String* pStr, SwUndoIds *pRepeatIds) const
+{
+ String aTmpStr;
+ SwUndoId nId;
+
+ if ( pStr != NULL)
+ {
+ nId = GetRepeatIds(pStr, pRepeatIds);
+ aTmpStr = *pStr;
+ }
+ else
+ nId = GetRepeatIds(&aTmpStr, pRepeatIds);
+
+ if (nId <= UNDO_END)
+ return String();
+
+ return aTmpStr;
+}
+
+SwUndoId SwDoc::GetRepeatIds(String* pStr, SwUndoIds *pRepeatIds) const
+{
+ SwUndoId nRepeatId = GetUndoIds( pStr, pRepeatIds );
+ if( REPEAT_START <= nRepeatId && REPEAT_END > nRepeatId )
+ return nRepeatId;
+ return UNDO_EMPTY;
+}
+
+
+SwUndo* SwDoc::RemoveLastUndo( SwUndoId eUndoId )
+{
+ SwUndo* pUndo = (*pUndos)[ nUndoPos - 1 ];
+ if( eUndoId == pUndo->GetId() && nUndoPos == pUndos->Count() )
+ {
+ if( !nUndoSttEnd )
+ --nUndoCnt;
+ --nUndoPos;
+ pUndos->Remove( nUndoPos, 1 );
+ }
+ else
+ {
+ pUndo = 0;
+ ASSERT( !this, "falsches Undo-Object" );
+ }
+ return pUndo;
+}
+
+SwUndoIdAndName::SwUndoIdAndName( SwUndoId nId, const String* pStr )
+ : eUndoId( nId ), pUndoStr( pStr ? new String( *pStr ) : 0 )
+{
+}
+
+SwUndoIdAndName::~SwUndoIdAndName()
+{
+ delete pUndoStr;
+}
+
+
+