void SfxUndoAction::Repeat(SfxRepeatTarget&)
{ // These are only conceptually pure virtual
assert(!"pure virtual function called: SfxUndoAction::Repeat()");
}
// Remove entries from the pActUndoArray when we have to reduce // the number of entries due to a lower nMaxUndoActionCount. // Both redo and undo action entries will be removed until we reached the // new nMaxUndoActionCount.
SAL_WARN_IF( ImplIsInListAction_Lock(), "svl", "SfxUndoManager::Clear: suspicious call - do you really wish to clear the current level?" );
ImplClearCurrentLevel_NoNotify( aGuard );
void SfxUndoManager::ImplClearRedo_NoLock( boolconst i_currentLevel )
{ if (IsDoing())
{ // cannot clear redo while undo/redo is in process. Delay ClearRedo until safe to clear. // (assuming if TopLevel requests a clear, it should have priority over CurrentLevel) if (!m_xData->moNeedsClearRedo.has_value() || i_currentLevel == TopLevel)
m_xData->moNeedsClearRedo = i_currentLevel; return;
}
UndoManagerGuard aGuard( *m_xData );
ImplClearRedo( aGuard, i_currentLevel );
}
void SfxUndoManager::ClearRedo()
{
SAL_WARN_IF( IsInListAction(), "svl", "SfxUndoManager::ClearRedo: suspicious call - do you really wish to clear the current level?" );
ImplClearRedo_NoLock( CurrentLevel );
}
ImplCheckEmptyActions(); // notification - only if the top level's stack was cleared if ( i_currentLevel == SfxUndoManager::TopLevel )
i_guard.scheduleNotification( &SfxUndoListener::clearedRedo );
}
if ( ImplIsInListAction_Lock() )
{
assert(!"SfxUndoManager::Undo: not possible when within a list action!"); returnfalse;
}
if ( m_xData->pActUndoArray->nCurUndoAction == 0 )
{
SAL_WARN("svl", "SfxUndoManager::Undo: undo stack is empty!" ); returnfalse;
}
if (i_contextOrNull && i_contextOrNull->GetUndoOffset() > 0)
{
size_t nCurrent = m_xData->pActUndoArray->nCurUndoAction;
size_t nOffset = i_contextOrNull->GetUndoOffset(); if (nCurrent >= nOffset + 1)
{ // Move the action we want to execute to the top of the undo stack. // data() + nCurrent - nOffset - 1 is the start, data() + nCurrent - nOffset is what we // want to move to the top, maUndoActions.data() + nCurrent is past the end/top of the // undo stack.
std::rotate(m_xData->pActUndoArray->maUndoActions.data() + nCurrent - nOffset - 1,
m_xData->pActUndoArray->maUndoActions.data() + nCurrent - nOffset,
m_xData->pActUndoArray->maUndoActions.data() + nCurrent);
}
}
SfxUndoAction* pAction = m_xData->pActUndoArray->maUndoActions[ --m_xData->pActUndoArray->nCurUndoAction ].pAction.get(); const OUString sActionComment = pAction->GetComment(); try
{ // clear the guard/mutex before calling into the SfxUndoAction - this can be an extension-implemented UNO component // nowadays ... auto aResetGuard(aGuard.clear()); if ( i_contextOrNull != nullptr )
pAction->UndoWithContext( *i_contextOrNull ); else
pAction->Undo();
} catch( ... )
{ // in theory, somebody might have tampered with all of *m_xData while the mutex was unlocked. So, see if // we still find pAction in our current Undo array
size_t nCurAction = 0; while ( nCurAction < m_xData->pActUndoArray->maUndoActions.size() )
{ if ( m_xData->pActUndoArray->maUndoActions[ nCurAction++ ].pAction.get() == pAction )
{ // the Undo action is still there ... // assume the error is a permanent failure, and clear the Undo stack
ImplClearUndo( aGuard ); throw;
}
}
SAL_WARN("svl", "SfxUndoManager::Undo: can't clear the Undo stack after the failure - some other party was faster ..." ); throw;
}
m_xData->mbDoing = false; if (m_xData->moNeedsClearRedo.has_value())
{
ImplClearRedo_NoLock(*m_xData->moNeedsClearRedo);
m_xData->moNeedsClearRedo.reset();
}
if ( ImplIsInListAction_Lock() )
{
assert(!"SfxUndoManager::Redo: not possible when within a list action!"); returnfalse;
}
if ( m_xData->pActUndoArray->nCurUndoAction >= m_xData->pActUndoArray->maUndoActions.size() )
{
SAL_WARN("svl", "SfxUndoManager::Redo: redo stack is empty!"); returnfalse;
}
SfxUndoAction* pAction = m_xData->pActUndoArray->maUndoActions[ m_xData->pActUndoArray->nCurUndoAction++ ].pAction.get(); const OUString sActionComment = pAction->GetComment(); try
{ // clear the guard/mutex before calling into the SfxUndoAction - this can be an extension-implemented UNO component // nowadays ... auto aResetGuard(aGuard.clear()); if ( i_contextOrNull != nullptr )
pAction->RedoWithContext( *i_contextOrNull ); else
pAction->Redo();
} catch( ... )
{ // in theory, somebody might have tampered with all of *m_xData while the mutex was unlocked. So, see if // we still find pAction in our current Undo array
size_t nCurAction = 0; while ( nCurAction < m_xData->pActUndoArray->maUndoActions.size() )
{ if ( m_xData->pActUndoArray->maUndoActions[ nCurAction ].pAction.get() == pAction )
{ // the Undo action is still there ... // assume the error is a permanent failure, and clear the Undo stack
ImplClearRedo( aGuard, SfxUndoManager::CurrentLevel ); throw;
}
++nCurAction;
}
SAL_WARN("svl", "SfxUndoManager::Redo: can't clear the Undo stack after the failure - some other party was faster ..." ); throw;
}
m_xData->mbDoing = false;
assert(!m_xData->moNeedsClearRedo.has_value() && "Assuming I don't need to handle it here. What about if thrown?");
ImplCheckEmptyActions();
aGuard.scheduleNotification( &SfxUndoListener::actionRedone, sActionComment );
if ( !m_xData->maUndoArray.nMaxUndoActions ) return;
SfxListUndoAction* pAction = new SfxListUndoAction( rComment, rRepeatComment, nId, nViewShellId, m_xData->pActUndoArray );
OSL_VERIFY( ImplAddUndoAction_NoNotify( std::unique_ptr<SfxUndoAction>(pAction), false, false, aGuard ) ); // expected to succeed: all conditions under which it could fail should have been checked already
m_xData->pActUndoArray = pAction;
if ( !m_xData->maUndoArray.nMaxUndoActions ) return0;
if( !ImplIsInListAction_Lock() )
{
SAL_WARN("svl", "svl::SfxUndoManager::ImplLeaveListAction, called without calling EnterListAction()!" ); return0;
}
assert(m_xData->pActUndoArray->pFatherUndoArray);
// the array/level which we're about to leave
SfxUndoArray* pArrayToLeave = m_xData->pActUndoArray; // one step up
m_xData->pActUndoArray = m_xData->pActUndoArray->pFatherUndoArray;
// If no undo actions were added to the list, delete the list action const size_t nListActionElements = pArrayToLeave->nCurUndoAction; if ( nListActionElements == 0 )
{
i_guard.markForDeletion( m_xData->pActUndoArray->Remove( --m_xData->pActUndoArray->nCurUndoAction ) );
i_guard.scheduleNotification( &SfxUndoListener::listActionCancelled ); return0;
}
// now that it is finally clear the list action is non-trivial, and does participate in the Undo stack, clear // the redo stack
ImplClearRedo( i_guard, SfxUndoManager::CurrentLevel );
SfxUndoAction* pCurrentAction= m_xData->pActUndoArray->maUndoActions[ m_xData->pActUndoArray->nCurUndoAction-1 ].pAction.get();
SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction * >( pCurrentAction );
ENSURE_OR_RETURN( pListAction, "SfxUndoManager::ImplLeaveListAction: list action expected at this position!", nListActionElements );
if ( i_merge )
{ // merge the list action with its predecessor on the same level
SAL_WARN_IF( m_xData->pActUndoArray->nCurUndoAction <= 1, "svl", "SfxUndoManager::ImplLeaveListAction: cannot merge the list action if there's no other action on the same level - check this beforehand!" ); if ( m_xData->pActUndoArray->nCurUndoAction > 1 )
{
std::unique_ptr<SfxUndoAction> pPreviousAction = m_xData->pActUndoArray->Remove( m_xData->pActUndoArray->nCurUndoAction - 2 );
--m_xData->pActUndoArray->nCurUndoAction;
pListAction->SetComment( pPreviousAction->GetComment() );
pListAction->Insert( std::move(pPreviousAction), 0 );
++pListAction->nCurUndoAction;
}
}
// if the undo array has no comment, try to get it from its children if ( pListAction->GetComment().isEmpty() )
{ for( size_t n = 0; n < pListAction->maUndoActions.size(); n++ )
{ if (!pListAction->maUndoActions[n].pAction->GetComment().isEmpty())
{
pListAction->SetComment( pListAction->maUndoActions[n].pAction->GetComment() ); break;
}
}
}
if ((m_xData->mnEmptyMark < i_mark) || (MARK_INVALID == i_mark))
{ return std::numeric_limits<size_t>::max(); // nothing to remove
} elseif (i_mark == m_xData->mnEmptyMark)
{
--m_xData->mnEmptyMark; // never returned from MarkTop => invalid return std::numeric_limits<size_t>::max();
}
for ( size_t i=0; i<m_xData->maUndoArray.maUndoActions.size(); ++i )
{
MarkedUndoAction& rAction = m_xData->maUndoArray.maUndoActions[i]; auto markPos = std::find(rAction.aMarks.begin(), rAction.aMarks.end(), i_mark); if (markPos != rAction.aMarks.end())
{
rAction.aMarks.erase( markPos ); return i;
}
}
SAL_WARN("svl", "SfxUndoManager::RemoveMark: mark not found!"); // TODO: this might be too offensive. There are situations where we implicitly remove marks // without our clients, in particular the client which created the mark, having a chance to know // about this.
void SfxUndoManager::UndoMark(UndoStackMark i_mark)
{
SfxMarkedUndoContext context(*this, i_mark); // Removes the mark if (context.GetUndoOffset() == std::numeric_limits<size_t>::max()) return; // nothing to undo
if ( IsInListAction() && ( m_xData->maUndoArray.nCurUndoAction == 1 ) )
{ // this can happen if we are performing a very large writer edit (e.g. removing a very large table)
SAL_WARN("svl", "SfxUndoManager::RemoveOldestUndoActions: cannot remove a not-yet-closed list action!"); returnfalse;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.