⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 m_undo.cpp

📁 Windows CE 6.0 Word Application 源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		{
			j = _dwLim - 1;
		}
		else
		{
			j--;
		}
	}

	return UID_UNKNOWN;
}

/*
 *	CUndoStack::GetMergeAntiEvent (void)
 *
 *	@mfunc	If we are in merge typing mode, then return the topmost
 *			anti-event
 *
 *	@rdesc	NULL or the current AntiEvent if in merge mode
 */
IAntiEvent *CUndoStack::GetMergeAntiEvent(void)
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::GetMergeAntiEvent");

	DWORD i;

	if( _fMerge == TRUE )
	{
		i = GetPrev();	// _index by default points to the next available
						// slot

		Assert(_prgActions[i].pae);		//can't be in merge anti event mode
										//if there is no anti-event to merge
										//with!!!

		return _prgActions[i].pae;
	}
	return NULL;
}

/*
 *	CUndoStack::GetTopAECookie
 *
 *	@mfunc	Returns a cookie to the topmost anti-event.
 *
 *	@rdesc	A cookie value.  Note that this cookie is just the anti-event
 *			pointer, but clients shouldn't really know that.
 */		
 DWORD CUndoStack::GetTopAECookie( void )
 {
 	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::GetTopAECookie");

	DWORD i = GetPrev();

	return (DWORD)_prgActions[i].pae;
}


/*
 *	CUndoStack::ClearAll ()
 *
 *	@mfunc
 *		removes any anti-events that are currently in the undo stack
 */

void CUndoStack::ClearAll( void )
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::ClearAll");

	DWORD i;	 
 	for( i = 0; i < _dwLim; i++ )
	{
		if( _prgActions[i].pae != NULL )
		{
			DestroyAEList(_prgActions[i].pae);
			_prgActions[i].pae = NULL;
		}
	}

	// just in case we've been grouping typing; clear the
	// state.
	StopGroupTyping();
}

/*
 *	CUndoStack::CanUndo
 *
 *	@mfunc
 *		indicates whether or not can undo operation can be performed
 *		(in other words, are there any anti-events in our buffer)
 *
 *	@rdesc
 *		TRUE	-- anti-events exist 	<nl>
 *		FALSE 	-- no anti-events		<nl>
 */
BOOL CUndoStack::CanUndo()
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::CanUndo");

	DWORD i = GetPrev();	// _index by default points to the next available
							// slot

	if( _prgActions[i].pae != NULL )
	{
		return TRUE;
	}
	else if( _fSingleLevelMode )
	{
		// if fSingleLevelMode is on, we can't be the redo stack
		Assert(_fRedo == FALSE);

		// if we are in single level mode, we are the undo stack.  Check to
		// see if the redo stack can do something here.
		if( _ped->GetRedoMgr() )
		{
			return _ped->GetRedoMgr()->CanUndo();
		}
	}

	return FALSE;
}

/*
 *	CUndoStack::StartGroupTyping
 *
 *	@mfunc
 *		TOGGLES the group typing flag on.  If fGroupTyping is set, then
 *		all *typing* events will be merged together
 *
 *	@comm
 *	Algorithm:
 *
 *		There are three interesting states:	<nl>
 *			-no group merge; every action just gets pushed onto the stack <nl>
 *			-group merge started; the first action is pushed onto the stack<nl>
 *			-group merge in progress; every action (as long as it's "typing")
 *			is merged into the prior state	<nl>
 *
 *		See the state diagram in the implemenation doc for more details
 */

void CUndoStack::StartGroupTyping()
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::StartGroupTyping");

	if( _fGroupTyping == TRUE )
	{
		_fMerge = TRUE;
	}
	else
	{
		Assert(_fMerge == FALSE);
		_fGroupTyping = TRUE;
	}
}

/*
 *	CUndoStack::StopGroupTyping
 *
 *	@mfunc
 *		TOGGLES the group typing flag off.  If fGroupTyping is not set,
 *		then no merging of typing anti-events will be done
 */

void CUndoStack::StopGroupTyping()
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::StopGroupTyping");

	_fGroupTyping = FALSE;
	_fMerge = FALSE;
}

