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: undo.cxx,v $
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_svtools.hxx"
34 #include <com/sun/star/uno/Exception.hpp>
36 #include <tools/debug.hxx>
38 #include <svtools/undo.hxx>
40 using ::com::sun::star::uno::Exception
;
42 // STATIC DATA -----------------------------------------------------------
44 DBG_NAME(SfxUndoAction
)
46 //========================================================================
48 TYPEINIT0(SfxUndoAction
);
49 TYPEINIT0(SfxListUndoAction
);
50 TYPEINIT0(SfxLinkUndoAction
);
51 TYPEINIT0(SfxRepeatTarget
);
53 //------------------------------------------------------------------------
55 SfxRepeatTarget::~SfxRepeatTarget()
59 //------------------------------------------------------------------------
61 BOOL
SfxUndoAction::IsLinked()
66 //------------------------------------------------------------------------
68 void SfxUndoAction::SetLinked( BOOL bIsLinked
)
73 //------------------------------------------------------------------------
75 SfxUndoAction::~SfxUndoAction()
77 DBG_DTOR(SfxUndoAction
, 0);
78 DBG_ASSERT( !IsLinked(), "Gelinkte Action geloescht" );
82 SfxUndoAction::SfxUndoAction()
84 DBG_CTOR(SfxUndoAction
, 0);
88 //------------------------------------------------------------------------
90 BOOL
SfxUndoAction::Merge( SfxUndoAction
* )
92 DBG_CHKTHIS(SfxUndoAction
, 0);
96 //------------------------------------------------------------------------
98 XubString
SfxUndoAction::GetComment() const
100 DBG_CHKTHIS(SfxUndoAction
, 0);
104 //------------------------------------------------------------------------
107 USHORT
SfxUndoAction::GetId() const
109 DBG_CHKTHIS(SfxUndoAction
, 0);
113 //------------------------------------------------------------------------
115 XubString
SfxUndoAction::GetRepeatComment(SfxRepeatTarget
&) const
117 DBG_CHKTHIS(SfxUndoAction
, 0);
121 //------------------------------------------------------------------------
124 void SfxUndoAction::Undo()
126 // die sind nur konzeptuell pure virtual
127 DBG_ERROR( "pure virtual function called: SfxUndoAction::Undo()" );
130 //------------------------------------------------------------------------
132 void SfxUndoAction::Redo()
134 // die sind nur konzeptuell pure virtual
135 DBG_ERROR( "pure virtual function called: SfxUndoAction::Redo()" );
138 //------------------------------------------------------------------------
140 void SfxUndoAction::Repeat(SfxRepeatTarget
&)
142 // die sind nur konzeptuell pure virtual
143 DBG_ERROR( "pure virtual function called: SfxUndoAction::Repeat()" );
146 //------------------------------------------------------------------------
149 BOOL
SfxUndoAction::CanRepeat(SfxRepeatTarget
&) const
154 //========================================================================
157 SfxUndoManager::SfxUndoManager( USHORT nMaxUndoActionCount
)
158 : pFatherUndoArray(0)
159 , mbUndoEnabled( true )
161 pUndoArray
=new SfxUndoArray(nMaxUndoActionCount
);
162 pActUndoArray
=pUndoArray
;
166 //------------------------------------------------------------------------
169 SfxUndoManager::~SfxUndoManager()
174 //------------------------------------------------------------------------
176 void SfxUndoManager::EnableUndo( bool bEnable
)
178 mbUndoEnabled
= bEnable
;
181 //------------------------------------------------------------------------
184 void SfxUndoManager::SetMaxUndoActionCount( USHORT nMaxUndoActionCount
)
186 // Remove entries from the pActUndoArray when we have to reduce
187 // the number of entries due to a lower nMaxUndoActionCount.
188 // Both redo and undo action entries will be removed until we reached the
189 // new nMaxUndoActionCount.
191 long nNumToDelete
= pActUndoArray
->aUndoActions
.Count() - nMaxUndoActionCount
;
192 if ( nNumToDelete
> 0 )
194 while ( nNumToDelete
> 0 )
196 USHORT nPos
= pActUndoArray
->aUndoActions
.Count();
197 if ( nPos
> pActUndoArray
->nCurUndoAction
)
199 if ( !pActUndoArray
->aUndoActions
[nPos
-1]->IsLinked() )
201 delete pActUndoArray
->aUndoActions
[nPos
-1];
202 pActUndoArray
->aUndoActions
.Remove( nPos
-1 );
207 if ( nNumToDelete
> 0 && pActUndoArray
->nCurUndoAction
> 0 )
209 if ( !pActUndoArray
->aUndoActions
[0]->IsLinked() )
211 delete pActUndoArray
->aUndoActions
[0];
212 pActUndoArray
->aUndoActions
.Remove(0);
213 --pActUndoArray
->nCurUndoAction
;
218 if ( nPos
== pActUndoArray
->aUndoActions
.Count() )
219 break; // Cannot delete more entries
223 pActUndoArray
->nMaxUndoActions
= nMaxUndoActionCount
;
226 //------------------------------------------------------------------------
228 USHORT
SfxUndoManager::GetMaxUndoActionCount() const
230 return pActUndoArray
->nMaxUndoActions
;
233 //------------------------------------------------------------------------
235 void SfxUndoManager::Clear()
237 while ( pActUndoArray
->aUndoActions
.Count() )
239 SfxUndoAction
*pAction
=
240 pActUndoArray
->aUndoActions
[pActUndoArray
->aUndoActions
.Count() - 1];
241 pActUndoArray
->aUndoActions
.Remove( pActUndoArray
->aUndoActions
.Count() - 1 );
245 pActUndoArray
->nCurUndoAction
= 0;
248 //------------------------------------------------------------------------
250 void SfxUndoManager::ClearRedo()
252 while ( pActUndoArray
->aUndoActions
.Count() > pActUndoArray
->nCurUndoAction
)
254 SfxUndoAction
*pAction
=
255 pActUndoArray
->aUndoActions
[pActUndoArray
->aUndoActions
.Count() - 1];
256 pActUndoArray
->aUndoActions
.Remove( pActUndoArray
->aUndoActions
.Count() - 1 );
261 //------------------------------------------------------------------------
263 void SfxUndoManager::AddUndoAction( SfxUndoAction
*pAction
, BOOL bTryMerge
)
267 // Redo-Actions loeschen
268 for ( USHORT nPos
= pActUndoArray
->aUndoActions
.Count();
269 nPos
> pActUndoArray
->nCurUndoAction
; --nPos
)
270 delete pActUndoArray
->aUndoActions
[nPos
-1];
272 pActUndoArray
->aUndoActions
.Remove(
273 pActUndoArray
->nCurUndoAction
,
274 pActUndoArray
->aUndoActions
.Count() - pActUndoArray
->nCurUndoAction
);
276 if ( pActUndoArray
->nMaxUndoActions
)
278 SfxUndoAction
*pTmpAction
= pActUndoArray
->nCurUndoAction
?
279 pActUndoArray
->aUndoActions
[pActUndoArray
->nCurUndoAction
-1] : 0;
281 if ( !bTryMerge
|| !(pTmpAction
&& pTmpAction
->Merge(pAction
)) )
283 // auf Max-Anzahl anpassen
284 if( pActUndoArray
== pUndoArray
)
285 while( pActUndoArray
->aUndoActions
.Count() >=
286 pActUndoArray
->nMaxUndoActions
&&
287 !pActUndoArray
->aUndoActions
[0]->IsLinked() )
289 delete pActUndoArray
->aUndoActions
[0];
290 pActUndoArray
->aUndoActions
.Remove(0);
291 --pActUndoArray
->nCurUndoAction
;
294 // neue Action anh"angen
295 const SfxUndoAction
* pTemp
= pAction
;
296 pActUndoArray
->aUndoActions
.Insert(
297 pTemp
, pActUndoArray
->nCurUndoAction
++ );
305 //------------------------------------------------------------------------
307 USHORT
SfxUndoManager::GetUndoActionCount() const
309 return pActUndoArray
->nCurUndoAction
;
312 //------------------------------------------------------------------------
314 XubString
SfxUndoManager::GetUndoActionComment( USHORT nNo
) const
316 DBG_ASSERT( nNo
< pActUndoArray
->nCurUndoAction
, "svtools::SfxUndoManager::GetUndoActionComment(), illegal id!" );
317 if( nNo
< pActUndoArray
->nCurUndoAction
)
319 return pActUndoArray
->aUndoActions
[pActUndoArray
->nCurUndoAction
-1-nNo
]->GetComment(); //!
328 //------------------------------------------------------------------------
330 USHORT
SfxUndoManager::GetUndoActionId( USHORT nNo
) const
332 DBG_ASSERT( nNo
< pActUndoArray
->nCurUndoAction
, "svtools::SfxUndoManager::GetUndoActionId(), illegal id!" );
333 if( nNo
< pActUndoArray
->nCurUndoAction
)
335 return pActUndoArray
->aUndoActions
[pActUndoArray
->nCurUndoAction
-1-nNo
]->GetId(); //!
343 //------------------------------------------------------------------------
345 SfxUndoAction
* SfxUndoManager::GetUndoAction( USHORT nNo
) const
347 DBG_ASSERT( nNo
< pActUndoArray
->nCurUndoAction
, "svtools::SfxUndoManager::GetUndoAction(), illegal id!" );
348 if( nNo
< pActUndoArray
->nCurUndoAction
)
350 return pActUndoArray
->aUndoActions
[pActUndoArray
->nCurUndoAction
-1-nNo
]; //!
358 //------------------------------------------------------------------------
360 /** clears the redo stack and removes the top undo action */
361 void SfxUndoManager::RemoveLastUndoAction()
363 DBG_ASSERT( pActUndoArray
->nCurUndoAction
, "svtools::SfxUndoManager::RemoveLastUndoAction(), no action to remove?!" );
364 if( pActUndoArray
->nCurUndoAction
)
366 pActUndoArray
->nCurUndoAction
--;
368 // delete redo-actions and top action
370 for ( nPos
= pActUndoArray
->aUndoActions
.Count(); nPos
> pActUndoArray
->nCurUndoAction
; --nPos
)
371 delete pActUndoArray
->aUndoActions
[nPos
-1];
373 pActUndoArray
->aUndoActions
.Remove(
374 pActUndoArray
->nCurUndoAction
,
375 pActUndoArray
->aUndoActions
.Count() - pActUndoArray
->nCurUndoAction
);
379 //------------------------------------------------------------------------
381 BOOL
SfxUndoManager::Undo( USHORT
)
383 bool bUndoWasEnabled
= mbUndoEnabled
;
384 mbUndoEnabled
= false;
390 DBG_ASSERT( pActUndoArray
== pUndoArray
, "svtools::SfxUndoManager::Undo(), LeaveListAction() not yet called!" );
391 if ( pActUndoArray
->nCurUndoAction
)
393 Undo( *pActUndoArray
->aUndoActions
[ --pActUndoArray
->nCurUndoAction
] );
397 catch( Exception
& e
)
399 mbUndoEnabled
= bUndoWasEnabled
;
402 mbUndoEnabled
= bUndoWasEnabled
;
406 //------------------------------------------------------------------------
408 void SfxUndoManager::Undo( SfxUndoAction
&rAction
)
410 bool bUndoWasEnabled
= mbUndoEnabled
;
411 mbUndoEnabled
= false;
416 catch( Exception
& e
)
418 mbUndoEnabled
= bUndoWasEnabled
;
422 mbUndoEnabled
= bUndoWasEnabled
;
425 //------------------------------------------------------------------------
427 USHORT
SfxUndoManager::GetRedoActionCount() const
429 return pActUndoArray
->aUndoActions
.Count() - pActUndoArray
->nCurUndoAction
; //!
432 //------------------------------------------------------------------------
434 XubString
SfxUndoManager::GetRedoActionComment( USHORT nNo
) const
436 return pActUndoArray
->aUndoActions
[pActUndoArray
->nCurUndoAction
+nNo
]->GetComment(); //!
439 //------------------------------------------------------------------------
441 USHORT
SfxUndoManager::GetRedoActionId( USHORT nNo
) const
443 return pActUndoArray
->aUndoActions
[pActUndoArray
->nCurUndoAction
+nNo
]->GetId(); //!
446 //------------------------------------------------------------------------
448 BOOL
SfxUndoManager::Redo( USHORT
)
450 bool bUndoWasEnabled
= mbUndoEnabled
;
451 mbUndoEnabled
= false;
457 if ( pActUndoArray
->aUndoActions
.Count() > pActUndoArray
->nCurUndoAction
)
459 Redo( *pActUndoArray
->aUndoActions
[pActUndoArray
->nCurUndoAction
++] );
463 catch( Exception
& e
)
465 mbUndoEnabled
= bUndoWasEnabled
;
469 mbUndoEnabled
= bUndoWasEnabled
;
473 //------------------------------------------------------------------------
475 void SfxUndoManager::Redo( SfxUndoAction
&rAction
)
477 bool bUndoWasEnabled
= mbUndoEnabled
;
478 mbUndoEnabled
= false;
484 catch( Exception
& e
)
486 mbUndoEnabled
= bUndoWasEnabled
;
490 mbUndoEnabled
= bUndoWasEnabled
;
493 //------------------------------------------------------------------------
495 USHORT
SfxUndoManager::GetRepeatActionCount() const
497 return pActUndoArray
->aUndoActions
.Count();
500 //------------------------------------------------------------------------
502 XubString
SfxUndoManager::GetRepeatActionComment( SfxRepeatTarget
&rTarget
, USHORT nNo
) const
504 return pActUndoArray
->aUndoActions
[ pActUndoArray
->aUndoActions
.Count() - 1 - nNo
]
505 ->GetRepeatComment(rTarget
);
508 //------------------------------------------------------------------------
510 BOOL
SfxUndoManager::Repeat( SfxRepeatTarget
&rTarget
, USHORT
/*nFrom*/, USHORT
/*nCount*/ )
512 if ( pActUndoArray
->aUndoActions
.Count() )
514 Repeat( rTarget
, *pActUndoArray
->aUndoActions
[ pActUndoArray
->aUndoActions
.Count() - 1 ] );
521 //------------------------------------------------------------------------
523 void SfxUndoManager::Repeat( SfxRepeatTarget
&rTarget
, SfxUndoAction
&rAction
)
525 if ( rAction
.CanRepeat(rTarget
) )
526 rAction
.Repeat(rTarget
);
529 //------------------------------------------------------------------------
531 BOOL
SfxUndoManager::CanRepeat( SfxRepeatTarget
&rTarget
, SfxUndoAction
&rAction
) const
533 return rAction
.CanRepeat(rTarget
);
536 //------------------------------------------------------------------------
538 BOOL
SfxUndoManager::CanRepeat( SfxRepeatTarget
&rTarget
, USHORT nNo
) const
540 if ( pActUndoArray
->aUndoActions
.Count() > nNo
)
542 USHORT nActionNo
= pActUndoArray
->aUndoActions
.Count() - 1 - nNo
;
543 return pActUndoArray
->aUndoActions
[nActionNo
]->CanRepeat(rTarget
);
549 //------------------------------------------------------------------------
551 void SfxUndoManager::EnterListAction(
552 const XubString
& rComment
, const XubString
&rRepeatComment
, USHORT nId
)
556 Fuegt eine ListUndoAction ein und setzt dessen UndoArray als aktuelles.
563 if ( !pUndoArray
->nMaxUndoActions
)
566 pFatherUndoArray
=pActUndoArray
;
567 SfxListUndoAction
*pAction
=new SfxListUndoAction(
568 rComment
, rRepeatComment
, nId
, pActUndoArray
);
569 AddUndoAction( pAction
);
570 pActUndoArray
=pAction
;
573 //------------------------------------------------------------------------
575 void SfxUndoManager::LeaveListAction()
579 Verlaesst die aktuelle ListAction und geht eine Ebene nach oben.
582 if ( !mbUndoEnabled
)
585 if ( !pUndoArray
->nMaxUndoActions
)
588 if( pActUndoArray
== pUndoArray
)
590 DBG_ERROR( "svtools::SfxUndoManager::LeaveListAction(), called without calling EnterListAction()!" );
594 DBG_ASSERT(pActUndoArray
->pFatherUndoArray
,"svtools::SfxUndoManager::LeaveListAction(), no father undo array!?");
596 SfxUndoArray
* pTmp
=pActUndoArray
;
597 pActUndoArray
=pActUndoArray
->pFatherUndoArray
;
599 // If no undo action where added, delete the undo list action
600 SfxUndoAction
*pTmpAction
= pActUndoArray
->aUndoActions
[pActUndoArray
->nCurUndoAction
-1];
601 if(!pTmp
->nCurUndoAction
)
603 pActUndoArray
->aUndoActions
.Remove( --pActUndoArray
->nCurUndoAction
);
608 // if the undo array has no comment, try to get it from its children
609 SfxListUndoAction
* pList
= dynamic_cast< SfxListUndoAction
* >( pTmpAction
);
610 if( pList
&& pList
->GetComment().Len() == 0 )
613 for( n
= 0; n
< pList
->aUndoActions
.Count(); n
++ )
615 if( pList
->aUndoActions
[n
]->GetComment().Len() )
617 pList
->SetComment( pList
->aUndoActions
[n
]->GetComment() );
625 //------------------------------------------------------------------------
627 USHORT
SfxListUndoAction::GetId() const
632 //------------------------------------------------------------------------
634 XubString
SfxListUndoAction::GetComment() const
639 //------------------------------------------------------------------------
641 void SfxListUndoAction::SetComment( const UniString
& rComment
)
646 //------------------------------------------------------------------------
648 XubString
SfxListUndoAction::GetRepeatComment(SfxRepeatTarget
&) const
650 return aRepeatComment
;
654 //------------------------------------------------------------------------
656 SfxListUndoAction::SfxListUndoAction
658 const XubString
&rComment
,
659 const XubString rRepeatComment
,
661 SfxUndoArray
*pFather
663 : nId(Id
), aComment(rComment
), aRepeatComment(rRepeatComment
)
665 pFatherUndoArray
= pFather
;
666 nMaxUndoActions
= USHRT_MAX
;
669 //------------------------------------------------------------------------
671 void SfxListUndoAction::Undo()
673 for(INT16 i
=nCurUndoAction
-1;i
>=0;i
--)
674 aUndoActions
[i
]->Undo();
678 //------------------------------------------------------------------------
680 void SfxListUndoAction::Redo()
682 for(USHORT i
=nCurUndoAction
;i
<aUndoActions
.Count();i
++)
683 aUndoActions
[i
]->Redo();
684 nCurUndoAction
= aUndoActions
.Count();
687 //------------------------------------------------------------------------
689 void SfxListUndoAction::Repeat(SfxRepeatTarget
&rTarget
)
691 for(USHORT i
=0;i
<nCurUndoAction
;i
++)
692 aUndoActions
[i
]->Repeat(rTarget
);
695 //------------------------------------------------------------------------
697 BOOL
SfxListUndoAction::CanRepeat(SfxRepeatTarget
&r
) const
699 for(USHORT i
=0;i
<nCurUndoAction
;i
++)
700 if(!aUndoActions
[i
]->CanRepeat(r
))
705 //------------------------------------------------------------------------
707 BOOL
SfxListUndoAction::Merge( SfxUndoAction
*pNextAction
)
709 return aUndoActions
.Count() && aUndoActions
[aUndoActions
.Count()-1]->Merge( pNextAction
);
712 //------------------------------------------------------------------------
714 SfxLinkUndoAction::SfxLinkUndoAction(SfxUndoManager
*pManager
)
717 Richtet eine LinkAction ein, die auf einen weiteren UndoManager zeigt.
718 Holt sich als zugehoerige Action des weiteren UndoManagers dessen
723 pUndoManager
= pManager
;
724 if ( pManager
->GetMaxUndoActionCount() )
726 USHORT nPos
= pManager
->GetUndoActionCount()-1;
727 pAction
= pManager
->pActUndoArray
->aUndoActions
[nPos
];
728 pAction
->SetLinked();
734 //------------------------------------------------------------------------
736 void SfxLinkUndoAction::Undo()
739 pUndoManager
->Undo(1);
742 //------------------------------------------------------------------------
744 void SfxLinkUndoAction::Redo()
747 pUndoManager
->Redo(1);
750 //------------------------------------------------------------------------
753 BOOL
SfxLinkUndoAction::CanRepeat(SfxRepeatTarget
& r
) const
755 return pAction
&& pUndoManager
->CanRepeat(r
,*pAction
);
759 //------------------------------------------------------------------------
762 void SfxLinkUndoAction::Repeat(SfxRepeatTarget
&r
)
765 pUndoManager
->Repeat(r
,*pAction
);
769 //------------------------------------------------------------------------
771 XubString
SfxLinkUndoAction::GetComment() const
774 return pAction
->GetComment();
780 //------------------------------------------------------------------------
782 XubString
SfxLinkUndoAction::GetRepeatComment(SfxRepeatTarget
&r
) const
785 return pAction
->GetRepeatComment(r
);
790 //------------------------------------------------------------------------
792 SfxLinkUndoAction::~SfxLinkUndoAction()
795 pAction
->SetLinked( FALSE
);
799 //------------------------------------------------------------------------
801 SfxUndoArray::~SfxUndoArray()
803 while ( aUndoActions
.Count() )
805 SfxUndoAction
*pAction
=
806 aUndoActions
[ aUndoActions
.Count() - 1 ];
807 aUndoActions
.Remove( aUndoActions
.Count() - 1 );
813 USHORT
SfxLinkUndoAction::GetId() const
815 return pAction
? pAction
->GetId() : 0;