#include "shellprv.h" #pragma hdrstop #include // use a linked list because we're going to be pulling things off the top // and bottom all the time. HDPA s_hdpaUndo = NULL; BOOL s_fUndoSuspended = FALSE; #define MAX_UNDO 10 void NukeUndoAtom(LPUNDOATOM lpua) { lpua->Release( lpua ); LocalFree( lpua ); } void SuspendUndo(BOOL f) { if (f) s_fUndoSuspended++; else s_fUndoSuspended--; ASSERT(s_fUndoSuspended >= 0); // sanity check if (s_fUndoSuspended < 0) s_fUndoSuspended = 0; } void AddUndoAtom(LPUNDOATOM lpua) { int i; ENTERCRITICAL; ASSERT(lpua); if (!s_hdpaUndo) { s_hdpaUndo = DPA_Create(MAX_UNDO + 1); } if (s_hdpaUndo) { i = DPA_AppendPtr(s_hdpaUndo, lpua); if (i != -1) { if (i >= MAX_UNDO) { lpua = DPA_FastGetPtr(s_hdpaUndo, 0); NukeUndoAtom(lpua); DPA_DeletePtr(s_hdpaUndo, 0); } } else { NukeUndoAtom(lpua); } } LEAVECRITICAL; } LPUNDOATOM _PeekUndoAtom(LPINT lpi) { int i = -1; LPUNDOATOM lpua = NULL; ASSERTCRITICAL; if (s_hdpaUndo) { i = DPA_GetPtrCount(s_hdpaUndo) - 1; if (i >= 0) { lpua = DPA_FastGetPtr(s_hdpaUndo, i); } } if (lpi) *lpi = i; return lpua; } void EnumUndoAtoms(int (CALLBACK* lpfn)(LPUNDOATOM lpua, LPARAM lParam), LPARAM lParam) { int i; if (!s_hdpaUndo) { return; } ENTERCRITICAL; for (i = DPA_GetPtrCount(s_hdpaUndo) - 1; i >= 0; i--) { LPUNDOATOM lpua; int iRet; lpua = DPA_FastGetPtr(s_hdpaUndo, i); iRet = lpfn(lpua, lParam); if (iRet & EUA_DELETE) { DPA_DeletePtr(s_hdpaUndo, i); NukeUndoAtom(lpua); } if (iRet & EUA_ABORT) { break; } } LEAVECRITICAL; } #define DoUndoAtom(lpua) ((lpua)->Invoke((lpua))) void Undo(HWND hwnd) { int i; LPUNDOATOM lpua; DECLAREWAITCURSOR; if (!IsUndoAvailable()) { MessageBeep(0); return; } SetWaitCursor(); ENTERCRITICAL; ASSERT(s_hdpaUndo); lpua = _PeekUndoAtom(&i); if (lpua) DPA_DeletePtr(s_hdpaUndo, i); LEAVECRITICAL; if (lpua) { lpua->hwnd = hwnd; DoUndoAtom(lpua); } ResetWaitCursor(); } BOOL IsUndoAvailable() { return s_hdpaUndo && !s_fUndoSuspended && DPA_GetPtrCount(s_hdpaUndo); } #define _GetUndoText(lpua, buffer, cchBuffer, type) (lpua)->GetText((lpua), buffer, cchBuffer, type) // Gets undo information for the first item in the undo buffer // void GetUndoText(LPTSTR lpszBuffer, UINT cchBuffer, int type) { TCHAR szTemp[MAX_PATH * 2 + 80]; TCHAR lpszFormat[MAX_PATH]; // (MAX_PATH is overkill, oh well...) ASSERT(cchBuffer > 0); lpszBuffer[0] = 0; // assume failure szTemp[0] = 0; // While holding onto lpua's from the hdpa, we need to be inside the critical section { LPUNDOATOM lpua; ENTERCRITICAL; lpua = _PeekUndoAtom(NULL); if (lpua) _GetUndoText(lpua, szTemp, ARRAYSIZE(szTemp), type); LEAVECRITICAL; } if (LoadString(HINST_THISDLL, (type == UNDO_MENUTEXT) ? IDS_UNDOACCEL : IDS_UNDO, lpszFormat, ARRAYSIZE(lpszFormat)) != 0) { if (type == UNDO_STATUSTEXT) { // Status text shouldn't have ampersand or tab ASSERT(StrChr(lpszFormat, TEXT('&')) == NULL); ASSERT(StrChr(lpszFormat, TEXT('\t')) == NULL); } wnsprintf(lpszBuffer, cchBuffer, lpszFormat, szTemp); } } void FreeUndoList() { HDPA hdpa; int i; ENTERCRITICAL; hdpa = s_hdpaUndo; s_hdpaUndo = NULL; LEAVECRITICAL; if (hdpa) { for (i = DPA_GetPtrCount(hdpa) - 1; i >= 0; i--) { NukeUndoAtom(DPA_FastGetPtr(hdpa, i)); } DPA_DeleteAllPtrs(hdpa); } }