Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

552 lines
14 KiB

//------------------------------------------------------------------------------
// undo.cpp
// Copyright (c)1997-1999 Microsoft Corporation, All Rights Reserved
//
// Undo support routines for TriEdit
//
//------------------------------------------------------------------------------
#include "stdafx.h"
#include <ocidl.h>
#include "undo.h"
#include "triedit.h"
#include "document.h"
///////////////////////////////////////////////////////////////////////////////
//
// AddUndoUnit
//
// Add the given undo unit to the given Trident instance. Return S_OK
// or a Trident error code.
//
HRESULT AddUndoUnit(IUnknown* punkTrident, IOleUndoUnit* pioleUndoUnit)
{
HRESULT hr = E_FAIL;
IServiceProvider* piservProv;
IOleUndoManager* pioleUndoManager;
if (punkTrident && pioleUndoUnit)
{
hr = punkTrident->QueryInterface(IID_IServiceProvider, (LPVOID*)&piservProv);
if (SUCCEEDED(hr))
{
_ASSERTE(piservProv);
hr = piservProv->QueryService(IID_IOleUndoManager,
IID_IOleUndoManager, (LPVOID*)&pioleUndoManager);
if (SUCCEEDED(hr))
{
_ASSERTE(pioleUndoManager);
hr = pioleUndoManager->Add(pioleUndoUnit);
_ASSERTE(SUCCEEDED(hr));
pioleUndoManager->Release();
}
piservProv->Release();
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// EmptyUndoRedoStack
//
// If fUndo is TRUE, discard all undo items from the given undo manager.
// If fUndo is FALSE, discard all redo items from the given undo manager
// Return S_OK if all goes well, or a Trident error code otherwise.
//
HRESULT EmptyUndoRedoStack(BOOL fUndo, IOleUndoManager *pUndoManager)
{
CComPtr<IEnumOleUndoUnits> srpEnum;
CComPtr<IOleUndoUnit> srpcd;
ULONG cFetched=0, cTotal=0;
HRESULT hr = E_FAIL;
if (fUndo)
{
if (FAILED(hr = pUndoManager->EnumUndoable(&srpEnum)))
goto Fail;
}
else
{
if (FAILED(hr = pUndoManager->EnumRedoable(&srpEnum)))
goto Fail;
}
while (SUCCEEDED(srpEnum->Next(1, &srpcd, &cFetched)))
{
_ASSERTE(cFetched <=1);
if (srpcd == NULL)
break;
cTotal++;
srpcd.Release();
}
// get the one on top of the stack and discard from that
if (cTotal > 0)
{
if (FAILED(hr = srpEnum->Reset()))
goto Fail;
if (FAILED(hr = srpEnum->Skip(cTotal-1)))
goto Fail;
srpcd.Release();
if (FAILED(hr = srpEnum->Next(1, &srpcd, &cFetched)))
goto Fail;
_ASSERTE(cFetched ==1);
if (FAILED(hr = pUndoManager->DiscardFrom(srpcd)))
goto Fail;
}
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetUndoManager
//
// Obtain and return (under *ppOleUndoManager) the IOleUndoManager
// associated with the given Trident instance. Return S_OK if a
// manager was returned; E_FAIL otherwise.
//
HRESULT GetUndoManager(IUnknown* punkTrident, IOleUndoManager **ppOleUndoManager)
{
HRESULT hr = E_FAIL;
CComPtr<IServiceProvider> srpiservProv;
CComPtr<IOleUndoManager> srpioleUndoManager;
_ASSERTE(ppOleUndoManager != NULL);
_ASSERTE(punkTrident != NULL);
if (punkTrident)
{
hr = punkTrident->QueryInterface(IID_IServiceProvider, (LPVOID*)&srpiservProv);
if (SUCCEEDED(hr))
{
_ASSERTE(srpiservProv);
if (SUCCEEDED(hr = srpiservProv->QueryService(IID_IOleUndoManager,
IID_IOleUndoManager, (LPVOID*)&srpioleUndoManager)))
{
*ppOleUndoManager = srpioleUndoManager;
(*ppOleUndoManager)->AddRef();
}
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndo::CUndo
// CUndo::~Undo
//
// Simple constructor and destructor for the CUndo class.
//
CUndo::CUndo()
{
m_cRef = 1;
m_fUndo = TRUE;
}
CUndo::~CUndo()
{
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndo::QueryInterface (IUnknown method)
// CUndo::AddRef (IUnknown method)
// CUndo::Release (IUnknown method)
//
// Implementations of the three IUnknown methods.
//
STDMETHODIMP CUndo::QueryInterface(REFIID riid, LPVOID* ppvObject)
{
if (!ppvObject)
return E_POINTER;
if (IsEqualGUID(riid, IID_IUnknown))
*ppvObject = (IUnknown*)this;
else
if (IsEqualGUID(riid, IID_IOleUndoUnit))
*ppvObject = (IOleUndoUnit*)this;
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) CUndo::AddRef(void)
{
return InterlockedIncrement((LONG*)&m_cRef);
}
STDMETHODIMP_(ULONG) CUndo::Release(void)
{
ULONG cRef = InterlockedDecrement((LONG*)&m_cRef);
if (!cRef)
delete this;
return cRef;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoDrag::CUndoDrag
// CUndoDrag::~CUndoDrag
//
// Constructor for an object which can undo the drag of an HTML element.
//
CUndoDrag::CUndoDrag(IHTMLStyle* pihtmlStyle, POINT ptOrig, POINT ptMove)
{
m_pihtmlStyle = pihtmlStyle;
if (m_pihtmlStyle)
m_pihtmlStyle->AddRef();
m_ptOrig = ptOrig;
m_ptMove = ptMove;
}
CUndoDrag::~CUndoDrag()
{
SAFERELEASE(m_pihtmlStyle);
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoDrag::Do (IOleUndoUnit method)
//
// Do or undo dragging of an HTML element from place to place. Set or
// restore the item's position. Return S_OK.
//
STDMETHODIMP CUndoDrag::Do(IOleUndoManager *pUndoManager)
{
HRESULT hr = S_OK;
if (pUndoManager)
{
hr = pUndoManager->Add(this);
}
if (m_pihtmlStyle)
{
// We do a put_pixelLeft(-1) and put_pixelTop(-1) below in order
// to work around a Trident problem. Sometimes they don't think
// that anything has changed - these calls below fool them into
// thinking that the values have changed.
if (m_fUndo)
{
m_pihtmlStyle->put_pixelLeft(-1);
m_pihtmlStyle->put_pixelLeft(m_ptOrig.x);
m_pihtmlStyle->put_pixelTop(-1);
m_pihtmlStyle->put_pixelTop(m_ptOrig.y);
}
else
{
m_pihtmlStyle->put_pixelLeft(-1);
m_pihtmlStyle->put_pixelLeft(m_ptMove.x);
m_pihtmlStyle->put_pixelTop(-1);
m_pihtmlStyle->put_pixelTop(m_ptMove.y);
}
m_fUndo = !m_fUndo;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoDrag::GetDescription (IOleUndoUnit method)
//
// Return the description of the undo item. Note that this function
// returns an empty string since this is the only would-be localizable
// content in TriEdit.
//
STDMETHODIMP CUndoDrag::GetDescription(BSTR *pBstr)
{
if (pBstr)
{
*pBstr = SysAllocString(_T(" "));
return S_OK;
}
return E_FAIL;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoDrag::GetUnitType (IOleUndoUnit method)
//
// Return the CLSID and an identifier for the undo item.
//
STDMETHODIMP CUndoDrag::GetUnitType(CLSID *pClsid, LONG *plID)
{
if (pClsid)
*pClsid = UID_TRIEDIT_UNDO;
if (plID)
*plID = TRIEDIT_UNDO_DRAG;
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoDrag::OnNextAdd (IOleUndoUnit method)
//
// Do nothing, but do it extremely well.
//
STDMETHODIMP CUndoDrag::OnNextAdd(void)
{
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoPackManager::~CUndoPackManager
//
// Destructor for a CUndoPackManager object. If currently packing undo
// items, end the packing before destroying the object.
//
CUndoPackManager::~CUndoPackManager(void)
{
if (m_fPacking)
End();
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoPackManager::Start
//
// Called to tell the pack manager to begin accumulating subsequent
// undo units into a unit that can be undone in one fell swoop. Turn
// on the packing flag. Return S_OK if all goes well or E_FAIL if
// something goes wrong.
//
HRESULT CUndoPackManager::Start(void)
{
HRESULT hr = E_FAIL;
CComPtr<IOleUndoManager> srpioleUndoManager;
CComPtr<IEnumOleUndoUnits> srpEnum;
CComPtr<IOleUndoUnit> srpcd;
ULONG cFetched=0;
_ASSERTE(m_indexStartPacking==0);
if (FAILED(hr = GetUndoManager(m_srpUnkTrident, &srpioleUndoManager)))
goto Fail;
if (FAILED(hr = srpioleUndoManager->EnumUndoable(&srpEnum)))
goto Fail;
while(SUCCEEDED(srpEnum->Next(1, &srpcd, &cFetched)))
{
_ASSERTE(cFetched <=1);
if (srpcd == NULL)
break;
m_indexStartPacking++;
srpcd.Release();
}
m_fPacking = TRUE;
Fail:
if (!m_fPacking)
m_indexStartPacking=0;
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoPackManager::End
//
// Called to tell the pack manager to stop accumulating undo units. Pack
// the accumulated undo units in to the parent undo unit and turn off
// the packing flag. Return S_OK if all goes well or E_FAIL if something
// goes wrong.
//
HRESULT CUndoPackManager::End(void)
{
HRESULT hr = E_FAIL;
CUndoPackUnit *pUndoParentUnit;
_ASSERTE(m_srpUnkTrident != NULL);
pUndoParentUnit = new CUndoPackUnit();
_ASSERTE(pUndoParentUnit != NULL);
if (FAILED(hr = pUndoParentUnit->PackUndo(m_indexStartPacking, m_srpUnkTrident)))
goto Fail;
m_fPacking = FALSE;
Fail:
pUndoParentUnit->Release();
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoPackUnit::Do (IOleUndoUnit method)
//
// Invoke the Do method of each undo unit referenced by the object. Return
// S_OK.
//
STDMETHODIMP CUndoPackUnit::Do(IOleUndoManager *pUndoManager)
{
HRESULT hr = S_OK;
for (INT i=sizeof(m_rgUndo)/sizeof(IOleUndoUnit*)-1; i >= 0; i--)
{
if (m_rgUndo[i] == NULL)
continue;
if (FAILED(hr = m_rgUndo[i]->Do(pUndoManager)))
goto Fail;
}
::EmptyUndoRedoStack(FALSE, pUndoManager);
Fail:
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoPackUnit::GetDescription (IOleUndoUnit method)
//
// Return the description of the undo item. Note that this function
// returns an empty string since this string would be one of only
// two localizable strings in TriEdit.
//
STDMETHODIMP CUndoPackUnit::GetDescription(BSTR *pBstr)
{
if (pBstr)
{
// In order to save localization work for the two TriEdit strings,
// it was decided that we would return a blank string here
*pBstr = SysAllocString(_T(" "));
return S_OK;
}
return E_FAIL;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoPackUnit::GetUnitType (IOleUndoUnit method)
//
// Return the CLSID and an identifier for the undo item.
//
STDMETHODIMP CUndoPackUnit::GetUnitType(CLSID *pClsid, LONG *plID)
{
if (pClsid)
*pClsid = UID_TRIEDIT_UNDO;
if (plID)
*plID = TRIEDIT_UNDO_PACK;
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoPackUnit::OnNextAdd (IOleUndoUnit method)
//
// Do nothing, but do it extremely well.
//
STDMETHODIMP CUndoPackUnit::OnNextAdd(void)
{
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// CUndoPackUnit::PackUndo
//
// Pack all of the undo units starting at the given index in to
// the parent undo manager. Return S_OK if all goes well, or
// E_FAIL if something goes wrong.
//
HRESULT CUndoPackUnit::PackUndo(ULONG indexStartPacking, IUnknown *pUnkTrident)
{
HRESULT hr = E_FAIL;
CComPtr<IOleUndoManager> srpioleUndoManager;
CComPtr<IEnumOleUndoUnits> srpEnumUndo;
CComPtr<IOleUndoUnit> rgUndo[cUndoPackMax]; // CONSIDER: allocate dynamically
CComPtr<IOleUndoUnit> srpcd;
ULONG cFetched=0, cUndo=0, i=0;
if (FAILED(hr = GetUndoManager(pUnkTrident, &srpioleUndoManager)))
goto Fail;
if (FAILED(hr = srpioleUndoManager->EnumUndoable(&srpEnumUndo)))
goto Fail;
_ASSERTE(srpEnumUndo != NULL);
while(SUCCEEDED(srpEnumUndo->Next(1, &srpcd, &cFetched)))
{
_ASSERTE(cFetched <= 1);
if (srpcd == NULL)
break;
cUndo++;
srpcd.Release();
}
// if there's nothing to pack
if ((cUndo-indexStartPacking) == 0)
return S_OK;
if ((cUndo-indexStartPacking) > cUndoPackMax)
return E_OUTOFMEMORY;
// get the undo units that we want to pack
if (FAILED(hr = srpEnumUndo->Reset()))
goto Fail;
if (FAILED(hr =srpEnumUndo->Skip(indexStartPacking)))
goto Fail;
if (FAILED(hr = srpEnumUndo->Next(cUndo-indexStartPacking, (IOleUndoUnit **) &m_rgUndo, &cFetched)))
goto Fail;
_ASSERTE(cFetched == (cUndo-indexStartPacking));
// now clear the undo/redo stack and then adds back the undo unit except that one that we just packed
if (FAILED(hr = srpEnumUndo->Reset()))
goto Fail;
if (FAILED(hr = srpEnumUndo->Next(cUndo, (IOleUndoUnit **) &rgUndo, &cFetched)))
goto Fail;
_ASSERTE(cFetched == cUndo);
if (FAILED(hr = srpioleUndoManager->DiscardFrom(NULL)))
goto Fail;
for (i=0; i < indexStartPacking; i++)
{
if (FAILED(hr = srpioleUndoManager->Add(rgUndo[i])))
goto Fail;
}
if (FAILED(hr = ::AddUndoUnit(pUnkTrident, this)))
goto Fail;
Fail:
return hr;
}