/*
 *	CUndoStack::EnableSingleLevelMode
 *
 *	@mfunc	Turns on single level undo mode; in this mode, we behave just like
 *			RichEdit 1.0 w.r.t. to Undo.
 *
 *	@comm	This special mode means that undo is 1 level deep and everything 
 *			is accessed via UNDO messages.  Thus, instead of redo to undo an 
 *			undo action, you simply use another undo message. 
 *
 *	@devnote	This call is _ONLY_ allowed for the UndoStack; the redo 
 *			stack simply tags along.  Note that caller is responsible for
 *			ensuring that we are in an empty state.
 */
HRESULT CUndoStack::EnableSingleLevelMode()
{
	Assert(_ped->GetRedoMgr() == NULL || 
		_ped->GetRedoMgr()->CanUndo() == FALSE);
	Assert(CanUndo() == FALSE);
	Assert(_fRedo == FALSE);

	_fSingleLevelMode = TRUE;

	// for single level undo mode, it is very important to get
	// just 1 entry in the undo stack.  If we can't do that,
	// then we better just fail.
	if( SetUndoLimit(1) != 1 )
	{
		_fSingleLevelMode = FALSE;
		return E_OUTOFMEMORY;
	}

	if( _ped->GetRedoMgr() )
	{
		// doesn't matter if the redo manager fails to reset
		_ped->GetRedoMgr()->SetUndoLimit(1);
	}

	return NOERROR;
}

/*
 *	CUndoStack::DisableSingleLevelMode
 *
 *	@mfunc	This turns off the 1.0 undo compatibility mode and restores us to 
 *			the RichEdit 2.0 default undo state
 */
void CUndoStack::DisableSingleLevelMode()
{
	Assert(_ped->GetRedoMgr() == NULL || 
		_ped->GetRedoMgr()->CanUndo() == FALSE);
	Assert(CanUndo() == FALSE);
	Assert(_fRedo == FALSE);

	_fSingleLevelMode = FALSE;

	// we don't care about failures here; multi-level undo mode
	// can handle any sized undo stack
	SetUndoLimit(DEFAULT_UNDO_SIZE);

	if( _ped->GetRedoMgr() )
	{
		// doesn't matter if the redo manager can't grow back in
		// size; it just means that we won't have full redo capability.
		_ped->GetRedoMgr()->SetUndoLimit(DEFAULT_UNDO_SIZE);
	}
}

//
// PRIVATE METHODS
//

/*
 *	CUndoStack::Next
 *
 *	@mfunc
 *		sets _index to the next available slot
 */
void CUndoStack::Next( void )
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::Next");

	_index++;
	
	if( _index == _dwLim )
	{	
		_index = 0;
	}
}

/*
 *	CUndoStack::Prev
 *
 *	@mfunc
 *		sets _index to the previous slot
 */
void CUndoStack::Prev( void )
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::Prev");

	_index = GetPrev();
}

/*
 *	CUndoStack::GetPrev
 *
 *	@mfunc
 *		figures out what the index to the previous slot
 *		*should* be (but does not set it)
 *
 *	@rdesc	the index of what the previous slot would be
 */

DWORD CUndoStack::GetPrev( void )
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::GetPrev");

	DWORD i = _index;

	if( i == 0 )
	{
		i = _dwLim - 1;
	}
	else
	{
		i--;
	}

	return i;
}

/*
 *	CUndoStack::IsCookieInList
 *
 *	@mfunc	
 *		determines whether or not the given DoTo cookie is in
 *		the list of anti-events.
 *
 *	@rdesc	TRUE/FALSE
 */
BOOL CUndoStack::IsCookieInList(
	IAntiEvent *pae,		//@parm	the list to check
	IAntiEvent *paeCookie)	//@parm the cookie to check
{
	while( pae )
	{
		if( pae == paeCookie )
		{
			return TRUE;
		}

		pae = pae->GetNext();
	}
	return FALSE;
}

/*
 *	CUndoStack::TransferToNewBuffer
 *
 *	@mfunc	
 *		transfers existing anti-events to the given buffer and
 *		swaps this undo stack to use the new buffer
 *
 *	@rdesc	void
 *
 *	@comm	The algorithm is very straightforward; go backwards in
 *			the ring buffer copying antievents over until either there
 *			are no more anti-events or the new buffer is full.  Discard
 *			any remaining anti-events.
 */
