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.

695 lines
16 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module PROPCHG.CPP -- Property Change Notification Routines |
  5. *
  6. * Original Author: <nl>
  7. * Rick Sailor
  8. *
  9. * History: <nl>
  10. * 9/5/95 ricksa Created and documented
  11. *
  12. * Documentation is generated straight from the code. The following
  13. * date/time stamp indicates the version of code from which the
  14. * the documentation was generated.
  15. *
  16. * Copyright (c) 1995-1997 Microsoft Corporation. All rights reserved.
  17. */
  18. #include "_common.h"
  19. #include "_edit.h"
  20. #include "_dispprt.h"
  21. #include "_dispml.h"
  22. #include "_dispsl.h"
  23. #include "_select.h"
  24. #include "_text.h"
  25. #include "_runptr.h"
  26. #include "_font.h"
  27. #include "_measure.h"
  28. #include "_render.h"
  29. #include "_urlsup.h"
  30. ASSERTDATA
  31. CTxtEdit::FNPPROPCHG CTxtEdit::_fnpPropChg[MAX_PROPERTY_BITS];
  32. /*
  33. * CTxtEdit::UpdateAccelerator()
  34. *
  35. * @mfunc
  36. * Get accelerator cp from host
  37. *
  38. * @rdesc
  39. * HRESULT
  40. *
  41. * @devnote:
  42. * The point of this is to leave the accelerator offset unchanged
  43. * in the face of an error from the host.
  44. */
  45. HRESULT CTxtEdit::UpdateAccelerator()
  46. {
  47. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::UpdateAccelerator");
  48. LONG cpAccel;
  49. HRESULT hr = _phost->TxGetAcceleratorPos(&cpAccel);
  50. if(SUCCEEDED(hr))
  51. {
  52. // It worked so reset our value
  53. AssertSz(cpAccel < 32768,
  54. "CTxtEdit::UpdateAccelerator: cp too large");
  55. _cpAccelerator = cpAccel;
  56. }
  57. return hr;
  58. }
  59. /*
  60. * CTxtEdit::HandleRichToPlainConversion()
  61. *
  62. * @mfunc
  63. * Convert a rich text object to a plain text object
  64. */
  65. void CTxtEdit::HandleRichToPlainConversion()
  66. {
  67. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::HandleRichToPlainConversion");
  68. // Notify every interested party that they should dump their formatting
  69. _nm.NotifyPreReplaceRange(NULL, CONVERT_TO_PLAIN, 0, 0, 0, 0);
  70. // Set _fRich to false so we can delete the final CRLF.
  71. _fRich = 0;
  72. _fSelChangeCharFormat = 0;
  73. _fPageView = 0;
  74. // if(_pdetecturl)
  75. // {
  76. // delete _pdetecturl;
  77. // _pdetecturl = NULL;
  78. // }
  79. // Tell document to dump its format runs
  80. _story.DeleteFormatRuns();
  81. // Clear out the ending CRLF
  82. CRchTxtPtr rtp(this, 0);
  83. rtp.ReplaceRange(GetTextLength(), 0, NULL, NULL, -1);
  84. }
  85. /*
  86. * CTxtEdit::OnRichEditChange (fPropertyFlag)
  87. *
  88. * @mfunc
  89. * Notify text services that rich-text property changed
  90. *
  91. * @rdesc
  92. * S_OK - Notification successfully processed.
  93. */
  94. HRESULT CTxtEdit::OnRichEditChange(
  95. BOOL fPropertyFlag) //@parm New state of richedit flag
  96. {
  97. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnRichEditChange");
  98. // Calculate length of empty document. Remember that multiline rich text
  99. // controls always have and end of paragraph marker.
  100. LONG cchEmptyDoc = cchCR;
  101. CFreezeDisplay fd(_pdp); // defer screen update until we finish the change.
  102. if(!_fRich)
  103. cchEmptyDoc = 0;
  104. else if(_f10Mode)
  105. cchEmptyDoc = cchCRLF;
  106. // This can only be changed if there is no text and nothing to undo.
  107. // It makes no sense to change when there is already text. This is
  108. // particularly true of going from rich to plain. Further, what would
  109. // you do with the undo state?
  110. if(GetTextLength() == cchEmptyDoc && (!_pundo || !_pundo->CanUndo()))
  111. {
  112. #ifdef DEBUG
  113. // Make sure that document is in a sensible state.
  114. if(_fRich)
  115. {
  116. CTxtPtr tp(this, 0);
  117. WCHAR szBuf[cchCRLF];
  118. tp.GetText(cchCRLF, &szBuf[0]);
  119. AssertSz(szBuf[0] == CR && (!_f10Mode || szBuf[1] == LF),
  120. "CTxtEdit::OnRichEditChange: invalid document terminator");
  121. }
  122. #endif // DEBUG
  123. if(_fRich && !fPropertyFlag)
  124. {
  125. // Going from rich text to plain text. Need to dump
  126. // format runs.
  127. HandleRichToPlainConversion();
  128. _fAutoFontSizeAdjust = TRUE;
  129. }
  130. else if (!_fRich && fPropertyFlag)
  131. {
  132. // Going from plain text to rich text. Need to add the
  133. // appropriate EOP at the end of the document.
  134. SetRichDocEndEOP(0);
  135. _fAutoFontSizeAdjust = FALSE;
  136. }
  137. _fRich = fPropertyFlag;
  138. return S_OK;
  139. }
  140. return E_FAIL; // Flag was not updated
  141. }
  142. /*
  143. * CTxtEdit::OnTxMultiLineChange (fMultiline)
  144. *
  145. * @mfunc
  146. * Notify text services that the display changed.
  147. *
  148. * @rdesc
  149. * S_OK - Notification successfully processed.
  150. */
  151. HRESULT CTxtEdit::OnTxMultiLineChange(
  152. BOOL fMultiLine)
  153. {
  154. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxMultiLineChange");
  155. BOOL fHadSelection = (_psel != NULL);
  156. CDisplay * pSavedDisplay;
  157. BOOL fOldShowSelection = FALSE;
  158. // Remember the old value for show selection
  159. if (fHadSelection)
  160. fOldShowSelection = _psel->GetShowSelection();
  161. // Save the current display away and null it out
  162. pSavedDisplay = _pdp;
  163. _pdp = NULL;
  164. // Attempt to create the new display
  165. if (fMultiLine)
  166. _pdp = new CDisplayML(this);
  167. else
  168. _pdp = new CDisplaySL(this);
  169. Assert(_pdp);
  170. if(!_pdp)
  171. {
  172. Assert(pSavedDisplay);
  173. _pdp = pSavedDisplay;
  174. return E_OUTOFMEMORY;
  175. }
  176. // Attempt to init the new display
  177. if(pSavedDisplay)
  178. _pdp->InitFromDisplay(pSavedDisplay);
  179. if(!_pdp->Init())
  180. {
  181. delete _pdp;
  182. Assert(pSavedDisplay);
  183. _pdp = pSavedDisplay;
  184. return E_FAIL;
  185. }
  186. // Ok to now kill the old display
  187. delete pSavedDisplay;
  188. // Is there are selection?
  189. if(_psel)
  190. {
  191. // Need to tell it there is a new display to talk to.
  192. _psel->SetDisplay(_pdp);
  193. }
  194. // Is this a switch to Single Line? If this is we need to
  195. // make sure we truncate the text to the first EOP. We wait
  196. // till this point to do this check to make sure that everything
  197. // is in sync before doing something which potentially affects
  198. // the display and the selection.
  199. if(!fMultiLine)
  200. {
  201. // Set up for finding an EOP
  202. CTxtPtr tp(this, 0);
  203. tp.FindEOP(tomForward);
  204. // Is there any EOP and text beyond?
  205. if (tp.GetCp() < GetAdjustedTextLength())
  206. {
  207. // FindEOP places the text after the EOP if there
  208. // is one. Since we want to delete the EOP as well
  209. // we need to back up to the EOP.
  210. tp.BackupCRLF();
  211. // Sync up the cp's of all the ranges before deleting
  212. // the text.
  213. CRchTxtPtr rtp(this, tp.GetCp());
  214. // Truncate from the EOP to the end of the document
  215. rtp.ReplaceRange(GetAdjustedTextLength() - tp.GetCp(), 0, NULL, NULL, -1);
  216. }
  217. }
  218. _pdp->UpdateView();
  219. if(fHadSelection && _fFocus && fOldShowSelection)
  220. _psel->ShowSelection(TRUE);
  221. return S_OK;
  222. }
  223. /*
  224. * CTxtEdit::OnTxReadOnlyChange (fReadOnly)
  225. *
  226. * @mfunc
  227. * Notify text services that read-only property changed
  228. *
  229. * @rdesc
  230. * S_OK - Notification successfully processed.
  231. */
  232. HRESULT CTxtEdit::OnTxReadOnlyChange(
  233. BOOL fReadOnly) //@parm TRUE = read only, FALSE = not read only
  234. {
  235. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxReadOnlyChange");
  236. if (fReadOnly)
  237. _ldte.ReleaseDropTarget();
  238. _fReadOnly = fReadOnly; // Cache bit
  239. return S_OK;
  240. }
  241. /*
  242. * CTxtEdit::OnShowAccelerator (fPropertyFlag)
  243. *
  244. * @mfunc
  245. * Update accelerator based on change
  246. *
  247. * @rdesc
  248. * S_OK - Notification successfully processed.
  249. */
  250. HRESULT CTxtEdit::OnShowAccelerator(
  251. BOOL fPropertyFlag) //@parm TRUE = show accelerator
  252. {
  253. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnShowAccelerator");
  254. // Get the new accelerator character
  255. HRESULT hr = UpdateAccelerator();
  256. // Update the view - we update even in the face of an error return.
  257. // The point is that errors will be rare (non-existent?) and the update
  258. // will work even in the face of the error so why bother conditionalizing
  259. // the execution.
  260. NeedViewUpdate(TRUE);
  261. return hr;
  262. }
  263. /*
  264. * CTxtEdit::OnUsePassword (fPropertyFlag)
  265. *
  266. * @mfunc
  267. * Update use-password property
  268. *
  269. * @rdesc
  270. * S_OK - Notification successfully processed.
  271. */
  272. HRESULT CTxtEdit::OnUsePassword(
  273. BOOL fPropertyFlag) //@parm TRUE = use password character
  274. {
  275. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnUsePassword");
  276. Assert((DWORD)fPropertyFlag <= 1); // Be sure it's C boolean
  277. _fUsePassword = fPropertyFlag;
  278. _pdp->UpdateView(); // State changed so update view
  279. return S_OK;
  280. }
  281. /*
  282. * CTxtEdit::OnTxHideSelectionChange (fHideSelection)
  283. *
  284. * @mfunc
  285. * Notify text services that hide-selection property changed
  286. *
  287. * @rdesc
  288. * S_OK - Notification successfully processed.
  289. */
  290. HRESULT CTxtEdit::OnTxHideSelectionChange(
  291. BOOL fHideSelection) //@parm TRUE = hide selection
  292. {
  293. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxHideSelectionChange");
  294. // update internal flag if selection is to be hidden
  295. _fHideSelection = fHideSelection;
  296. if (!_fFocus)
  297. OnHideSelectionChange(fHideSelection);
  298. return S_OK;
  299. }
  300. /*
  301. * CTxtEdit::OnHideSelectionChange (fHideSelection)
  302. *
  303. * @mfunc
  304. * Performs the actual hide selection. Helper to OnTxHideSelectionChange
  305. *
  306. * @rdesc
  307. * S_OK - Notification successfully processed.
  308. */
  309. HRESULT CTxtEdit::OnHideSelectionChange(
  310. BOOL fHideSelection) //@parm TRUE = hide selection
  311. {
  312. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnHideSelectionChange");
  313. _fHideSelection = fHideSelection;
  314. CTxtSelection * psel = GetSel();
  315. if(psel)
  316. {
  317. psel->ShowSelection(!fHideSelection);
  318. // 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
  319. // to hide the caret.
  320. if (_fFocus || fHideSelection)
  321. psel->ShowCaret(!fHideSelection);
  322. }
  323. if(!_fInPlaceActive)
  324. {
  325. TxInvalidate(); // Since _fInPlaceActive = FALSE,
  326. TxUpdateWindow(); // this only tells user.exe to
  327. } // send a WM_PAINT message
  328. return S_OK;
  329. }
  330. /*
  331. * CTxtEdit::OnSaveSelection (fPropertyFlag)
  332. *
  333. * @mfunc
  334. * Notify text services that save-selection property changed
  335. *
  336. * @rdesc
  337. * S_OK - Notification successfully processed.
  338. */
  339. HRESULT CTxtEdit::OnSaveSelection(
  340. BOOL fPropertyFlag) //@parm TRUE = save selection when inactive
  341. {
  342. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnSaveSelection");
  343. return S_OK;
  344. }
  345. /*
  346. * CTxtEdit::OnAutoWordSel (fPropertyFlag)
  347. *
  348. * @mfunc
  349. * Notify text services that auto-word-selection property changed
  350. *
  351. * @rdesc
  352. * S_OK - Notification successfully processed.
  353. */
  354. HRESULT CTxtEdit::OnAutoWordSel(
  355. BOOL fPropertyFlag) //@parm TRUE = auto word selection on
  356. {
  357. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnAutoWordSel");
  358. // We call back to the host when we need to know, so we don't bother doing
  359. // anything in response to this notification.
  360. return S_OK;
  361. }
  362. /*
  363. * CTxtEdit::OnTxVerticalChange (fVertical)
  364. *
  365. * @mfunc
  366. * Notify text services that vertical property changed
  367. *
  368. * @rdesc
  369. * S_OK - Notification successfully processed.
  370. */
  371. HRESULT CTxtEdit::OnTxVerticalChange(
  372. BOOL fVertical) //@parm TRUE - text vertically oriented.
  373. {
  374. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxVerticalChange");
  375. _fUseAtFont = fVertical;
  376. HandleSetTextFlow(fVertical ? tflowSW : tflowES);
  377. return S_OK;
  378. }
  379. /*
  380. * CTxtEdit::OnClientRectChange (fPropertyFlag)
  381. *
  382. * @mfunc
  383. * Notify text services that client rectangle changed
  384. *
  385. * @rdesc
  386. * S_OK - Notification successfully processed.
  387. */
  388. HRESULT CTxtEdit::OnClientRectChange(
  389. BOOL fPropertyFlag) //@parm Ignored for this property
  390. {
  391. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnClientRectChange");
  392. // It is unclear whether we need to actually do anything for this
  393. // notification. Logically, the change of this property is followed
  394. // closely by some kind of operation which will cause the display
  395. // cache to be updated anyway. The old code is left here as an
  396. // example of what might be done if it turns out we need to do
  397. // anything. For now, we will simply return S_OK to this notification.
  398. #if 0
  399. if (_fInPlaceActive)
  400. {
  401. RECT rc;
  402. if(_phost->TxGetClientRect(&rc) == NOERROR)
  403. _pdp->OnClientRectChange(rc);
  404. return S_OK;
  405. }
  406. return NeedViewUpdate(fPropertyFlag);
  407. #endif // 0
  408. if(IsInPageView())
  409. _pdp->Paginate(0, TRUE);
  410. // With a client rect change we do need to update the caret when
  411. // we get redrawn even if the basic information did not change.
  412. _pdp->SetUpdateCaret();
  413. if (_fInPlaceActive && _pMsgFilter && _pMsgCallBack)
  414. _pMsgCallBack->NotifyEvents(NE_LAYOUTCHANGE);
  415. return S_OK;
  416. }
  417. /*
  418. * CTxtEdit::OnCharFormatChange (fPropertyFlag)
  419. *
  420. * @mfunc
  421. * Update default CCharFormat
  422. *
  423. * @rdesc
  424. * S_OK - update successfully processed.
  425. */
  426. HRESULT CTxtEdit::OnCharFormatChange(
  427. BOOL fPropertyFlag) //@parm Not used
  428. {
  429. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnCharFormatChange");
  430. CCharFormat CF;
  431. DWORD dwMask;
  432. HRESULT hr = TxGetDefaultCharFormat(&CF, dwMask);
  433. if(hr == NOERROR)
  434. {
  435. DWORD dwMask2 = CFM2_CHARFORMAT;
  436. WPARAM wparam = SCF_ALL;
  437. if(!GetAdjustedTextLength())
  438. {
  439. dwMask2 = CFM2_CHARFORMAT | CFM2_NOCHARSETCHECK;
  440. wparam = 0;
  441. }
  442. // OnSetCharFormat handles updating the view.
  443. hr = OnSetCharFormat(wparam, &CF, NULL, dwMask, dwMask2) ? NOERROR : E_FAIL;
  444. }
  445. return hr;
  446. }
  447. /*
  448. * CTxtEdit::OnParaFormatChange (fPropertyFlag)
  449. *
  450. * @mfunc
  451. * Update default CParaFormat
  452. *
  453. * @rdesc
  454. * S_OK - update successfully processed
  455. */
  456. HRESULT CTxtEdit::OnParaFormatChange(
  457. BOOL fPropertyFlag) //@parm Not used
  458. {
  459. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnParaFormatChange");
  460. CParaFormat PF;
  461. HRESULT hr = TxGetDefaultParaFormat(&PF);
  462. if(hr == NOERROR)
  463. {
  464. // OnSetParaFormat handles updating the view.
  465. hr = OnSetParaFormat(SPF_SETDEFAULT, &PF, NULL, PFM_ALL2, 0)
  466. ? NOERROR : E_FAIL;
  467. }
  468. #ifdef TABS
  469. GetTabsCache()->Release(PF._iTabs);
  470. #endif
  471. return hr;
  472. }
  473. /*
  474. * CTxtEdit::NeedViewUpdate (fPropertyFlag)
  475. *
  476. * @mfunc
  477. * Notify text services that view of data changed
  478. *
  479. * @rdesc
  480. * S_OK - Notification successfully processed.
  481. */
  482. HRESULT CTxtEdit::NeedViewUpdate(
  483. BOOL fPropertyFlag)
  484. {
  485. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::NeedViewUpdate");
  486. _pdp->UpdateView();
  487. return S_OK;
  488. }
  489. /*
  490. * CTxtEdit::OnTxBackStyleChange (fPropertyFlag)
  491. *
  492. * @mfunc
  493. * Notify text services that background style changed
  494. *
  495. * @rdesc
  496. * S_OK - Notification successfully processed.
  497. */
  498. HRESULT CTxtEdit::OnTxBackStyleChange(
  499. BOOL fPropertyFlag) //@parm Ignored for this property
  500. {
  501. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnTxBackStyleChange");
  502. _fTransparent = (TxGetBackStyle() == TXTBACK_TRANSPARENT);
  503. TxInvalidate();
  504. return S_OK;
  505. }
  506. /*
  507. * CTxtEdit::OnAllowBeep (fPropertyFlag)
  508. *
  509. * @mfunc
  510. * Notify text services that beep property changed
  511. *
  512. * @rdesc
  513. * S_OK - Notification successfully processed.
  514. */
  515. HRESULT CTxtEdit::OnAllowBeep(
  516. BOOL fPropertyFlag) //@parm New state of property
  517. {
  518. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnAllowBeep");
  519. _fAllowBeep = fPropertyFlag;
  520. return S_OK;
  521. }
  522. /*
  523. * CTxtEdit::OnMaxLengthChange (fPropertyFlag)
  524. *
  525. * @mfunc
  526. * Notify text services that max-length property changed
  527. *
  528. * @rdesc
  529. * S_OK - Notification successfully processed.
  530. */
  531. HRESULT CTxtEdit::OnMaxLengthChange(
  532. BOOL fPropertyFlag) //@parm New state of property
  533. {
  534. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnMaxLengthChange");
  535. // Query host for max text length
  536. DWORD length = CP_INFINITE;
  537. _phost->TxGetMaxLength(&length);
  538. _cchTextMost = length;
  539. return S_OK;
  540. }
  541. /*
  542. * CTxtEdit::OnWordWrapChange (fPropertyFlag)
  543. *
  544. * @mfunc
  545. * Notify text services that word-wrap property changed
  546. *
  547. * @rdesc
  548. * S_OK - Notification successfully processed.
  549. */
  550. HRESULT CTxtEdit::OnWordWrapChange(
  551. BOOL fPropertyFlag) //@parm TRUE = do word wrap
  552. {
  553. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnWordWrapChange");
  554. _pdp->SetWordWrap(fPropertyFlag);
  555. // Update was successful so we need the screen updated at some point
  556. _pdp->UpdateView();
  557. return S_OK;
  558. }
  559. /*
  560. * CTxtEdit::OnDisableDrag (fPropertyFlag)
  561. *
  562. * @mfunc
  563. * Notify text services that disable drag property changed
  564. *
  565. * @rdesc
  566. * S_OK - Notification successfully processed.
  567. */
  568. HRESULT CTxtEdit::OnDisableDrag(
  569. BOOL fPropertyFlag) //@parm New state of property
  570. {
  571. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnDisableDrag");
  572. _fDisableDrag = fPropertyFlag;
  573. return S_OK;
  574. }
  575. /*
  576. * CTxtEdit::OnScrollChange (fPropertyFlag)
  577. *
  578. * @mfunc
  579. * Notify text services scroll property change
  580. *
  581. * @rdesc
  582. * S_OK - Notification successfully processed.
  583. */
  584. HRESULT CTxtEdit::OnScrollChange(
  585. BOOL fPropertyFlag) //@parm New state of property
  586. {
  587. TRACEBEGIN(TRCSUBSYSTS, TRCSCOPEINTERN, "CTxtEdit::OnScrollChange");
  588. // Tell the display that scroll bars for sure need to be updated
  589. _pdp->SetViewChanged();
  590. // Tell the display to update itself.
  591. _pdp->UpdateView();
  592. return S_OK;
  593. }