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

📄 undo.h

📁 一个完全使用MFC框架开发的C++编译器的代码。功能十分强大可以编译大型程序。
💻 H
字号:
// --------- undo.h
#ifndef UNDO_H
#define UNDO_H

#include <deque>
#include <stack>

namespace DDJCProgrammingColumnUndo	{

//------------------------------------------------------------------------------
// UndoNode<D>: base class for all undo/redo actions

template <class D> class UndoData;

template <class D>
class UndoNode
{
	bool terminator;		// undo action stream terminator
protected:
	explicit UndoNode(bool term) : terminator(term) { }
public:
	virtual ~UndoNode()	{ }
	virtual void Undo(D& doc) = 0;
	virtual void Redo(D& doc) = 0;
	virtual void SetUndoContext(D& doc) = 0;
	bool& Terminator()
		{ return terminator; }
	void* operator new(size_t sz, UndoData<D>* data);
};

//------------------------------------------------------------------------------
// UndoItem: base template class for all undo/redo actions
// D = document class
// T = datum unit of undo action (string, char, etc.)
// P = document position information
// C = document context information
// class D must provide these public functions:
//     void SetUndoContext(C);
//     C GetUndoContext() const;
//     void Delete(P);		// deletes datum at P
//     void Insert(P, T);	// inserts datum T into document just ahead of P
//     void Replace(P, T);	// replaces datum at P with T
//     T GetDatum(P);		// returns datum at P
// classes T and C must support operator=
// classes T, P, and C must have public default constructors
//
template <class D, class T, class P, class C>
class UndoItem : public UndoNode<D>
{
	C context;		// document view context (cursor, e.g.) at time of action
	P position;		// document position of undoable action
	T datum;		// data value
protected:
    UndoItem(D& doc, P pos, bool term) : UndoNode<D>(term), position(pos)
		{ context = doc.GetUndoContext(); }
	void SetUndoContext(D& doc)
	{
		C ctx = context;
		context = doc.GetUndoContext();
		doc.SetUndoContext(ctx);
	}
	P Position() const
		{ return position; }
	T Datum() const
		{ return datum; }
	void SetDatum(T d)
		{ datum = d; }
};
//------------------------------------------------------------------------------
// base class for undoing insertion actions
// instantiate derived class and add to UndoData stack before performing action
//
template <class D, class T, class P, class C>
class UndoInsertNode : public UndoItem<D,T,P,C>
{
public:
	UndoInsertNode(D& doc, P pos, bool term) : UndoItem<D,T,P,C>(doc, pos, term)
		{ }
	void Undo(D& doc)
	{
		// --- save datum for redo
		SetDatum(doc.GetDatum(Position()));
		// ---- undo the insertion
		doc.Delete(Position());
	}
	void Redo(D& doc)
	{
		doc.Insert(Position(), Datum());
	}
};
//------------------------------------------------------------------------------
// base class for undoing deletion actions
// instantiate derived class and add to UndoData stack before performing action
//
template <class D, class T, class P, class C>
class UndoDeleteNode : public UndoItem<D,T,P,C>
{
public:
	UndoDeleteNode(D& doc, P pos, bool term) : UndoItem<D,T,P,C>(doc, pos, term)
	{
		// --- save datum for undo/redo
		T dat = doc.GetDatum(Position());
		SetDatum(dat);
	}
	void Undo(D& doc)
	{
		doc.Insert(Position(), Datum());
	}
	void Redo(D& doc)
	{
		doc.Delete(Position());
	}
};
//------------------------------------------------------------------------------
// base class for undoing replacement actions
// instantiate derived class and add to UndoData stack before performing action
//
template <class D, class T, class P, class C>
class UndoReplaceNode : public UndoItem<D,T,P,C>
{
public:
	UndoReplaceNode(D& doc, P pos, bool term) : UndoItem<D,T,P,C>(doc, pos, term)
	{
		// --- save datum for undo/redo
		SetDatum(doc.GetDatum(Position()));
	}
	void Undo(D& doc)
	{
		T temp = doc.GetDatum(Position());
		doc.Replace(Position(), Datum());
		SetDatum(temp);
	}
	void Redo(D& doc)
		{ Undo(doc); }
};
//------------------------------------------------------------------------------
// base class for storing undo actions
// application derives from this class
//
template <class D>
class UndoData
{
	D& doc;
	bool discardedundos;
	bool undoenabled;
	std::deque<UndoNode<D>*> undodeque;
	std::stack<UndoNode<D>*> redostack;
	int maxundos;
	bool unredoing;
	void DeleteAllRedoActions();
	void DeleteAllUndoActions();
public:
	UndoData(D& doc, int max);
	virtual ~UndoData();
	void AddUndoNode(UndoNode<D>*undonode);	// adds an action that can be undone
	void UndoLastAction();					// undoes the most recent action
	void RedoLastUndo();					// redoes the most recent undo
	void EnableUndo()
		{ undoenabled = true; }
	void DisableUndo()
		{ undoenabled = false; }
	bool IsUndoEnabled() const
		{ return undoenabled && !unredoing; }
    bool IsUndoDataStored() const
		{ return !undodeque.empty(); }
    bool WasUndoDataDiscarded() const
		{ return discardedundos; }
    bool IsRedoDataStored() const
		{ return !redostack.empty(); }
};

template <class D>
UndoData<D>::UndoData(D& doc, int max) : doc(doc), 
		unredoing(false), discardedundos(false), undoenabled(true), maxundos(max)
{
}
template <class D>
UndoData<D>::~UndoData()
{
	DeleteAllUndoActions();
	DeleteAllRedoActions();
}
template <class D>
void UndoData<D>::DeleteAllUndoActions()
{
	while (!undodeque.empty())	{
		delete undodeque.back();
		undodeque.pop_back();
	}
}
template <class D>
void UndoData<D>::DeleteAllRedoActions()
{
	while (!redostack.empty())	{
		delete redostack.top();
		redostack.pop();
	}
}
template <class D>
void UndoData<D>::AddUndoNode(UndoNode<D>* undonode)
{
	if (undonode != 0)	{
		// --- clean up the undos saved for possible redos
		DeleteAllRedoActions();
		// --- prevent the undo deque from growing too large
		if (undodeque.size() >= maxundos)	{
			while (!undodeque.empty() && (undodeque.size() >= maxundos || 
					undodeque.front()->Terminator() == false))	{
				delete undodeque.front();
				undodeque.pop_front();
			}
			if (!undodeque.empty())
				undodeque.front()->Terminator() = true;
			else
				undonode->Terminator() = true;
			discardedundos = true;
		}
		undodeque.push_back(undonode);
	}
}
template <class D>
void UndoData<D>::UndoLastAction()
{
	if (!undodeque.empty())	{
		bool term = false;
		unredoing = true;
		UndoNode<D>* undonode = 0;
		while (!term)	{
			assert(!undodeque.empty());
			undonode = undodeque.back();
			undonode->Undo(doc);
			redostack.push(undonode);
			undodeque.pop_back();
			term = undonode->Terminator();
		}
		undonode->SetUndoContext(doc);
		unredoing = false;
	}
}
template <class D>
void UndoData<D>::RedoLastUndo()
{
	if (!redostack.empty())	{
		bool term = false;
		unredoing = true;
		UndoNode<D>* undonode = 0;
		while (!term)	{
			undonode = redostack.top();
			undonode->Redo(doc);
			undodeque.push_back(undonode);
			redostack.pop();
			// stop if the stack is empty or if the top, unpopped node 
			// (which is the terminating node of the next sequence) has a terminator
			term = redostack.empty() ? true : redostack.top()->Terminator();
		}
		assert(undonode != 0);
		undonode->SetUndoContext(doc);
		unredoing = false;
	}
}
// ---- operator placement new supports undo enable/disable
template <class D>
void* UndoNode<D>::operator new(size_t sz, UndoData<D>* data)
{
	void* p = 0;
	if (data->IsUndoEnabled())
		p = ::operator new (sz);
	return p;
}

} // namespace DDJCProgrammingColumnUndo

#endif

⌨️ 快捷键说明

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