void CUndoStack::TransferToNewBuffer(UndoAction *prgnew, DWORD dwLimNew)
{
	TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CUndoStack::TransferToNewBuffer");

	DWORD 	iOld = 0, 
			iNew = 0,
			iCopyStart = 0;

	// first, clear the new buffer.
	memset(prgnew, 0, dwLimNew * sizeof(UndoAction));

	// if there is nothing to copy, don't bother

	if( NULL == _prgActions || NULL == _prgActions[GetPrev()].pae )
	{
		goto SetState;
	}

	// this is a bit counter-intuitive, but since the stack is really
	// a ring buffer, go *forwards* until you hit a non-NULL slot.
	// This will be the _end_ of the existing antievents.
	//
	// However, we need to make sure that if dwLimNew is 
	// _smaller_ than _dwLim we only copy the final dwLimNew
	// anti-events.  We'll set iCopyStart to indicate when
	// we can start copying stuff.

	if( dwLimNew < _dwLim )
	{
		iCopyStart = _dwLim - dwLimNew;
	}

	for(; iOld < _dwLim; iOld++, Next() )
	{
		if( NULL == _prgActions[_index].pae )
		{
			continue;
		}
		else if( iOld >= iCopyStart )
		{
			Assert(iNew < dwLimNew );
			// copy anti-events over 
			prgnew[iNew] = _prgActions[_index];
			iNew++;
		}
		else
		{
			// otherwise, get rid of them
			DestroyAEList(_prgActions[_index].pae);
			_prgActions[_index].pae = NULL;
		}
	}

SetState:
	
	//we start at index iNew
	_index = (iNew == dwLimNew ) ? 0 : iNew;
	Assert(iNew <= dwLimNew);

	_dwLim = dwLimNew;
	
	if( _prgActions )
	{
		delete _prgActions;
	}
	_prgActions = prgnew;
}	

//
//	CGenUndoBuilder implementation
//

//
//	Public methods
//

/*
 *	CGenUndoBuilder::CGenUndoBuilder (pstack)
 *
 *	@mfunc	Constructor
 *
 *	@comm
 *		This is a *PUBLIC* constructor
 *	
 */

CGenUndoBuilder::CGenUndoBuilder( 
	CTxtEdit *ped, 			//@parm	the overall context
	DWORD flags) :			//@parm flags (usually UB_AUTOCOMMIT)

	_fAutoCommit(1),
	_pfirstae(NULL)
	
{
	CompName	name = COMP_UNDOBUILDER;
	CCallMgr *	pcallmgr = ped->GetCallMgr();

	_idName		= UID_UNKNOWN;
	_ped 		= ped;
	_pfirstae 	= NULL;
	_fStartGroupTyping = FALSE;
	_fRedo		= FALSE;
	_fDontFlushRedo = FALSE;

	if( (flags & UB_AUTOCOMMIT) )
	{
		_fAutoCommit = TRUE;
	}

	if( (flags & UB_REDO) )
	{
		_fRedo = TRUE;
		name = COMP_REDOBUILDER;
		_pundo = ped->GetRedoMgr();
	}
	else
	{
		_pundo = ped->GetUndoMgr();
	}

	if( (flags & UB_DONTFLUSHREDO) )
	{
		_fDontFlushRedo = TRUE;
	}

#ifdef PWD_JUPITER // GuyBark Jupiter 18411: Don't attempt to merge events during an undo
    _bNoAttemptToMerge = FALSE;
#endif //  PWD_JUPITER

	// now link ourselves to any undobuilders that are higher up on
	// the stack.  Note that is is legal for multiple undo builders
	// to live within the same call context.

	_publdrPrev = (CGenUndoBuilder *)_ped->GetCallMgr()->GetComponent(name);

	// If we are in the middle of an undo, then we'll have two undo stacks
	// active, the undo stack and the redo stack.  Don't like the two
	// together.
	if( _fDontFlushRedo )
	{
		_publdrPrev = NULL;
	}

	_ped->GetCallMgr()->RegisterComponent((IReEntrantComponent *)this,
							name);
}

/*
 *	CGenUndoBuilder::~CGenUndoBuilder
 *
 *	@mfunc	Destructor

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -