/* * CRchTxtPtr::InitRunPtrs(cp) * * @mfunc * Initialize Run Ptrs of this rich-text ptr to correspond to * document given by ped and to cp given by cp. */ void CRchTxtPtr::InitRunPtrs( LONG cp) // @parm character position to move RunPtrs to { TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::InitRunPtrs"); CTxtStory *pStory; AssertSz(GetPed(), "RTP::InitRunPtrs: illegal GetPed()"); if( IsRich() || IsIMERich() ) { pStory = GetPed()->GetTxtStory(); if(pStory->_pCFRuns) // and there's RichData, { // initialize format-run ptrs _rpCF.SetRunArray((CRunArray *)pStory->_pCFRuns); _rpCF.BindToCp(cp); } if (pStory->_pPFRuns) { _rpPF.SetRunArray((CRunArray *)pStory->_pPFRuns); _rpPF.BindToCp(cp); } } }
// Window procedure WXLRESULT ExtTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { // if we're richtext and read-only, block ctrl-l, -e, -r key strokes if (IsRich()) { if (nMsg == WM_KEYDOWN) { char c = LOWORD(MapVirtualKey(wParam, 2)); if (c == 'R' || c == 'L' || c == 'E') { if (GetKeyState(VK_CONTROL) < 0) return 0; } if (GetKeyState(VK_CONTROL) < 0) { if (wParam == VK_UP) { return myKeyHandler ? myKeyHandler->OnArrowUpDown(true) : 0; } else if (wParam == VK_DOWN) { return myKeyHandler ? myKeyHandler->OnArrowUpDown(false) : 0; } } else if (wParam == ' ') if (myKeyHandler) return myKeyHandler->OnSpace(); } } if (!IsRich()) { if (nMsg == WM_CHAR) { if (wParam == 1) { SetSelection(-1, -1); return 0; } } } // inherited behaviour return wxTextCtrl::MSWWindowProc(nMsg, wParam, lParam); }
/* * CRchTxtPtr::Check_rpPF() * * @mfunc * enable _rpPF if it's not already enabled * * @rdesc * TRUE if _rpPF is enabled */ BOOL CRchTxtPtr::Check_rpPF() { TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::Check_rpPF"); if(_rpPF.IsValid()) return TRUE; if( !IsRich() ) return FALSE; if( !_rpPF.InitRuns (GetCp(), GetTextLength(), &(GetPed()->GetTxtStory()->_pPFRuns)) ) { return FALSE; } CNotifyMgr *pnm = GetPed()->GetNotifyMgr(); // For notifying of changes if( pnm ) pnm->NotifyPostReplaceRange( // Notify interested parties (ITxNotify *)this, INFINITE, // of the change. 0, 0, INFINITE, INFINITE); return TRUE; }
/* * CRchTxtPtr::ReplaceRange(cchOld, cchNew, *pch, pcpFirstRecalc, publdr, * iFormat) * @mfunc * Replace a range of text at this text pointer using CCharFormat iFormat * and updating other text runs as needed * * @rdesc * Count of new characters added * * @devnote * Moves this text pointer to end of replaced text. * May move text block and formatting arrays. */ LONG CRchTxtPtr::ReplaceRange( LONG cchOld, // @parm length of range to replace // (<lt> 0 means to end of text) LONG cchNew, // @parm length of replacement text TCHAR const *pch, // @parm replacement text IUndoBuilder *publdr, // @parm CCharFormat iFormat to use for cchNew LONG iFormat) { TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::ReplaceRange"); LONG cch; LONG cchEndEOP = 0; // Default 0 final EOP fixup LONG cchMove = 0; // Default nothing to move LONG cchNextEOP = cchOld; // cch to next EOP LONG cchPrevEOP = 0; // cch back to previous EOP LONG cpFR; // between PF runs LONG cpSave = GetCp(); LONG cpFormatMin = cpSave; // Used for notifications LONG cpFormat = cpSave; // Will add cchOld, maybe cchMove IAntiEvent * paeCF = NULL; IAntiEvent * paePF = NULL; CNotifyMgr * pnm; CObjectMgr * pobjmgr; _TEST_INVARIANT_ LONG cchEnd = GetTextLength() - GetCp(); if(cchOld < 0) cchOld = cchEnd; if(IsRich() && cchOld == cchEnd) // Attempting to delete up { // thru final EOP cchEndEOP = (GetPed()->Get10Mode()) // Calc cch of final EOP ? CCH_EOD_10 : CCH_EOD_20; if(cchEndEOP <= cchOld) // Don't delete it unless cchOld -= cchEndEOP; // converting from 2.0 } else if(_rpPF.IsValid() && cchOld) // If PARAFORMATs are enabled, { // get tp and rp at end of CFormatRunPtr rp(_rpPF); // range. Need bounding para CTxtPtr tp(_rpTX); // counts to save valid PF BOOL fIsAtBOP; // for undo tp.AdvanceCp(cchOld); rp.AdvanceCp(cchOld); cch = 0; if(tp.IsAfterEOP()) // Range ends with an EOP: { // get EOP length by cch = -tp.BackupCpCRLF(); // backing up over it tp.AdvanceCp(cch); // Advance past EOP } cchNextEOP = tp.FindEOP(tomForward); // Get cch up to next EOP fIsAtBOP = !GetCp() || _rpTX.IsAfterEOP(); if (!fIsAtBOP && cch == cchOld && // Deleting EOP alone before !rp.GetIch()) // new PARAFORMAT run start { // in para with more than EOP cchMove = cchNextEOP; // Need to move chars up to cpFormat += cchMove; // end of next para for } cchNextEOP += cchOld; // Count from GetCp() to EOP tp.SetCp(GetCp()); // Back to this ptr's _cp if(!fIsAtBOP) cchPrevEOP = tp.FindEOP(tomBackward);// Get cch to start of para // If deleting from within one format run up to or into another, set // up to move last para in starting format run into the run following // the deleted text if(rp.GetFormat() != _rpPF.GetFormat() // Change of format during && !fIsAtBOP && !cchMove) // deleted text not starting { // at BOP cchMove = cchPrevEOP; // Get cch to start of para cpFormatMin += cchMove; // in this ptr's run for } // moving into rp's run } Assert(cchNew >= 0 && cchOld >= 0); if(!(cchNew + cchOld)) // Nothing to do (note: all return 0; // these cch's are >= 0) // Handle pre-replace range notifications. This method is very // useful for delayed rendering of data copied to the clipboard. pnm = GetPed()->GetNotifyMgr(); if( pnm ) { pnm->NotifyPreReplaceRange((ITxNotify *)this, cpSave, cchOld, cchNew, cpFormatMin, cpFormat + cchOld); } if(iFormat >= 0) Check_rpCF(); // Get rid of objects first. This let's us guarantee that when we // insert the objects as part of an undo, the objects themselves are // restored _after_ their corresponding WCH_EMBEDDINGs have been // added to the backing store. if(GetObjectCount()) { pobjmgr = GetPed()->GetObjectMgr(); Assert(pobjmgr); pobjmgr->ReplaceRange(cpSave, cchOld, publdr); } if( ( IsRich() || IsIMERich() ) && iFormat != tomUndefined) // Rich text enabled { // The anti-events used below are a bit tricky (paeCF && paePF). // Essentially, this call, CRchTxtPtr::ReplaceRange generates one // 'combo' anti-event composed of up to two formatting AE's plus // the text anti-event. These anti-events are combined together // to prevent ordering problems during undo/redo. cpFR = ReplaceRangeFormatting(cchOld + cchEndEOP, cchNew + cchEndEOP, iFormat, publdr, &paeCF, &paePF, cchMove, cchPrevEOP, cchNextEOP); if (cchEndEOP) { // If we added in the EOP we need to back up by the EOP so // that the invariants don't get annoyed and the richtext object // doesn't get out of sync. _rpCF.AdvanceCp(-cchEndEOP); _rpPF.AdvanceCp(-cchEndEOP); } if(cpFR < 0) { Tracef(TRCSEVERR, "ReplaceRangeFormatting(%ld, %ld, %ld) failed", GetCp(), cchOld, cchNew); cch = 0; goto Exit; } } // As noted above in the call to ReplaceRangeFormatting, the anti-events // paeCF and paePF, if non-NULL, were generated by ReplaceRangeFormatting. // In order to solve ordering problems, the anti-event generated by this // method is actually a combo anti-event of text && formatting AE's. cch = _rpTX.ReplaceRange(cchOld, cchNew, pch, publdr, paeCF, paePF); if (cch != cchNew) { Tracef(TRCSEVERR, "_rpTX.ReplaceRange(%ld, %ld, ...) failed", cchOld, cchNew); // Boy, out of memory or something bad. Dump our formatting and hope // for the best. // // FUTURE: (alexgo) degrade more gracefully than loosing formatting // info. // Notify every interested party that they should dump their formatting if( pnm ) { pnm->NotifyPreReplaceRange(NULL, CONVERT_TO_PLAIN, 0, 0, 0, 0); } // Tell document to dump its format runs GetPed()->GetTxtStory()->DeleteFormatRuns(); goto Exit; } AssertSz(!_rpPF.IsValid() || _rpPF.GetIch() || !GetCp() || _rpTX.IsAfterEOP(), "CRchTxtPtr::ReplaceRange: EOP not at end of PF run"); // BUGBUG!! (alexgo) doesn't handle correctly the case where things fail // (due to out of memory or whatever). See also notes in CTxtPtr::HandleReplaceRange // Undo. The assert below is therefore somewhat bogus, but if it fires, // then our floating ranges are going to be in trouble until we fix // up the logic here. Assert(cch == cchNew); Exit: #ifdef DEBUG // test the invariant again before calling out to replace range notification; // in this way, we can catch bugs earlier. The invariant has its own // scope for convenience. if( 1 ) { _TEST_INVARIANT_ } #endif if( pnm ) { pnm->NotifyPostReplaceRange((ITxNotify *)this, cpSave, cchOld, cch, cpFormatMin, cpFormat + cchOld); } GetPed()->GetCallMgr()->SetChangeEvent(CN_TEXTCHANGED); return cch; }