/* * @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

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: * 1. typing another character * 2. backspacing over a character in this merge * typing session. */ HRESULT CReplaceRangeAE::MergeData( DWORD dwDataType, //@parm the type of

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

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; }