|
|
/*
* @doc INTERNAL * * @module PROPCHG.CPP -- Property Change Notification Routines | * * Original Author: <nl> * Rick Sailor * * History: <nl> * 9/5/95 ricksa Created and documented * * Documentation is generated straight from the code. The following * date/time stamp indicates the version of code from which the * the documentation was generated. * * Copyright (c) 1995-1997 Microsoft Corporation. All rights reserved. */ #include "_common.h"
#include "_edit.h"
#include "_dispprt.h"
#include "_dispml.h"
#include "_dispsl.h"
#include "_select.h"
#include "_text.h"
#include "_runptr.h"
#include "_font.h"
#include "_measure.h"
#include "_render.h"
#include "_urlsup.h"
ASSERTDATA
CTxtEdit::FNPPROPCHG CTxtEdit::_fnpPropChg[MAX_PROPERTY_BITS];
/*
* CTxtEdit::UpdateAccelerator() * * @mfunc * Get accelerator cp from host * * @rdesc * HRESULT * * @devnote: * The point of this is to leave the accelerator offset unchanged * in the face of an error from the host. */ HRESULT CTxtEdit::UpdateAccelerator() { TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::UpdateAccelerator"); LONG cpAccel; HRESULT hr = _phost->TxGetAcceleratorPos(&cpAccel);
if(SUCCEEDED(hr)) { // It worked so reset our value
AssertSz(cpAccel < 32768, "CTxtEdit::UpdateAccelerator: cp too large"); _cpAccelerator = cpAccel; } return hr; }
/*
* CTxtEdit::HandleRichToPlainConversion() * * @mfunc * Convert a rich text object to a plain text object */ void CTxtEdit::HandleRichToPlainConversion() { TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::HandleRichToPlainConversion");
// Notify every interested party that they should dump their formatting
_nm.NotifyPreReplaceRange(NULL, CONVERT_TO_PLAIN, 0, 0, 0, 0);
// Set _fRich to false so we can delete the final CRLF.
_fRich = 0; _fSelChangeCharFormat = 0;
// if(_pdetecturl)
// {
// delete _pdetecturl;
// _pdetecturl = NULL;
// }
// Tell document to dump its format runs
_story.DeleteFormatRuns();
// Clear out the ending CRLF
CRchTxtPtr rtp(this, 0); rtp.ReplaceRange(GetTextLength(), 0, NULL, NULL, -1);
}
/*
* CTxtEdit::OnRichEditChange (fPropertyFlag) * * @mfunc * Notify text services that rich-text property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnRichEditChange( BOOL fPropertyFlag) //@parm New state of richedit flag
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnRichEditChange");
// Calculate length of empty document. Remember that multiline rich text
// controls always have and end of paragraph marker.
LONG cchEmptyDoc = cchCR; CFreezeDisplay fd(_pdp); // defer screen update until we finish the change.
if(!_fRich) cchEmptyDoc = 0; else if(_f10Mode) cchEmptyDoc = cchCRLF;
// This can only be changed if there is no text and nothing to undo.
// It makes no sense to change when there is already text. This is
// particularly true of going from rich to plain. Further, what would
// you do with the undo state?
if(GetTextLength() == cchEmptyDoc && (!_pundo || !_pundo->CanUndo())) { #ifdef DEBUG
// Make sure that document is in a sensible state.
if(_fRich) { CTxtPtr tp(this, 0); WCHAR szBuf[cchCRLF];
tp.GetText(cchCRLF, &szBuf[0]); AssertSz(szBuf[0] == CR && (!_f10Mode || szBuf[1] == LF), "CTxtEdit::OnRichEditChange: invalid document terminator"); } #endif // DEBUG
if(_fRich && !fPropertyFlag) { // Going from rich text to plain text. Need to dump
// format runs.
HandleRichToPlainConversion(); _fAutoFontSizeAdjust = TRUE; } else if (!_fRich && fPropertyFlag) { // Going from plain text to rich text. Need to add the
// appropriate EOP at the end of the document.
SetRichDocEndEOP(0); _fAutoFontSizeAdjust = FALSE; } _fRich = fPropertyFlag; return S_OK; } return E_FAIL; // Flag was not updated
}
/*
* CTxtEdit::OnTxMultiLineChange (fMultiline) * * @mfunc * Notify text services that the display changed. * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnTxMultiLineChange( BOOL fMultiLine) { TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxMultiLineChange");
BOOL fHadSelection = (_psel != NULL); CDisplay * pSavedDisplay; BOOL fOldShowSelection = FALSE;
// Remember the old value for show selection
if (fHadSelection) fOldShowSelection = _psel->GetShowSelection();
// Save the current display away and null it out
pSavedDisplay = _pdp; _pdp = NULL;
// Attempt to create the new display
if (fMultiLine) _pdp = new CDisplayML(this); else _pdp = new CDisplaySL(this); Assert(_pdp);
if(!_pdp) { Assert(pSavedDisplay); _pdp = pSavedDisplay; return E_OUTOFMEMORY; }
// Attempt to init the new display
if(pSavedDisplay) _pdp->InitFromDisplay(pSavedDisplay);
if(!_pdp->Init()) { delete _pdp; Assert(pSavedDisplay); _pdp = pSavedDisplay; return E_FAIL; }
// Ok to now kill the old display
delete pSavedDisplay;
// Is there are selection?
if(_psel) { // Need to tell it there is a new display to talk to.
_psel->SetDisplay(_pdp); }
// Is this a switch to Single Line? If this is we need to
// make sure we truncate the text to the first EOP. We wait
// till this point to do this check to make sure that everything
// is in sync before doing something which potentially affects
// the display and the selection.
if(!fMultiLine) { // Set up for finding an EOP
CTxtPtr tp(this, 0);
tp.FindEOP(tomForward);
// Is there any EOP and text beyond?
if (tp.GetCp() < GetAdjustedTextLength()) { // FindEOP places the text after the EOP if there
// is one. Since we want to delete the EOP as well
// we need to back up to the EOP.
tp.BackupCpCRLF();
// Sync up the cp's of all the ranges before deleting
// the text.
CRchTxtPtr rtp(this, tp.GetCp());
// Truncate from the EOP to the end of the document
rtp.ReplaceRange(GetAdjustedTextLength() - tp.GetCp(), 0, NULL, NULL, -1); } } _pdp->UpdateView(); if(fHadSelection && _fFocus && fOldShowSelection) _psel->ShowSelection(TRUE);
return S_OK; }
/*
* CTxtEdit::OnTxReadOnlyChange (fReadOnly) * * @mfunc * Notify text services that read-only property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnTxReadOnlyChange( BOOL fReadOnly) //@parm TRUE = read only, FALSE = not read only
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxReadOnlyChange");
if (fReadOnly) _ldte.ReleaseDropTarget();
_fReadOnly = fReadOnly; // Cache bit
return S_OK; }
/*
* CTxtEdit::OnShowAccelerator (fPropertyFlag) * * @mfunc * Update accelerator based on change * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnShowAccelerator( BOOL fPropertyFlag) //@parm TRUE = show accelerator
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnShowAccelerator");
// Get the new accelerator character
HRESULT hr = UpdateAccelerator();
// Update the view - we update even in the face of an error return.
// The point is that errors will be rare (non-existent?) and the update
// will work even in the face of the error so why bother conditionalizing
// the execution.
NeedViewUpdate(TRUE);
return hr; }
/*
* CTxtEdit::OnUsePassword (fPropertyFlag) * * @mfunc * Update use-password property * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnUsePassword( BOOL fPropertyFlag) //@parm TRUE = use password character
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnUsePassword");
Assert((DWORD)fPropertyFlag <= 1); // Be sure it's C boolean
_fUsePassword = fPropertyFlag; _pdp->UpdateView(); // State changed so update view
return S_OK; }
/*
* CTxtEdit::OnTxHideSelectionChange (fHideSelection) * * @mfunc * Notify text services that hide-selection property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnTxHideSelectionChange( BOOL fHideSelection) //@parm TRUE = hide selection
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxHideSelectionChange");
// update internal flag if selection is to be hidden
_fHideSelection = fHideSelection;
if (!_fFocus) OnHideSelectionChange(fHideSelection); return S_OK; }
/*
* CTxtEdit::OnHideSelectionChange (fHideSelection) * * @mfunc * Performs the actual hide selection. Helper to OnTxHideSelectionChange * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnHideSelectionChange( BOOL fHideSelection) //@parm TRUE = hide selection
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnHideSelectionChange");
_fHideSelection = fHideSelection; CTxtSelection * psel = GetSel(); if(psel) { psel->ShowSelection(!fHideSelection);
// In the case where we don't have focus we don't want to allow the user to display the caret but it's okay
// to hide the caret.
if (_fFocus || fHideSelection) psel->ShowCaret(!fHideSelection); }
if(!_fInPlaceActive) { TxInvalidateRect(NULL, FALSE); // Since _fInPlaceActive = FALSE,
TxUpdateWindow(); // this only tells user.exe to
} // send a WM_PAINT message
return S_OK; }
/*
* CTxtEdit::OnSaveSelection (fPropertyFlag) * * @mfunc * Notify text services that save-selection property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnSaveSelection( BOOL fPropertyFlag) //@parm TRUE = save selection when inactive
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnSaveSelection");
return S_OK; }
/*
* CTxtEdit::OnAutoWordSel (fPropertyFlag) * * @mfunc * Notify text services that auto-word-selection property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnAutoWordSel( BOOL fPropertyFlag) //@parm TRUE = auto word selection on
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnAutoWordSel");
// We call back to the host when we need to know, so we don't bother doing
// anything in response to this notification.
return S_OK; }
/*
* CTxtEdit::OnTxVerticalChange (fVertical) * * @mfunc * Notify text services that vertical property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnTxVerticalChange( BOOL fVertical) //@parm TRUE - text vertically oriented.
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxVerticalChange");
// We pretend like something actually happened.
GetCallMgr()->SetChangeEvent(CN_GENERIC); return S_OK; }
/*
* CTxtEdit::OnClientRectChange (fPropertyFlag) * * @mfunc * Notify text services that client rectangle changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnClientRectChange( BOOL fPropertyFlag) //@parm Ignored for this property
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnClientRectChange");
// It is unclear whether we need to actually do anything for this
// notification. Logically, the change of this property is followed
// closely by some kind of operation which will cause the display
// cache to be updated anyway. The old code is left here as an
// example of what might be done if it turns out we need to do
// anything. For now, we will simply return S_OK to this notification.
#if 0
if (_fInPlaceActive) { RECT rc;
if(_phost->TxGetClientRect(&rc) == NOERROR) _pdp->OnClientRectChange(rc);
return S_OK; }
return NeedViewUpdate(fPropertyFlag); #endif // 0
// With a client rect change we do need to update the caret when
// we get redrawn even if the basic information did not change.
_pdp->SetUpdateCaret();
return S_OK; }
/*
* CTxtEdit::OnCharFormatChange (fPropertyFlag) * * @mfunc * Update default CCharFormat * * @rdesc * S_OK - update successfully processed. */ HRESULT CTxtEdit::OnCharFormatChange( BOOL fPropertyFlag) //@parm Not used
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnCharFormatChange");
CCharFormat CF; DWORD dwMask;
HRESULT hr = TxGetDefaultCharFormat(&CF, dwMask); if(hr == NOERROR) { DWORD dwMask2 = CFM2_CHARFORMAT; WPARAM wparam = SCF_ALL;
if(!GetAdjustedTextLength()) { dwMask2 = CFM2_CHARFORMAT | CFM2_NOCHARSETCHECK; wparam = 0; }
// OnSetCharFormat handles updating the view.
hr = OnSetCharFormat(wparam, &CF, NULL, dwMask, dwMask2) ? NOERROR : E_FAIL; } return hr; }
/*
* CTxtEdit::OnParaFormatChange (fPropertyFlag) * * @mfunc * Update default CParaFormat * * @rdesc * S_OK - update successfully processed * * @devnote * Because Forms^3 doesn't set cbSize correctly, we limit this API * to PARAFORMAT (until they fix it). */ HRESULT CTxtEdit::OnParaFormatChange( BOOL fPropertyFlag) //@parm Not used
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnParaFormatChange");
CParaFormat PF;
HRESULT hr = TxGetDefaultParaFormat(&PF); if(hr == NOERROR) { // OnSetParaFormat handles updating the view.
hr = OnSetParaFormat(SPF_SETDEFAULT, &PF, NULL, PFM_ALL2) ? NOERROR : E_FAIL; } #ifdef TABS
GetTabsCache()->Release(PF._iTabs); #endif
return hr; }
/*
* CTxtEdit::NeedViewUpdate (fPropertyFlag) * * @mfunc * Notify text services that view of data changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::NeedViewUpdate( BOOL fPropertyFlag) { TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::NeedViewUpdate");
_pdp->UpdateView(); return S_OK; }
/*
* CTxtEdit::OnTxBackStyleChange (fPropertyFlag) * * @mfunc * Notify text services that background style changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnTxBackStyleChange( BOOL fPropertyFlag) //@parm Ignored for this property
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxBackStyleChange");
_fTransparent = (TxGetBackStyle() == TXTBACK_TRANSPARENT); TxInvalidateRect(NULL, FALSE); return S_OK; }
/*
* CTxtEdit::OnAllowBeep (fPropertyFlag) * * @mfunc * Notify text services that beep property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnAllowBeep( BOOL fPropertyFlag) //@parm New state of property
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnAllowBeep");
_fAllowBeep = fPropertyFlag; return S_OK; }
/*
* CTxtEdit::OnMaxLengthChange (fPropertyFlag) * * @mfunc * Notify text services that max-length property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnMaxLengthChange( BOOL fPropertyFlag) //@parm New state of property
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnMaxLengthChange");
// Query host for max text length
DWORD length = CP_INFINITE; _phost->TxGetMaxLength(&length); _cchTextMost = length;
return S_OK; }
/*
* CTxtEdit::OnWordWrapChange (fPropertyFlag) * * @mfunc * Notify text services that word-wrap property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnWordWrapChange( BOOL fPropertyFlag) //@parm TRUE = do word wrap
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnWordWrapChange");
_pdp->SetWordWrap(fPropertyFlag);
// Update was successful so we need the screen updated at some point
_pdp->UpdateView(); return S_OK; }
/*
* CTxtEdit::OnDisableDrag (fPropertyFlag) * * @mfunc * Notify text services that disable drag property changed * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnDisableDrag( BOOL fPropertyFlag) //@parm New state of property
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnDisableDrag");
_fDisableDrag = fPropertyFlag; return S_OK; }
/*
* CTxtEdit::OnScrollChange (fPropertyFlag) * * @mfunc * Notify text services scroll property change * * @rdesc * S_OK - Notification successfully processed. */ HRESULT CTxtEdit::OnScrollChange( BOOL fPropertyFlag) //@parm New state of property
{ TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnScrollChange");
// Tell the display that scroll bars for sure need to be updated
_pdp->SetViewChanged();
// Tell the display to update itself.
_pdp->UpdateView();
return S_OK; }
|