Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1063 lines
25 KiB

/*
* @doc INTERNAL
*
* @module ANTIEVT.C |
*
* Purpose:
* implemenation of common anti-events and a caching mechanism
*
* Author:
* alexgo 3/25/95
*
* Copyright (c) 1995-1997, Microsoft Corporation. All rights reserved.
*/
#include "_common.h"
#include "_m_undo.h"
#include "_antievt.h"
#include "_edit.h"
#include "_range.h"
#include "_select.h"
#include "_format.h"
#include "_coleobj.h"
#include "_objmgr.h"
#ifdef DEBUG
#include "_uspi.h"
#endif
ASSERTDATA
//
// CAntiEventDispenser global instance
//
CAntiEventDispenser gAEDispenser;
//
// CBaseAE PUBLIC methods
//
/*
* CBaseAE::Destroy ()
*
* @mfunc
* sends the Destroy notification to the next anti-event in the list
*/
void CBaseAE::Destroy()
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CBaseAE::Destroy");
;
}
/*
* CBaseAE::Undo (ped, publdr)
*
* @mfunc
* sends the Undo notification to the next anti-event in the list
*
* @rdesc HRESULT
*/
HRESULT CBaseAE::Undo(
CTxtEdit *ped, //@parm the context for this undo operation
IUndoBuilder *publdr) //@parm the undo context.
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CBaseAE::Undo");
return NOERROR;
}
/*
* CBaseAE::OnCommit (ped)
*
* @mfunc called after the anti-event is added to the undo stack
*
* @rdesc void
*/
void CBaseAE::OnCommit(
CTxtEdit *ped) //@parm the edit context
{
;
}
/*
* CBaseAE::MergeData (dwDataType, pdata)
*
* @mfunc simply forwards the merge data request to the next anti-evt
* (if one exists)
*
* @rdesc HRESULT. If S_FALSE, indicates that nothing could be done
* with the merge data.
*/
HRESULT CBaseAE::MergeData(
DWORD dwDataType, //@parm the type of data in <p pdata>
void *pdata) //@parm the merge data
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CBaseAE::MergeData");
return S_FALSE;
}
/*
* CBaseAE::SetNext
*
* @mfunc
* informs this anti-event of the anti-event which should follow it
*/
void CBaseAE::SetNext(
IAntiEvent *pNext) //@parm the AntiEvent to link to
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CBaseAE::SetNext");
_pnext = pNext;
}
/*
* CBaseAE::GetNext
*
* @mfunc
* retrieves the next element (if any)
*
* @rdesc a pointer to the next AntiEvent
*/
IAntiEvent *CBaseAE::GetNext()
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CBaseAE::GetNext");
return _pnext;
}
//
// CBaseAE PROTECTED methods
//
/*
* CBaseAE::CBaseAE()
*
* @mfunc Constructor
*/
CBaseAE::CBaseAE()
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CBaseAE::CBaseAE");
_pnext = NULL;
}
/*
* CReplaceRangeAE::Destroy ()
*
* @mfunc
* deletes this instance
*/
void CReplaceRangeAE::Destroy()
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceRangeAE::Destroy");
if(_paeCF)
{
_paeCF->Destroy();
_paeCF = NULL;
}
if(_paePF)
{
_paePF->Destroy();
_paePF = NULL;
}
CBaseAE::Destroy();
delete this;
}
/*
* CReplaceRangeAE::Undo (ped, publdr)
*
* @mfunc
* undoes a CTxtPtr::ReplaceRange operation
*
* @comm
* Algorithm:
*
* A replace range works as follows: delete n characters and in their
* place, put m characters.
*
* To undo this, we delete m characters and restore the n that were
* originally deleted. Note that we restore the n characters with
* default formatting. If there was any other formatting to those
* characters, a separate anti-event (CReplaceFormattingAE) will
* apply the correct formatting.
*/
HRESULT CReplaceRangeAE::Undo(
CTxtEdit *ped, //@parm Context for this undo operation
IUndoBuilder *publdr) //@parm Undo context
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceRangeAE::Undo");
CRchTxtPtr rtp(ped, _cpMin);
LONG cchMove = 0;
rtp.ReplaceRange(_cpMax - _cpMin,
_cchDel,
_pchDel,
publdr,
-1,
&cchMove,
RR_NO_EOR_CHECK | RR_ITMZ_NONE); // RAID 6554
// Passing NULL for the publdr is *extremely* important
// below. The rich text pointer ReplaceRange call will
// already generate the appropriate anti-events for any
// deleted formatting, so we do not need to repeat that here.
if(_paeCF)
_paeCF->Undo(ped, NULL);
if(_paePF)
_paePF->Undo(ped, NULL);
if (ped->IsComplexScript())
{
// For complex script doc, we need itemization at the end of the range undo.
// Since the formattings were rolled back. The rtp's runptrs are no longer
// reliable.
if (_paeCF && rtp._rpCF.IsValid())
rtp._rpCF.BindToCp(_cpMin + _cchDel);
if (_paePF && rtp._rpPF.IsValid())
rtp._rpPF.BindToCp(_cpMin + _cchDel);
rtp.ItemizeReplaceRange(_cchDel, cchMove, NULL, FALSE);
}
return CBaseAE::Undo(ped, publdr);
}
/*
* CReplaceRangeAE::MergeData (dwDataType, pdata)
*
* @mfunc gives the caller a chance to extend the current anti-event
* if we're in merge typing mode
*
* @comm if the requested data can be trivially merged into this
* anti-event, then do so; otherwise, return S_FALSE.
*
* There are two cases of interest: <nl>
* 1. typing another character
* 2. backspacing over a character in this merge
* typing session.
*/
HRESULT CReplaceRangeAE::MergeData(
DWORD dwDataType, //@parm the type of <p pdata>
void *pdata) //@parm the merge data
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceRangeAE::MergeData");
if(dwDataType == MD_SIMPLE_REPLACERANGE)
{
SimpleReplaceRange *psr = (SimpleReplaceRange *)pdata;
// Test for first case: just typing another character
if(psr->cpMin == _cpMax && psr->cchDel == 0)
{
_cpMax = psr->cpMax;
return NOERROR;
}
// Second case: deleting text stored in this antievent
if (psr->cpMax == psr->cpMin &&
psr->cpMin + psr->cchDel == _cpMax &&
psr->cpMin >= _cpMin)
{
_cpMax = psr->cpMax;
return NOERROR;
}
}
return S_FALSE;
}
/*
* CReplaceRangeAE::CReplaceRangeAE (cpMin, cpMax, cchDel, pchDel, paeCF, paePF)
*
* @mfunc Constructor for a text replace range anti-event
*/
CReplaceRangeAE::CReplaceRangeAE(
LONG cpMin, //@parm cp starting the *final* range
LONG cpMax, //@parm cp ending the *final* range
LONG cchDel, //@parm # of chars deleted during ReplaceRange
TCHAR *pchDel, //@parm deleted characters. Ownership of
// memory is transferred to this object.
IAntiEvent *paeCF, //@parm Anti-event for any character formatting
// replacement
IAntiEvent *paePF) //@parm Anti-event for any paragraph formatting
// replacement
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceRangeAE::CReplaceRangeAE");
_cpMin = cpMin;
_cpMax = cpMax;
_cchDel = cchDel;
_pchDel = pchDel;
_paeCF = paeCF;
_paePF = paePF;
}
/*
* CReplaceRangeAE::~CReplaceRangeAE ()
*
* @mfunc Destructor
*/
CReplaceRangeAE::~CReplaceRangeAE()
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceRangeAE::~CReplaceRangeAE");
if(_pchDel)
delete _pchDel;
}
/*
* CReplaceFormattingAE
*
* @mfunc Destroys this instance
*/
void CReplaceFormattingAE::Destroy()
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceFormattingAE::Destroy");
CBaseAE::Destroy();
delete this;
}
/*
* CReplaceFormattingAE::Undo (ped, publdr)
*
* @mfunc Undoes a formatting operation
*
* @devnote This anti-event assumes that the text to which formatting
* should be applied exists!!
*/
HRESULT CReplaceFormattingAE::Undo(
CTxtEdit *ped, //@parm CTxtEdit closure
IUndoBuilder *publdr) //@parm Undo builder context
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceFormattingAE::Undo");
LONG cchEaten;
LONG cchTotal = 0;
LONG delta;
LONG i;
LONG iRunMerge;
IAntiEvent * pae;
IFormatCache * pf = _fPara
? (IFormatCache *)GetParaFormatCache()
: (IFormatCache *)GetCharFormatCache();
CNotifyMgr * pnm = ped->GetNotifyMgr();
CFormatRuns ** ppfmtruns;
CTxtStory * pStory = ped->GetTxtStory();
const CParaFormat * pDefPF = _fPara ? pStory->GetParaFormat(-1) : NULL;
BYTE bDefPFLevel = pDefPF && pDefPF->IsRtlPara() ? 1 : 0;
// First set things up correctly for whether we are paragraph
// or character formatting
CFormatRunPtr rp(_fPara ? pStory->GetPFRuns() :pStory->GetCFRuns());
// Count up count of characters affected
for(i = 0 ; i < _cRuns; i++)
cchTotal += _prgRuns[i]._cch;
// We are going to be adding in some runs, so be sure the format
// run array is allocated!
if(!rp.IsValid())
{
ppfmtruns = _fPara ? &(pStory->_pPFRuns) : &(pStory->_pCFRuns);
if(!rp.InitRuns(0, ped->GetTextLength(), ppfmtruns))
return E_OUTOFMEMORY;
// tell folks we allocated a new run
if(pnm)
pnm->NotifyPostReplaceRange(NULL, CP_INFINITE, 0, 0, CP_INFINITE, CP_INFINITE);
}
// Now do a pre-notification of the change we are about to make
// This let's objects like a delayed render data object grab
// any data *before* we change it.
rp.BindToCp(_cp);
// do a little more checking
AssertNr(rp.CalcTextLength() == ped->GetTextLength());
if(pnm)
pnm->NotifyPreReplaceRange(NULL, CP_INFINITE, 0, 0, _cp, _cp + cchTotal);
// We want to merge runs with where we start plus one behind.
iRunMerge = rp._iRun;
if(iRunMerge > 0)
iRunMerge--;
// if we need to be able to undo this opertion, go through and
// save existing run information
if(publdr)
{
LONG cchBackup = 0, cchAdvance = 0;
if (ped->IsBiDi())
{
// For redo'ing purpose, we expand the range to keep in the antievent
// to make sure that BiDi levels are recorded adequately.
CRchTxtPtr rtp(ped, _cp);
cchBackup = rtp.ExpandRangeFormatting(cchTotal, 0, cchAdvance);
Assert(cchBackup >= 0);
}
rp.AdvanceCp(-cchBackup);
pae = gAEDispenser.CreateReplaceFormattingAE(ped, rp, cchTotal + cchBackup + cchAdvance,
pf, _fPara);
rp.AdvanceCp(cchBackup);
if(pae)
publdr->AddAntiEvent(pae);
}
#ifdef DEBUG
CTxtPtr rtp(ped, _cp);
WCHAR ch;
#endif
// Now go through and apply the saved formatting.
for(i = 0; i < _cRuns; i++)
{
cchEaten = 0;
// Use a do-while, because we may have a zero-length
// format run. We know we need to do "something" at
// least once, because otherwise, we would not have
// bothered creating a run!
do
{
if (_fPara && _prgRuns[i]._iFormat == -1)
// (#6768) The -1 format may have changed before undoing.
_prgRuns[i]._level._value = bDefPFLevel;
delta = rp.SetFormat(_prgRuns[i]._iFormat,
_prgRuns[i]._cch - cchEaten, pf, &_prgRuns[i]._level);
if(delta == -1)
{
ped->GetCallMgr()->SetOutOfMemory();
break;
}
cchEaten += delta;
} while(cchEaten < _prgRuns[i]._cch);
#ifdef DEBUG
if (_fPara)
{
rtp.AdvanceCp(_prgRuns[i]._cch);
ch = rtp.GetPrevChar();
if(!IsASCIIEOP(ch))
{
rtp.MoveGapToEndOfBlock(); // Make it easier to see
AssertSz(FALSE, // what's going on
"CReplaceFormattingAE::Undo: PF run doesn't end with EOP");
}
}
#endif
}
// Merge formatting runs in case there are duplicate formatting
// runs side by side
rp.NextRun();
rp.MergeRuns(iRunMerge, pf);
// Make sure the runs are still OK.
AssertNr(rp.CalcTextLength() == ped->GetTextLength());
if(pnm)
pnm->NotifyPostReplaceRange(NULL, CP_INFINITE, 0, 0, _cp, _cp + cchTotal);
ped->GetCallMgr()->SetChangeEvent(CN_GENERIC);
return CBaseAE::Undo(ped, publdr);
}
/*
* CReplaceFormattingAE::CReplaceFormattingAE(&rpIn, cch, pf, fPara)
*
* @mfunc Constructor. During construction, we will loop through and
* find all of the formats for the given text range
*/
CReplaceFormattingAE::CReplaceFormattingAE(
CTxtEdit *ped, //@parm CTxtEdit
CFormatRunPtr &rpIn, //@parm Run pointer to start with
LONG cch, //@parm Count of characters to
// find formatting info on
IFormatCache *pf, //@parm Format cache (to AddRef/
// Release formats)
BOOL fPara) //@parm If TRUE, formatting is for paras
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceFormattingAE::CReplaceFormattingAE");
LONG cchLeft;
LONG cchtemp = (LONG)cch;
LONG i;
CFormatRunPtr rp(rpIn); // We use 2 format run pointers to avoid
CFormatRunPtr rpTemp(rpIn); // backing up after counting the number of
// format runs
Assert(pf);
// TODO: pass in cp as a parameter to avoid following calculation
_cp = rpIn.CalculateCp();
_fPara = fPara;
// Count the number of formats needed. Recall that even
// if 0 characters are to be deleted, we may still be
// "deleting" a zero length format run.
_cRuns = 0;
do
{
_cRuns++;
cchLeft = rp.GetCchLeft();
cchtemp -= min(cchLeft, cchtemp);
rp.NextRun();
} while(cchtemp > 0);
_prgRuns = new CFormatRun[_cRuns];
if(!_prgRuns)
{
_cRuns = 0;
return;
}
// Would be nice to add this but ped is not passed in
// CTxtPtr rtp(ped, _cp);
// WCHAR ch;
for(i = 0; i < _cRuns; i++)
{
_prgRuns[i]._cch = min(cch, rpTemp.GetCchLeft());
CFormatRun *pRun = rpTemp.GetRun(0);
_prgRuns[i]._iFormat = pRun->_iFormat;
_prgRuns[i]._level = pRun->_level;
pf->AddRef(_prgRuns[i]._iFormat);
rpTemp.NextRun();
cch -= _prgRuns[i]._cch;
#if 0
// Would be nice dor DEBUG but ped is not passed in
if (_fPara)
{
rtp.AdvanceCp(_prgRuns[i]._cch);
ch = rtp.GetPrevChar();
if(!IsASCIIEOP(ch))
{
rtp.MoveGapToEndOfBlock(); // Make it easier to see
AssertSz(FALSE, // what's going on
"CReplaceFormattingAE::CReplaceFormattingAE: PF run doesn't end with EOP");
}
}
#endif
}
Assert(cch == 0);
}
/*
* CReplaceFormattingAE::~CReplaceFormattingAE ()
*
* @mfunc Destructor
*/
CReplaceFormattingAE::~CReplaceFormattingAE()
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceFormattingAE::~CReplaceFormattingAE");
IFormatCache * pf = _fPara
? (IFormatCache *)GetParaFormatCache()
: (IFormatCache *)GetCharFormatCache();
if(_prgRuns)
{
if(pf)
{
for(LONG i = 0; i < _cRuns; i++)
pf->Release(_prgRuns[i]._iFormat);
}
delete _prgRuns;
}
}
//
// CReplaceObjectAE PUBLIC methods
//
/*
* CReplaceObjectAE::Destroy()
*
* @mfunc Destroy's this object
*/
void CReplaceObjectAE::Destroy()
{
COleObject *pobj;
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceObjectAE::Destroy");
pobj = _pobj;
_pobj = NULL;
// we only need to zombie the object if it wasn't put back into
// the document.
if(!_fUndoInvoked)
pobj->MakeZombie();
pobj->Release();
CBaseAE::Destroy();
delete this;
}
/*
* CReplaceObjectAE::Undo (ped, publdr)
*
* @mfunc Undo'es the delete operation and restores the object
* to it's original state
*
* @rdesc HRESULT
*/
HRESULT CReplaceObjectAE::Undo(
CTxtEdit *ped, //@parm edit context
IUndoBuilder *publdr) //@parm undo/redo context
{
CObjectMgr *pobjmgr;
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceObjectAE::Undo");
pobjmgr = ped->GetObjectMgr();
if(_pobj && pobjmgr)
{
_fUndoInvoked = TRUE;
_pobj->Restore();
pobjmgr->RestoreObject(_pobj);
}
return CBaseAE::Undo(ped, publdr);
}
/*
* CReplaceObjectAE::OnCommit(ped)
*
* @mfunc called when the anti-event chain is committed to the
* undo stack. This gives us a chance to make 'dangerous'
* calls that could cause us to be re-entered.
*/
void CReplaceObjectAE::OnCommit(
CTxtEdit *ped) //@parm the edit context
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceObjectAE::OnCommit");
_pobj->Close(OLECLOSE_SAVEIFDIRTY);
}
//
// CReplaceObjectAE PRIVATE methods
//
/*
* CReplaceObjectAE::CReplaceObjectAE (pobj)
*
* @mfunc constructor
*/
CReplaceObjectAE::CReplaceObjectAE(
COleObject *pobj) //@parm object that was deleted
{
_fUndoInvoked = FALSE;
_pobj = pobj;
_pobj->AddRef();
}
/*
* CReplaceObjectAE::~CReplaceObjectAE
*
* @mfunc destructor
*/
CReplaceObjectAE::~CReplaceObjectAE()
{
Assert(_pobj == NULL);
}
//
// CResizeObjectAE PUBLIC methods
//
/*
* CResizeObjectAE::Destroy
*
* @mfunc Destroy's this object
*/
void CResizeObjectAE::Destroy(void)
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CResizeObjectAE::Destroy");
_pobj = NULL;
CBaseAE::Destroy();
delete this;
}
/*
* CResizeObjectAE::Undo(ped, publdr)
*
* @mfunc Undo'es the resize operation and restores the object
* to it's original size/position
*
* @rdesc HRESULT
*/
HRESULT CResizeObjectAE::Undo(
CTxtEdit *ped, //@parm edit context
IUndoBuilder *publdr) //@parm undo/redo context
{
CObjectMgr *pobjmgr;
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceObjectAE::Undo");
pobjmgr = ped->GetObjectMgr();
if(_pobj && pobjmgr)
{
_fUndoInvoked = TRUE;
_pobj->Resize(_rcPos);
}
return CBaseAE::Undo(ped, publdr);
}
/*
* CResizeObjectAE::OnCommit
*
* @mfunc called when the anti-event chain is committed to the
* undo stack. This gives us a chance to make 'dangerous'
* calls that could cause us to be re-entered.
*/
void CResizeObjectAE::OnCommit(
CTxtEdit *ped) //@parm the edit context
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CReplaceObjectAE::OnCommit");
}
//
// CResizeObjectAE PRIVATE methods
//
/*
* CResizeObjectAE::CResizeObjectAE (pobj, rcPos)
*
* @mfunc constructor
*
* @rdesc void
*/
CResizeObjectAE::CResizeObjectAE(
COleObject *pobj, //@parm the object that was resized
RECT rcPos) //@parm the old position/size rect
{
_fUndoInvoked = FALSE;
_pobj = pobj;
_rcPos = rcPos;
}
/*
* CResizeObjectAE::~CResizeObjectAE
*
* @mfunc destructor
*/
CResizeObjectAE::~CResizeObjectAE(void)
{
Assert(_pobj == NULL);
}
//
// CSelectionAE PUBLIC methods
//
/*
* CSelectionAE::Destroy ()
*
* @mfunc gets rid of this instance
*
* @rdesc void
*/
void CSelectionAE::Destroy()
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CSelectionAE::Destroy");
CBaseAE::Destroy();
delete this;
}
/*
* CSelectionAE::Undo (ped, publdr)
*
* @mfunc restore the selection to it's former position
*
* @rdesc NOERROR
*/
HRESULT CSelectionAE::Undo(
CTxtEdit *ped, //@parm the context for this undo operation
IUndoBuilder *publdr) //@parm the undo context
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CSelectionAE::Destroy");
CTxtSelection *psel = ped->GetSel();
if(psel)
psel->SetDelayedSelectionRange(_cp, _cch);
if(publdr)
{
IAntiEvent *pae;
pae = gAEDispenser.CreateSelectionAE(ped, _cpNext, _cchNext,
_cp, _cch);
if(pae)
publdr->AddAntiEvent(pae);
}
return CBaseAE::Undo(ped, publdr);
}
/*
* CSelectionAE::MergeData(dwDataType, pdata)
*
* @mfunc merges new selection data
*
* @rdesc S_FALSE, NOERROR
*
* @comm The mergine algorithm is fairly tricky. There are basically two
* cases of interest: group typing and drag-move.
*
* In the group typing case, the "start" of the typing becomes a
* fixed reference from which characters are added or removed (i.e.
* you type or hit the backspace key). "Undo" should return you to
* that reference point; redo, on the other hand, should return the
* selection to the last insertion point. Thus, we only update
* _xxNext for the SELAE_MERGE action.
*
* Drag-Move is somewhat different; in this case, there are really
* two actions--the "paste" on the drop, and the subsequent "cut"
* operation. Thus, we need to be able to update the selection
* anti-event during the cut (since this only happens on move; not
* copies). This is accomplished with teh FORCEREPLACE flag
* and by setting fields to -1 to be ignored.
*
*/
HRESULT CSelectionAE::MergeData(
DWORD dwDataType, //@parm the type of data in <p pdata>
void *pdata) //@parm the merge data
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CSelectionAE::MergeData");
SelRange *psrg = (SelRange *)pdata;
if(dwDataType == MD_SELECTIONRANGE)
{
if(psrg->flags == SELAE_MERGE)
{
Assert(psrg->cpNext != -1);
_cpNext = psrg->cpNext;
_cchNext = psrg->cchNext;
}
else
{
// -1 is used a no-op, so we should ignore it
if(psrg->cp != -1)
{
_cp = psrg->cp;
_cch = psrg->cch;
}
if(psrg->cpNext != -1)
{
_cpNext = psrg->cpNext;
_cchNext = psrg->cchNext;
}
}
return NOERROR;
}
return S_FALSE;
}
//
// CSelectionAE PRIVATE methods
//
/*
* CSelectionAE::CSelectionAE (cp, cch, cpNext, cchNext)
*
* @mfunc Constructor
*/
CSelectionAE::CSelectionAE(
LONG cp, //@parm the actve end cp
LONG cch, //@parm the signed extension
LONG cpNext, //@parm the cp to use for the AE of this AE
LONG cchNext) //@parm the cch for the AE of this AE
{
_cp = cp;
_cch = cch;
_cpNext = cpNext;
_cchNext = cchNext;
}
/*
* CSelectionAE::~CSelectionAE()
*
* @mfunc desctructor
*/
CSelectionAE::~CSelectionAE()
{
;
}
/*
* CAntiEventDispenser::CreateReplaceRangeAE(ped, cpMin, cpMax, cchDel,
* pchDel, paeCF, paePF)
* @mfunc
* creates an anti-event for a replace range operation
*/
IAntiEvent * CAntiEventDispenser::CreateReplaceRangeAE(
CTxtEdit *ped, //@parm edit context
LONG cpMin, //@parm cp starting the *final* range
LONG cpMax, //@parm cp ending the *final* range
LONG cchDel, //@parm # of chars deleted during ReplaceRange
TCHAR *pchDel, //@parm Deleted characters. Ownership of
// memory is transferred to this object.
IAntiEvent *paeCF, //@parm Anti-event for any character formatting
// replacement
IAntiEvent *paePF) //@parm Anti-event for any paragraph formatting
// replacement
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CAntiEventDispenser::CreateReplaceRangeAE");
// FUTURE (alexgo): improve the efficiency of this routine!!
IAntiEvent *pae;
pae = (IAntiEvent *)(new CReplaceRangeAE(cpMin, cpMax, cchDel, pchDel,
paeCF, paePF));
if(!pae)
{
// we don't need to do anything else; the callmgr will discard
// undo for us.
ped->GetCallMgr()->SetOutOfMemory();
}
return pae;
}
/*
* CAntiEventDispenser::CreateReplaceFormattingAE(ped, &rp, cch, pf, fPara)
*
* @mfunc Creates an anti-event for replacing formatting
*/
IAntiEvent * CAntiEventDispenser::CreateReplaceFormattingAE(
CTxtEdit *ped, //@parm Edit context
CFormatRunPtr &rp, //@parm Run pointer to start with
LONG cch, //@parm Countof characters to
// find formatting info on
IFormatCache *pf, //@parm Format cache (to AddRef/
//Release formats)
BOOL fPara) //@parm If TRUE, formatting is paragraphs
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN, "CAntiEventDispenser::CreateReplaceFormattingAE");
// FUTURE (alexgo): improve the efficiency of this routine!!!
IAntiEvent *pae;
pae = (IAntiEvent *)(new CReplaceFormattingAE(ped, rp, cch, pf, fPara));
if(!pae)
{
// We don't need to do anything else; the callmgr will discard
// undo for us.
ped->GetCallMgr()->SetOutOfMemory();
}
return pae;
}
/*
* CAntiEventDispenser::CreateReplaceObjectAE (ped, pobj)
*
* @mfunc Creates an anti-event for replacing an object
*
* @rdesc the created anti-event
*/
IAntiEvent * CAntiEventDispenser::CreateReplaceObjectAE(
CTxtEdit *ped, //@parm the edit context.
COleObject *pobj) //@parm the object that was deleted
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN,
"CAntiEventDispenser::CreateReplaceObjectAE");
IAntiEvent *pae;
// Always allocating is probably a reasonable strategy for objects;
// they are not expected to be the bread & butter case.
pae = (IAntiEvent *)(new CReplaceObjectAE(pobj));
if(!pae)
{
// We don't need to do anything else; the callmgr will discard
// undo for us.
ped->GetCallMgr()->SetOutOfMemory();
}
return pae;
}
/*
* CAntiEventDispenser::CreateResizeObjectAE (ped, pobj, rcPos)
*
* @mfunc Creates an anti-event for resizing an object
*
* @rdesc the created anti-event
*/
IAntiEvent * CAntiEventDispenser::CreateResizeObjectAE(
CTxtEdit *ped, //@parm the edit context.
COleObject *pobj, //@parm the object that was resized
RECT rcPos) //@parm the old object position rectangle
{
TRACEBEGIN(TRCSUBSYSUNDO, TRCSCOPEINTERN,
"CAntiEventDispenser::CreateResizeeObjectAE");
IAntiEvent *pae;
// Always allocating is probably a reasonable strategy for objects;
// they are not expected to be the bread & butter case.
pae = (IAntiEvent *)(new CResizeObjectAE(pobj, rcPos));
if(!pae)
{
// We don't need to do anything else; the callmgr will discard
// undo for us.
ped->GetCallMgr()->SetOutOfMemory();
}
return pae;
}
/*
* CAntiEventDispenser::CreateSelectionAE (ped, cp, cch, cpNext, cchNext)
*
* @mfunc Creates an anti-event for restoring a non-degenerate selection
*
* @rdesc the created anti-event
*/
IAntiEvent * CAntiEventDispenser::CreateSelectionAE(
CTxtEdit *ped, //@parm edit context
LONG cp, //@parm the active end of the selection
LONG cch, //@parm the signed extension
LONG cpNext, //@parm the cp to use for the AE of this AE
LONG cchNext) //@parm the cch to use for the AE
{
// FUTURE (alexgo): improve the efficiency of this routine
IAntiEvent *pae;
pae = (IAntiEvent *)(new CSelectionAE(cp, cch, cpNext, cchNext));
if(!pae)
{
// We don't need to do anything else; the callmgr will discard
// undo for us.
ped->GetCallMgr()->SetOutOfMemory();
}
return pae;
}