home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OWLSRC.PAK / RICHEDIT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  36.3 KB  |  1,399 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1995, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.20  $
  6. //
  7. // Implementation of class TRichEdit.
  8. //----------------------------------------------------------------------------
  9. #pragma hdrignore SECTION
  10. #include <owl/pch.h>
  11. #if !defined(OWL_WINDOW_H)
  12. # include <owl/window.h>
  13. #endif
  14. #if !defined(OWL_CONTROL_H)
  15. # include <owl/control.h>
  16. #endif
  17. #if !defined(OWL_EDIT_H)
  18. # include <owl/edit.h>
  19. #endif
  20. #if !defined(OWL_EDITSEAR_H)
  21. # include <owl/editsear.h>
  22. #endif
  23. #if !defined(OWL_EDITFILE_H)
  24. # include <owl/editfile.h>
  25. #endif
  26. #if !defined(OWL_RICHEDIT_H)
  27. # include <owl/richedit.h>
  28. #endif
  29. #if !defined(CLASSLIB_FILENAME_H)
  30. # include <classlib/filename.h>
  31. #endif
  32.  
  33. OWL_DIAGINFO;
  34.  
  35. // Range of the editor's font size
  36. //
  37. const int MinPointSize = 6;
  38. const int MaxPointSize = 128;
  39.  
  40. // System DLL providing underlying support for RichEdit controls
  41. //
  42. const char RichEditDllName[]  = "RICHED32.DLL";
  43.  
  44. //
  45. // Constructs a CharacterFormat structure from the current character
  46. // attributes of a RICHEDIT control. NOTE: Specifying 'true' for selection
  47. // will return the attribute of the character at the current location if
  48. // there are no block of data selected in the control.
  49. //
  50. TCharFormat::TCharFormat(const TRichEdit& edit, bool selection, ulong mask)
  51. {
  52.   PRECONDITION((HWND)edit);
  53.  
  54.   memset(this, 0, sizeof(CHARFORMAT));
  55.  
  56.   cbSize = sizeof(CHARFORMAT);
  57.   dwMask = mask;
  58.   edit.GetCharFormat(*this, selection);
  59. }
  60.  
  61. //
  62. // Toggles the 'bold' character attribute according to boolean parameter
  63. // specified.
  64. //
  65. void
  66. TCharFormat::EnableBold(bool flag)
  67. {
  68.   dwMask |= CFM_BOLD;
  69.   if (flag) {
  70.     dwEffects |= CFE_BOLD;
  71.   }
  72.   else {
  73.     dwEffects &= ~CFE_BOLD;
  74.   }
  75. }
  76.  
  77. //
  78. // Toggles 'italic' character attribute based on the boolean parameter
  79. // specified.
  80. //
  81. void
  82. TCharFormat::EnableItalic(bool flag)
  83. {
  84.   dwMask |= CFM_ITALIC;
  85.   if (flag) {
  86.     dwEffects |= CFE_ITALIC;
  87.   }
  88.   else {
  89.     dwEffects &= ~CFE_ITALIC;
  90.   }
  91. }
  92.  
  93. //
  94. // Toggle the 'underline' character attribute based on the boolean parameter
  95. // specified.
  96. //
  97. void
  98. TCharFormat::EnableUnderline(bool flag)
  99. {
  100.   dwMask |= CFM_UNDERLINE;
  101.   if (flag) {
  102.     dwEffects |= CFE_UNDERLINE;
  103.   }
  104.   else {
  105.     dwEffects &= ~CFE_UNDERLINE;
  106.   }
  107. }
  108.  
  109. //
  110. // Toggle the 'strike-out' character attribute based on the boolean parameter
  111. // specified.
  112. //
  113. void
  114. TCharFormat::EnableStrikeOut(bool flag)
  115. {
  116.   dwMask |= CFM_STRIKEOUT;
  117.   if (flag) {
  118.     dwEffects |= CFE_STRIKEOUT;
  119.   }
  120.   else {
  121.     dwEffects &= ~CFE_STRIKEOUT;
  122.   }
  123. }
  124.  
  125. //
  126. // Toggle the 'protected' character attribute based on the boolean parameter
  127. // specified.
  128. //
  129. void
  130. TCharFormat::EnableProtected(bool flag)
  131. {
  132.   dwMask |= CFM_PROTECTED;
  133.   if (flag) {
  134.     dwEffects |= CFE_PROTECTED;
  135.   }
  136.   else {
  137.     dwEffects &= ~CFE_PROTECTED;
  138.   }
  139. }
  140.  
  141. //
  142. // Retrieve the character color stored in the CHARFORMAT structure.
  143. // NOTE: Default to system text color of no explicit color was set
  144. //       in the CHARFORMAT structure.
  145. //
  146. TColor
  147. TCharFormat::GetTextColor() const
  148. {
  149.   if ((dwMask & CFM_COLOR) && !(dwEffects & CFE_AUTOCOLOR))
  150.     return TColor(crTextColor);
  151.   return TColor::SysWindowText;
  152. }
  153.  
  154. //
  155. // Update the CHARFORMAT structure with the specified color.
  156. // NOTE: If 'TColor::None' is specified, enable the flag specifying that the
  157. //       color should default to the system text color .
  158. //
  159. void
  160. TCharFormat::SetTextColor(const TColor& color)
  161. {
  162.   dwMask |= CFM_COLOR;
  163.   if (color == TColor::None) {
  164.     dwEffects |= CFE_AUTOCOLOR;
  165.   }
  166.   else {
  167.     dwEffects &= ~CFE_AUTOCOLOR;
  168.     crTextColor = color;
  169.   }
  170. }
  171.  
  172. //
  173. // Set the face name of the font.
  174. //
  175. void
  176. TCharFormat::SetFaceName(const char far* name)
  177. {
  178.   strcpy(szFaceName, name);
  179. }
  180.  
  181. //
  182. // Set the character set of the font. Valid values include the following:
  183. // ANSI_CHARSET, OEM_CHARSET and SYMBOL_CHARSET.
  184. //
  185. void
  186. TCharFormat::SetCharSet(uint8 charSet)
  187. {
  188.   bCharSet = charSet;
  189. }
  190.  
  191. //
  192. // Set the pitch and family of the font. The two lower-bits specify the pitch
  193. // of the font and can be one of the following values:
  194. // DEFAULT_PITCH, FIXED_PITCH and VARIABLE_PITCH.
  195.  
  196. // Bits 4 through 7 of the member specify the font family and can be
  197. // one of the following values:
  198. // FF_DECORATIVE, FF_DONTCARE, FF_MODERN, FF_ROMAN, FF_SCRIPT & FF_SWISS.
  199. //
  200. void
  201. TCharFormat::SetPitchAndFamily(uint8 pitchFam)
  202. {
  203.   bPitchAndFamily = pitchFam;
  204. }
  205.  
  206. //
  207. // Set the character height
  208. //
  209. void
  210. TCharFormat::SetHeight(long height)
  211. {
  212.   dwMask |= CFM_SIZE;
  213.   yHeight = height;
  214. }
  215.  
  216. //
  217. // Set the character offset from the baseline. If the parameter is positive,
  218. // the character is a superscript; if it is negative, the character is a
  219. // subscript
  220. //
  221. void
  222. TCharFormat::SetOffset(long offset)
  223. {
  224.   dwMask |= CFM_OFFSET;
  225.   yOffset = offset;
  226. }
  227.  
  228. //
  229. // Transfer the information currently in the underlying CHARFORMAT structure
  230. // to a LOGFONT structure.
  231. // This is useful when changing the editor's font as initialized LOGFONT
  232. // structure can subsequently be used when invoking the FONT Common
  233. // Dialog, i.e. TChooseFontDialog
  234. //
  235. void
  236. TCharFormat::SetFontInfo(LOGFONT& lf) const
  237. {
  238.   memset(&lf, 0, sizeof(LOGFONT));
  239.  
  240.   if (dwMask & CFM_SIZE)                //  (1 Point == 20 twips)
  241.     lf.lfHeight = yHeight/-20;
  242.  
  243.   if (dwMask & CFM_BOLD)
  244.     lf.lfWeight = dwEffects & CFE_BOLD ? FW_BOLD : FW_NORMAL;
  245.  
  246.   if (dwMask & CFM_ITALIC)
  247.     lf.lfItalic = (uint8)(dwEffects & CFE_ITALIC ? TRUE : FALSE);
  248.  
  249.   if (dwMask & CFM_UNDERLINE)
  250.     lf.lfUnderline = (uint8)(dwEffects & CFE_UNDERLINE ? TRUE : FALSE);
  251.  
  252.   if (dwMask & CFM_FACE) {
  253.     lf.lfPitchAndFamily = bPitchAndFamily;
  254.     strcpy(lf.lfFaceName, szFaceName);
  255.   }
  256.  
  257.   lf.lfCharSet = DEFAULT_CHARSET;
  258.   lf.lfQuality = DEFAULT_QUALITY;
  259. }
  260.  
  261. //
  262. // Initialize the underlying CHARFORMAT structure using the information
  263. // stored in a LOGFONT structure.
  264. //
  265. void
  266. TCharFormat::GetFontInfo(const LOGFONT& lf)
  267. {
  268.   dwMask = (CFM_SIZE | CFM_BOLD | CFM_ITALIC | CFM_OFFSET|
  269.             CFM_STRIKEOUT | CFM_UNDERLINE | CFM_FACE);
  270.  
  271.   yHeight = lf.lfHeight * -20;
  272.  
  273.   if (FW_BOLD == lf.lfWeight)
  274.     dwEffects |= CFE_BOLD;
  275.   if (lf.lfItalic)
  276.     dwEffects |= CFE_ITALIC;
  277.   if (lf.lfStrikeOut)
  278.     dwEffects |= CFE_STRIKEOUT;
  279.   if (lf.lfUnderline)
  280.     dwEffects |= CFE_UNDERLINE;
  281.  
  282.   bPitchAndFamily = lf.lfPitchAndFamily;
  283.   strcpy(szFaceName, lf.lfFaceName);
  284. }
  285.  
  286. //
  287. // Construct a TFormatRange object initializing data members with the
  288. // specified parameters.
  289. //
  290. TFormatRange::TFormatRange(HDC renderDC, HDC devDC, const TRect& renderArea,
  291.                            const TRect& entireArea, const TCharRange& range)
  292. {
  293.   SetRenderDC(renderDC);
  294.   SetTargetDC(devDC);
  295.   SetRenderRect(renderArea);
  296.   SetPageRect(entireArea);
  297.   SetRange(range);
  298. }
  299.  
  300. //
  301. // Set the device context of the device to render to.
  302. //
  303. void
  304. TFormatRange::SetRenderDC(HDC renderDC)
  305. {
  306.   hdc = renderDC;
  307. }
  308.  
  309. //
  310. // Set the device context of the target device to format for.
  311. //
  312. void
  313. TFormatRange::SetTargetDC(HDC targetDC)
  314. {
  315.   hdcTarget = targetDC;
  316. }
  317.  
  318. //
  319. // Set the area to render to.
  320. // NOTE: The specified units are in TWIPS.
  321. //
  322. void
  323. TFormatRange::SetRenderRect(const TRect& renderRect)
  324. {
  325.   rc = renderRect;
  326. }
  327.  
  328. //
  329. // Set the entire area of the rendering device.
  330. // NOTE: The specified units are in TWIPS.
  331. //
  332. void
  333. TFormatRange::SetPageRect(const TRect& pgRect)
  334. {
  335.   rcPage = pgRect;
  336. }
  337.  
  338. //
  339. // Set the range of text to format.
  340. //
  341. void
  342. TFormatRange::SetRange(const TCharRange& charRange)
  343. {
  344.   chrg = charRange;
  345. }
  346.  
  347. //
  348. // Set the range of text to format specifying the starting and ending
  349. // character offsets.
  350. //
  351. void
  352. TFormatRange::SetRange(long start, long end)
  353. {
  354.   chrg.cpMin = start;
  355.   chrg.cpMax = end;
  356. }
  357.  
  358. //
  359. // Construct a default TParaFormat structure.
  360. //
  361. TParaFormat::TParaFormat(ulong mask)
  362. {
  363.   cbSize = sizeof(PARAFORMAT);
  364.   dwMask = mask;
  365. }
  366.  
  367. //
  368. // Construct a TParaFormat structure whose members are initialized with the
  369. // paragraph formatting attributes of the current selection of a rich edit
  370. // control.
  371. //
  372. TParaFormat::TParaFormat(const TRichEdit& edit, ulong mask)
  373. {
  374.   PRECONDITION((HWND)edit);
  375.  
  376.   cbSize = sizeof(PARAFORMAT);
  377.   dwMask = mask;
  378.   edit.GetParaFormat(*this);
  379. }
  380.  
  381. //
  382. // Toggle the specified flag in the member which describes which information
  383. // of the PARAFORMAT structures is valid.
  384. //
  385. void
  386. TParaFormat::ToggleMaskBit(ulong flag)
  387. {
  388.   dwMask ^= flag;
  389. }
  390.  
  391. //
  392. // Set the numbering options. The only valid parameter is '0' or PFN_BULLET.
  393. //
  394. void
  395. TParaFormat::SetNumbering(uint16 opt)
  396. {
  397.   PRECONDITION(opt == 0 || opt == PFN_BULLET);
  398.  
  399.   dwMask |= PFM_ALIGNMENT;
  400.   wNumbering = opt;
  401. }
  402.  
  403. //
  404. // Set the indentation of the first line in the paragraph. If the paragraph
  405. // formatting is being set and the 'relative' parameter is true, the 'start'
  406. // value is  treated as a relative value that is added to the starting
  407. // indentation of each affected paragraph.
  408. //
  409. void
  410. TParaFormat::SetStartIndent(long start, bool relative)
  411. {
  412.   dwMask |= PFM_STARTINDENT;
  413.   if (relative)
  414.     dwMask |= PFM_OFFSETINDENT;
  415.   else
  416.     dwMask &= ~PFM_OFFSETINDENT;
  417.  
  418.   dxStartIndent = start;
  419. }
  420.  
  421. //
  422. // Set the size of the right identation, relative to the right margin.
  423. //
  424. void
  425. TParaFormat::SetRightIndent(long indent)
  426. {
  427.   dwMask |= PFM_RIGHTINDENT;
  428.   dxRightIndent = indent;
  429. }
  430.  
  431. //
  432. // Set the indentation of the second line and subsequent lines,
  433. // relative to the starting indentation. The first line is indented if
  434. // the 'offset' parameter is negative, or outdented if it is positive.
  435. //
  436. void
  437. TParaFormat::SetOffset(long offset)
  438. {
  439.   dwMask |= PFM_OFFSET;
  440.   dxOffset = offset;
  441. }
  442.  
  443. //
  444. // Set the alignment option. The 'opt' parameter can be one of the following
  445. // values:
  446. //    PFA_LEFT        Paragraphs are aligned with the left margin.
  447. //    PFA_RIGHT       Paragraphs are aligned with the right margin.
  448. //    PFA_CENTER      Paragraphs are centered.
  449. //
  450. void
  451. TParaFormat::SetAlignment(uint16 opt)
  452. {
  453.   dwMask |= PFM_ALIGNMENT;
  454.   wAlignment = opt;
  455. }
  456.  
  457. //
  458. // Set the number and absolute positions of the tab stops.
  459. //
  460. void
  461. TParaFormat::SetTabCount(short cnt, long* tabs)
  462. {
  463.   PRECONDITION(tabs || !cnt);
  464.  
  465.   dwMask |= PFM_TABSTOPS;
  466.   cTabCount = cnt;
  467.   for (int i=0; i<cnt; i++)
  468.     rgxTabs[i] = *tabs++;
  469. }
  470.  
  471.  
  472. DEFINE_RESPONSE_TABLE1(TRichEdit, TEditFile)
  473.   EV_COMMAND(CM_EDITCUT, CmEditCut),
  474.   EV_COMMAND(CM_EDITCOPY, CmEditCopy),
  475.   EV_COMMAND(CM_EDITPASTE, CmEditPaste),
  476.   EV_COMMAND(CM_EDITDELETE, CmEditDelete),
  477.   EV_COMMAND(CM_EDITCLEAR, CmEditClear),
  478.   EV_COMMAND(CM_EDITUNDO, CmEditUndo),
  479.   EV_COMMAND_ENABLE(CM_EDITCUT, CeHasSelect),
  480.   EV_COMMAND_ENABLE(CM_EDITCOPY, CeHasSelect),
  481.   EV_COMMAND_ENABLE(CM_EDITDELETE, CeHasSelect),
  482.   EV_COMMAND_ENABLE(CM_EDITPASTE, CeEditPaste),
  483.   EV_COMMAND_ENABLE(CM_EDITCLEAR, CeEditClear),
  484.   EV_COMMAND_ENABLE(CM_EDITUNDO, CeEditUndo),
  485.   EV_WM_CHAR,
  486.   EV_WM_KEYDOWN,
  487.   EV_WM_GETDLGCODE,
  488.   EV_WM_SETFOCUS,
  489.   EV_WM_KILLFOCUS,
  490. END_RESPONSE_TABLE;
  491.  
  492. //
  493. // constructor for a TRichEdit object
  494. //
  495. // by default, edit control has a border and its text is left-justified
  496. //
  497. // multiline edit control has horizontal vertical scroll bars
  498. //
  499. TRichEdit::TRichEdit(TWindow*        parent,
  500.                      int             id,
  501.                      const char far* text,
  502.                      int x, int y, int w, int h,
  503.                      const char far* fileName,
  504.                      TModule*        module)
  505.   : TEditFile(parent, id, text, x, y, w, h, fileName, module)
  506. {
  507.   // Make sure the RichEdit DLL is available
  508.   //
  509.   if (!TRichEditDll::IsAvailable())
  510.     TXCommCtrl::Raise();  
  511.  
  512.   // Default to RTF data format
  513.   //
  514.   SetFormat(SF_RTF);
  515.  
  516.   // Undo the styles specific to "EDIT" controls; add richedit styles
  517.   //
  518.   ModifyStyle(ES_LOWERCASE|ES_PASSWORD|ES_OEMCONVERT|
  519.               ES_UPPERCASE|ES_AUTOHSCROLL,
  520.               ES_LEFT | WS_BORDER | WS_TABSTOP);
  521. }
  522.  
  523. //
  524. // constructor for TRichEdit associated with a MS-Windows interface element
  525. // created by MS-Windows from a resource definition
  526. //
  527. // by default, data transfer is enabled
  528. //
  529. TRichEdit::TRichEdit(TWindow*   parent,
  530.                      int        resourceId,
  531.                      TModule*   module)
  532.   : TEditFile(parent, resourceId, module ? *module : *parent->GetModule())
  533. {
  534.   // Make sure the RichEdit DLL is available
  535.   //
  536.   if (!TRichEditDll::IsAvailable())
  537.     TXCommCtrl::Raise();  
  538. }
  539.  
  540.  
  541. //
  542. // Retrieve the current character formatting in an edit control. If
  543. // 'selection' parameter is 'true', the attribute of the current selection is
  544. // retrieved. Otherwise, the default formatting attribute is retrieved.
  545. //
  546. ulong
  547. TRichEdit::GetCharFormat(TCharFormat far& cf, bool selection) const
  548. {
  549.   return CONST_CAST(TRichEdit*,this)->SendMessage(
  550.                          EM_GETCHARFORMAT, selection ? SCF_SELECTION : 0,
  551.                                                   TParam2(&cf));
  552. }
  553.  
  554. //
  555. // Retrieve the paragraph formatting of the current selection of the rich
  556. // edit control.
  557. //
  558. // NOTE: If more than one paragraph is selected, the structure
  559. //       receives the attributes of the first paragraph, and the dwMask
  560. //       member specifies which attributes are consistent throughout the
  561. //       entire selection.
  562. //
  563. ulong
  564. TRichEdit::GetParaFormat(TParaFormat far& pf) const
  565. {
  566.   return CONST_CAST(TRichEdit*,this)->SendMessage(EM_GETPARAFORMAT, 0,
  567.                                                     TParam2(&pf));
  568. }
  569.  
  570. //
  571. // Set the character formatting of a rich edit control. The 'flags' parameter
  572. // can be one of the following:
  573. //
  574. //    SCF_SELECTION  Applies the formatting to the current selection, or sets
  575. //                   the default formatting if the selection is empty.
  576. //    SCF_WORD       Applies the formatting to the selected word or words. If
  577. //                   the selection is empty but the insertion point is inside
  578. //                   a word, the formatting is applied to the word. This value
  579. //                   must be used in conjunction with the SCF_SELECTION value.
  580. //
  581. bool
  582. TRichEdit::SetCharFormat(const TCharFormat far& cf, uint flags)
  583. {
  584.   return SendMessage(EM_SETCHARFORMAT, TParam1(flags), TParam2(&cf)) != 0;
  585. }
  586.  
  587. //
  588. // Set the paragraph formatting of the current selection of the rich edit
  589. // control.
  590. //
  591. bool
  592. TRichEdit::SetParaFormat(const TParaFormat far& pf)
  593. {
  594.   return SendMessage(EM_SETPARAFORMAT, 0, TParam2(&pf)) != 0;
  595. }
  596.  
  597. //
  598. // Set the background color of the rich edit control.
  599. // NOTE: If 'TColor::None' is specified, the color is set to the window
  600. //       background system color.
  601. //
  602. TColor
  603. TRichEdit::SetBkgndColor(const TColor& bkColor)
  604. {
  605.   TParam1 p1 = bkColor == TColor::None ? true : false;
  606.   TParam2 p2 = bkColor == TColor::None ? 0    : (COLORREF)bkColor;
  607.   return TColor((COLORREF)SendMessage(EM_SETBKGNDCOLOR, p1, p2));
  608. }
  609.  
  610. //
  611. // Return whether the current selection has a particular attribute.
  612. // The 'mask' identifies the attribute we're interested in.
  613. // The 'effects' contains the state of the attributes.
  614. // The function returns one of the following values:
  615. //
  616. //    TFmtStatus::Yes           The attribute is enabled
  617. //    TFmtStatus::No            The attribute is absent
  618. //    TFmtStatus::Partly        The attribute is partly present
  619. //
  620. uint
  621. TRichEdit::HasCharAttribute(ulong mask, ulong effects)
  622. {
  623.   TCharFormat cf(*this);
  624.   if (cf.dwMask & mask) {
  625.     if (cf.dwEffects & effects)
  626.       return Yes;
  627.     else
  628.       return No;
  629.   }
  630.   else
  631.     return Partly;
  632. }
  633.  
  634. //
  635. // Toggle a set of character attributes. The 'mask' identifies
  636. // the attributes we're interested in while 'effects' identifies the state
  637. // of the attributes.
  638. //
  639. bool
  640. TRichEdit::ToggleCharAttribute(ulong mask, ulong effects)
  641. {
  642.   TCharFormat cf(*this);
  643.   cf.dwMask = mask;
  644.   cf.ToggleEffectsBit(effects);
  645.   return SetCharFormat(cf);
  646. }
  647.  
  648. //
  649. // Increase or decrease (using a positive or negative value respectively) the
  650. // point size of the current selection.
  651. //
  652. bool
  653. TRichEdit::ChangeCharPointSize(int pointSizeDelta)
  654. {
  655.   TCharFormat cf(*this);
  656.   cf.dwMask = CFM_SIZE;
  657.   if (((cf.yHeight + 20*pointSizeDelta) <= (MaxPointSize*20)) &&
  658.       ((cf.yHeight + 20*pointSizeDelta) >= (MinPointSize*6))) {
  659.     cf.yHeight += 20*pointSizeDelta;
  660.     return SetCharFormat(cf);
  661.   }
  662.   return false;
  663. }
  664.  
  665. //
  666. // Return true if the rich edit control has an active selection. Return false
  667. // otherwise.
  668. //
  669. bool
  670. TRichEdit::HasSelection() const
  671. {
  672.   TCharRange chRange;
  673.   GetSelRange(chRange);
  674.   return chRange.cpMin != chRange.cpMax;
  675. }
  676.  
  677. //
  678. // Retrieve the starting and ending character position of the selection
  679. // in the rich edit control.
  680. //
  681. void
  682. TRichEdit::GetSelection(uint& startPos, uint& endPos) const
  683. {
  684.   TCharRange cr;
  685.   GetSelRange(cr);
  686.   startPos = cr.cpMin;
  687.   endPos = cr.cpMax;
  688. }
  689.  
  690. //
  691. // Retrieve the starting and ending character positions of the selection of
  692. // the richedit control.
  693. //
  694. void
  695. TRichEdit::GetSelRange(TCharRange far& cr) const
  696. {
  697.   CONST_CAST(TRichEdit*,this)->SendMessage(EM_EXGETSEL, 0, TParam2(&cr));
  698. }
  699.  
  700. //
  701. // Select a range of characters in the rich edit control.
  702. //
  703. bool
  704. TRichEdit::SetSelection(uint startPos, uint endPos)
  705. {
  706.   TCharRange cr(startPos, endPos);
  707.   return SetSelRange(cr) >= 0;
  708. }
  709.  
  710. //
  711. // Select a range of characters in the rich edit control.
  712. //
  713. int
  714. TRichEdit::SetSelRange(const TCharRange far& cr)
  715. {
  716.   return (int)SendMessage(EM_EXSETSEL, 0, TParam2(&cr));
  717. }
  718.  
  719. //
  720. // Show or hide the selection in the rich edit control.
  721. // The 'hide' parameter specifies whether to hide or show the selection. If the
  722. // is 'false' the selection is shown. Otherwise, the selection is hidden.
  723. // The 'changeStyle' parameter specifies whether to change the control's
  724. // ES_NOHIDESEL window style. If this parameter is 'false', the selection is
  725. // temporarily shown or hidden. Otherwise, the style is changed. If this
  726. // parameter is 'true' and the control has the focus, the selection is hidden
  727. // or shown as appropriate.
  728. //
  729. void
  730. TRichEdit::HideSelection(bool hide, bool changeStyle)
  731. {
  732.   SendMessage(EM_HIDESELECTION, TParam1(hide), TParam2(changeStyle));
  733. }
  734.  
  735. //
  736. // Return the selection type of the rich edit control. Returns SEL_EMPTY if
  737. // the selection is empty, or one or more of the following values:
  738. //
  739. //    Value                 Contents of the selection
  740. //    -----                 ------------------------
  741. //    SEL_TEXT              Text
  742. //    SEL_OBJECT            At least one OLE object
  743. //    SEL_MULTICHAR         More than one character of text
  744. //    SEL_MULTIOBJECT       More than one OLE object
  745. //
  746. ulong
  747. TRichEdit::GetSelectionType() const
  748. {
  749.   return CONST_CAST(TRichEdit*,this)->SendMessage(EM_SELECTIONTYPE);
  750. }
  751.  
  752. //
  753. // Retrieve a specified range of text from the rich edit control
  754. //
  755. int
  756. TRichEdit::GetTextRange(TTextRange far& tr) const
  757. {
  758.   return (int)CONST_CAST(TRichEdit*,this)->SendMessage(EM_GETTEXTRANGE, 0,
  759.                                                          TParam2(&tr));
  760. }
  761.  
  762. //
  763. // Retrieve a specified range of text from the rich edit control
  764. //
  765. int
  766. TRichEdit::GetTextRange(const TCharRange far& cr, char far* buffer) const
  767. {
  768.   TTextRange tr(cr, buffer);
  769.   return GetTextRange(tr);
  770. }
  771.  
  772. //
  773. // Retrieve a specified range of text from the rich edit control
  774. //
  775. void
  776. TRichEdit::GetSubText(char far* str, uint startPos, uint endPos) const
  777. {
  778.   TTextRange tr(startPos, endPos, str);
  779.   GetTextRange(tr);
  780. }
  781.  
  782. //
  783. // Retrieve the currently selected text of the rich edit control.
  784. //
  785. int
  786. TRichEdit::GetSelectedText(char far* buffer) const
  787. {
  788.   return (int)CONST_CAST(TRichEdit*,this)->SendMessage(EM_GETSELTEXT, 0,
  789.                                                          TParam2(buffer));
  790. }
  791.  
  792. //
  793. // Set an upper limit to the amount of text in the richedit control.
  794. //
  795. void
  796. TRichEdit::LimitText(long max)
  797. {
  798.   SendMessage(EM_EXLIMITTEXT, 0, TParam2(max));
  799. }
  800.  
  801. //
  802. // Find text within the rich edit control. The 'flags' parameter can be a
  803. // combination of the following values:
  804. // i.   FT_MATCHCASE  - Perform a case sensitiv search
  805. // ii.  FT_MATCHWORD  - Match whole words
  806. //
  807. int
  808. TRichEdit::FindText(uint flags, const TFindText far& ft)
  809. {
  810.   return (int)SendMessage(EM_FINDTEXT, TParam1(flags), TParam2(&ft));
  811. }
  812.  
  813. //
  814. // Find text within the rich edit control. The 'flags' parameter can be a
  815. // combination of the following values:
  816. // i.   FT_MATCHCASE  - Perform a case sensitiv search
  817. // ii.  FT_MATCHWORD  - Match whole words
  818. //
  819. int
  820. TRichEdit::FindText(uint flags, const TCharRange far& cr, const char far* text)
  821. {
  822.   TFindText ft(cr, text);
  823.   return FindText(flags, ft);
  824. }
  825.  
  826. //
  827. // Search for the specified text in the rich edit control. If found, select
  828. // the text and return the offset of the text. Otherwise, return -1.
  829. //
  830. // NOTE: If the 'startPos' is -1, it is assumed that the starting position is
  831. // the end [or beginning, depending on the direction parameter, 'up'] of the
  832. // current selection
  833. //
  834. int
  835. TRichEdit::Search(uint startPos, const char far* text, bool caseSensitive,
  836.                   bool wholeWord, bool up)
  837. {
  838.   if (!text || !text[0])
  839.     return -1;
  840.  
  841.   if (startPos == (uint)-1) {
  842.     uint sBeg, sEnd;
  843.     GetSelection(sBeg, sEnd);
  844.     startPos = up ? sBeg : sEnd;
  845.   }
  846.  
  847.   // The current docs. mention the FT_MATCHCASE and FT_WHOLEWORD flags which 
  848.   // are not defined currently. I suspect they meant the FR_xxxx flags (used 
  849.   // in CommDlg API).
  850.   //
  851.   TFindText findText(startPos, -1, text);
  852.   uint flags = (caseSensitive ? FR_MATCHCASE : 0) |
  853.                (wholeWord ? FR_WHOLEWORD : 0);
  854.   int index = FindText(flags, findText);
  855.  
  856.   //
  857.   // If we've got a match, select the text
  858.   //
  859.   if (index >= 0) {
  860.     int len = strlen(text);
  861.     SetSelection(index+len, index);
  862.   }
  863.   return index;
  864. }
  865.  
  866. //
  867. // Find the next work break before or after the specified character position,
  868. // or retrieve information about the character at that position. The 'code'
  869. // parameter can be one of the following:
  870. //
  871. //  WB_CLASSIFY       Returns the character class and word break flags of the
  872. //                    character at the specified position.
  873. //  WB_ISDELIMITER    Returns TRUE if the character at the specified position
  874. //                    is a delimiter, or FALSE otherwise.
  875. //  WB_LEFT           Finds the nearest character before the specified
  876. //                    position that begins a word.
  877. //  WB_LEFTBREAK      Finds the next word end before the specified position.
  878. //  WB_MOVEWORDLEFT   Finds the next character that begins a word before the
  879. //                    specified position. This value is used during CTRL+LEFT key processing.
  880. //  WB_MOVEWORDRIGHT  Finds the next character that begins a word after the
  881. //                    specified position. This value is used during
  882. //                    CTRL+RIGHT key processing.
  883. //  WB_RIGHT          Finds the next character that begins a word after the
  884. //                    specified position.
  885. //  WB_RIGHTBREAK     Finds the next end-of-word delimiter after the
  886. //                    specified position.
  887. //
  888. // The return value is the character index of the word break, unless the
  889. // 'code' parameter is WB_CLASSIFY or WB_ISDELIMETER
  890. int
  891. TRichEdit::FindWordBreak(uint code, long start)
  892. {
  893.   return (int)SendMessage(EM_FINDWORDBREAK, TParam1(code), TParam2(start));
  894. }
  895.  
  896. //
  897. // Determine which line contains the specified character in the richedit
  898. // control.
  899. // NOTE: The return value is zero-based.
  900. //
  901. int
  902. TRichEdit::GetLineFromPos(uint charPos) const
  903. {
  904.   return (int)CONST_CAST(TRichEdit*,this)->SendMessage(EM_EXLINEFROMCHAR,
  905.                                                          0, TParam2(charPos));
  906. }
  907.  
  908. //
  909. // Return true if the richedit can paste the specified clipboard format, or
  910. // false otherwise.
  911. //
  912. bool
  913. TRichEdit::CanPaste(uint format) const
  914. {
  915.   return CONST_CAST(TRichEdit*,this)->SendMessage(EM_CANPASTE,
  916.                                                     TParam1(format)) != 0;
  917. }
  918.  
  919. //
  920. // Paste the specified clipboard format in the rich edit control.
  921. //
  922. void
  923. TRichEdit::PasteSpecial(uint format)
  924. {
  925.   SendMessage(EM_PASTESPECIAL, TParam1(format));
  926. }
  927.  
  928. //
  929. // Paste a compatible clipboard format in the rich edit control.
  930. //
  931. void
  932. TRichEdit::Paste()
  933. {
  934.   SendMessage(WM_PASTE);
  935.  
  936. }
  937.  
  938. //
  939. // Replace the contents of the rich edit control with the specified data
  940. // stream. The 'format' parameter can be one of the following data formats,
  941. // optionally combined with the SFF_SELECTION flag:
  942. //
  943. //    Value               Meaning
  944. //    -----               -------
  945. //    SF_TEXT             Text
  946. //    SF_RTF              Rich-text format
  947. //
  948. // If the SFF_SELECTION flag is specified, the stream replaces the contents of
  949. // the current selection. Otherwise, the stream replaces the entire contents
  950. // of the control.
  951. //
  952. ulong
  953. TRichEdit::StreamIn(uint format, TEditStream far& es)
  954. {
  955.   return SendMessage(EM_STREAMIN, TParam1(format), TParam2(&es));
  956. }
  957.  
  958. //
  959. // Write the contents of the rich edit control to the specified data stream.
  960. // The 'format' parameter can be one of the following values, optionally
  961. // combined with the SFF_SELECTION flag:
  962. //
  963. //    Value               Meaning
  964. //    -----               -------
  965. //    SF_TEXT             Text with spaces in place of OLE objects
  966. //    SF_RTF              Rich-text format (RTF)
  967. //    SF_RTFNOOBJS        RTF with spaces in place of OLE object.
  968. //    SF_TEXTIZED         Text with a text representation of OLE objects.
  969. //
  970. // NOTE: The SF_RTFNOOBJS option is useful if an application stores OLE
  971. //       objects itself, as RTF representation of OLE objects is not very
  972. //       compact.
  973. //       If the SFF_SELECTION flag is specified, only the contents of the
  974. //       current selection are streamed out. Otherwise, the entire contents of
  975. //       the control are streamed out.
  976. //
  977. ulong
  978. TRichEdit::StreamOut(uint format, TEditStream far& es)
  979. {
  980.   return SendMessage(EM_STREAMOUT, TParam1(format), TParam2(&es));
  981. }
  982.  
  983. //
  984. // Display a portion of the richedit control's content within the specified
  985. // rectangle.
  986. // NOTE: The content of the control must first be formatted via a call to the
  987. //       'FormatRange' method.
  988. //
  989. bool
  990. TRichEdit::DisplayBand(TRect far& rc)
  991. {
  992.   return SendMessage(EM_DISPLAYBAND, 0, TParam2(&rc)) != 0;
  993. }
  994.  
  995. //
  996. // Formats a range of text (specified via the 'chrg' member of the
  997. // specified TFormatRange) for the device(s) specified via the 'hdcTarget'
  998. // and 'hdc' members of the TFormatRange structure.
  999. //
  1000. int
  1001. TRichEdit::FormatRange(const TFormatRange far& fr, bool render)
  1002. {
  1003.   return (int)SendMessage(EM_FORMATRANGE, TParam1(render), TParam2(&fr));
  1004. }
  1005.  
  1006. //
  1007. // Frees the Formatting information cached by the RichEdit control...
  1008. //
  1009. int
  1010. TRichEdit::FormatRange()
  1011. {
  1012.   return (int)SendMessage(EM_FORMATRANGE, TParam1(TRUE), 0);
  1013. }
  1014.  
  1015. //
  1016. // Set the target device and line width used for WYSIWYG (what you see is
  1017. // what you get) formatting of the rich edit control.
  1018. //
  1019. bool
  1020. TRichEdit::SetTargetDevice(HDC dc, int lineWidth)
  1021. {
  1022.   return SendMessage(EM_SETTARGETDEVICE, TParam1(dc),
  1023.                        TParam2(lineWidth)) != 0;
  1024. }
  1025.  
  1026. //
  1027. // Force the rich edit control to send an EN_REQUESTRESIZE notification
  1028. // message to its parent window.
  1029. //
  1030. // NOTE: This message is useful during WM_SIZE processing for the parent of a
  1031. //       bottomless rich edit control.
  1032. //
  1033. void
  1034. TRichEdit::RequestResize()
  1035. {
  1036.   SendMessage(EM_REQUESTRESIZE);
  1037. }
  1038.  
  1039. //
  1040. // Retrieve an IRichEditOle object that a client can use to access a rich edit
  1041. // control's OLE functionality. Returns 'true' if successful, or false
  1042. // otherwise.
  1043. //
  1044. bool
  1045. TRichEdit::GetOleInterface(IRichEditOle far* &pInterface) const
  1046. {
  1047.   return CONST_CAST(TRichEdit*,this)->SendMessage(EM_GETOLEINTERFACE,
  1048.                                 0, TParam2((void far* far*)&pInterface)) != 0;
  1049. }
  1050.  
  1051. //
  1052. // Set an IRichEditOleCallback object that the rich edit control uses to get
  1053. // OLE-related resources and information from the client. Returns 'true' if
  1054. // successful, or false otherwise.
  1055. //
  1056. bool
  1057. TRichEdit::SetOleInterface(IRichEditOleCallback far* /*pInterface*/)
  1058. {
  1059. #if 0
  1060.   // EM_SETOLEINTERFACE: Documented but missing...
  1061.   return SendMessage(EM_SETOLEINTERFACE, 0, TParam2(pInterface)) != 0;
  1062. #else
  1063.   return false;
  1064. #endif
  1065. }
  1066.  
  1067. //
  1068. // Retrieve the event mask for the rich edit control. The event mask specifies
  1069. // which notification messages the control sends to its parent window.
  1070. //
  1071. ulong
  1072. TRichEdit::GetEventMask() const
  1073. {
  1074.   return CONST_CAST(TRichEdit*,this)->SendMessage(EM_GETEVENTMASK);
  1075. }
  1076.  
  1077. //
  1078. // Set the event mask for a rich edit control. The event mask specifies which
  1079. // notification messages the control sends to its parent window. The 'msk'
  1080. // parameter can be zero or more of the following values:
  1081. //
  1082. //  Value               Meaning
  1083. //  -----               -------
  1084. //  ENM_CHANGE          Sends EN_CHANGE notifications.
  1085. //  ENM_CORRECTTEXT     Sends EN_CORRECTTEXT notifications.
  1086. //  ENM_DROPFILES       Sends EN_DROPFILES notifications.
  1087. //  ENM_KEYEVENTS       Sends EN_MSGFILTER  notifications for keyboard events.
  1088. //  ENM_MOUSEEVENTS     Sends EN_MSGFILTER notifications for mouse events.
  1089. //  ENM_PROTECTED       Sends EN_PROTECTED notifications.
  1090. //  ENM_RESIZEREQUEST   Sends EN_REQUESTRESIZE notifications.
  1091. //  ENM_SCROLL          Sends EN_HSCROLL notifications.
  1092. //  ENM_SELCHANGE       Sends EN_SELCHANGE notifications.
  1093. //  ENM_UPDATE          Sends EN_UPDATE notifications
  1094. //
  1095. ulong
  1096. TRichEdit::SetEventMask(ulong msk)
  1097. {
  1098.   return SendMessage(EM_SETEVENTMASK, 0, TParam2(msk));
  1099. }
  1100.  
  1101. //
  1102. // WM_GETDLGCODE handler to bypass TEdit's handler which caters for
  1103. // validators.
  1104. //
  1105. uint
  1106. TRichEdit::EvGetDlgCode(MSG far* msg)
  1107. {
  1108.   return TWindow::EvGetDlgCode(msg);
  1109. }
  1110.  
  1111. //
  1112. // WM_CHAR handler to bypass TEdit's handler which caters for
  1113. // validators.
  1114. //
  1115. void
  1116. TRichEdit::EvChar(uint /*key*/, uint /*repeatCount*/, uint /*flags*/)
  1117. {
  1118.   DefaultProcessing();
  1119. }
  1120.  
  1121. //
  1122. // WM_KEYDOWN handler to bypass TEdit's handler which caters for
  1123. // validators.
  1124. //
  1125. void
  1126. TRichEdit::EvKeyDown(uint /*key*/, uint /*repeatCount*/, uint /*flags*/)
  1127. {
  1128.   DefaultProcessing();
  1129. }
  1130.  
  1131. //
  1132. // WM_KILLFOCUS handler to bypass TEdit's handler which caters for
  1133. // validators.
  1134. //
  1135. void
  1136. TRichEdit::EvKillFocus(THandle hGetFocus)
  1137. {
  1138.   TControl::EvKillFocus(hGetFocus);
  1139. }
  1140.  
  1141. //
  1142. // WM_SETFOCUS handler to bypass TEdit's handler which caters for
  1143. // validators.
  1144. //
  1145. void
  1146. TRichEdit::EvSetFocus(THandle /*hLostFocus*/)
  1147. {
  1148.   DefaultProcessing();
  1149. }
  1150.  
  1151. //
  1152. // This function is called for Cut/Copy/Delete menu items to determine
  1153. // whether or not the item is enabled.
  1154. //
  1155. void
  1156. TRichEdit::CeHasSelect(TCommandEnabler& commandHandler)
  1157. {
  1158.   uint sPos, ePos;
  1159.  
  1160.   GetSelection(sPos, ePos);
  1161.   commandHandler.Enable(sPos != ePos);
  1162. }
  1163.  
  1164. //
  1165. // This function is called for the Paste menu item to determine whether or
  1166. // not the item is enabled.
  1167. //
  1168. void
  1169. TRichEdit::CeEditPaste(TCommandEnabler& ce)
  1170. {
  1171.   TClipboard clip(*this);
  1172.   if (clip.IsClipboardFormatAvailable(CF_TEXT) ||
  1173.       clip.IsClipboardFormatAvailable(CF_OEMTEXT))
  1174.     ce.Enable(true);
  1175.   else
  1176.     ce.Enable(false);
  1177. }
  1178.  
  1179. //
  1180. // This function is called for the Clear menu item to determine whether or
  1181. // not the item is enabled.
  1182. //
  1183. void
  1184. TRichEdit::CeEditClear(TCommandEnabler& commandHandler)
  1185. {
  1186.   commandHandler.Enable(!(GetNumLines() == 1 && GetLineLength(0) == 0));
  1187. }
  1188.  
  1189. //
  1190. // This function is called for the Undo menu item to determine whether or
  1191. // not the item is enabled.
  1192. //
  1193. void
  1194. TRichEdit::CeEditUndo(TCommandEnabler& commandHandler)
  1195. {
  1196.   commandHandler.Enable(CanUndo());
  1197. }
  1198.  
  1199. //
  1200. // Return name of predefined Windows edit class
  1201. //
  1202. char far*
  1203. TRichEdit::GetClassName()
  1204. {
  1205.   return "RICHEDIT";
  1206. }
  1207.  
  1208. //
  1209. // Updates the list of filters describing files which can be opened by
  1210. // the rich edit control.
  1211. //
  1212. //
  1213. void
  1214. TRichEdit::SetupWindow()
  1215. {
  1216.   TEditFile::SetupWindow();
  1217.  
  1218.   //Load RichEdit's filter
  1219.   //
  1220.   FileData.SetFilter(GetModule()->LoadString(IDS_RICHEDITFILTER).c_str());
  1221. }
  1222.  
  1223. //
  1224. // Callback used when reading data from a stream into a rich edit control.
  1225. //
  1226. DWORD CALLBACK
  1227. RichEditStrmInWithIStream(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
  1228. {
  1229.   PRECONDITION(dwCookie);
  1230.  
  1231.   istream& is = *((istream*)dwCookie);
  1232.  
  1233.   // Return 0 if transfer is complete
  1234.   //
  1235.   if (is.eof()) {
  1236.    *pcb = 0;
  1237.     return 0;
  1238.   }
  1239.  
  1240.   // Read data in buffer
  1241.   //
  1242.   is.read(pbBuff, cb);
  1243.  
  1244.   // Indicate amount of data read
  1245.   //
  1246.   *pcb = is.gcount();
  1247.  
  1248.   // Docs says to return the amount of bytes read in but that does not seem
  1249.   // to be correct!!! Returning 0, on the other side, seems to work - so
  1250.   // stick with it until...
  1251.   //
  1252.   return 0;
  1253. }
  1254.  
  1255. //
  1256. // Callback used when writing out the contents of a rich edit control to
  1257. // a data stream.
  1258. //
  1259. DWORD CALLBACK
  1260. RichEditStrmOutWithOstream(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
  1261. {
  1262.   PRECONDITION(dwCookie);
  1263.  
  1264.   ostream& os = *((ostream*)dwCookie);
  1265.  
  1266.   // Save current stream location and write data to buffer
  1267.   //
  1268.   streampos pCnt = os.tellp();
  1269.   os.write(pbBuff, cb);
  1270.  
  1271.   // Indicate the number of bytes written to the file
  1272.   //
  1273.   *pcb = os.tellp() - pCnt;
  1274.   return 0;
  1275. }
  1276.  
  1277. //
  1278. // Overriden to bypass TEdit's 'Transfer' method.
  1279. // NOTE: There's no transfer-support for rich edit controls.
  1280. //
  1281. uint
  1282. TRichEdit::Transfer(void* /*buffer*/, TTransferDirection /*direction*/)
  1283. {
  1284.   // NOTE: No transfer support for rich edit control
  1285.   //
  1286.   return 0;
  1287. }
  1288.  
  1289. //
  1290. // Read the data from the specified stream into the rich edit control. The
  1291. // 'fmt' parameter can be one of the following data formats, optionally
  1292. // combined with the SFF_SELECTION flag:
  1293. //
  1294. //    Value               Meaning
  1295. //    -----               -------
  1296. //    SF_TEXT             Text
  1297. //    SF_RTF              Rich-text format
  1298. //
  1299. // If the SFF_SELECTION flag is specified, the stream replaces the contents of
  1300. // the current selection. Otherwise, the stream replaces the entire contents
  1301. // of the control.
  1302. //
  1303. bool
  1304. TRichEdit::ReadFromStream(istream& is, uint fmt)
  1305. {
  1306.   TEditStream edStrm(DWORD((istream*)&is), RichEditStrmInWithIStream);
  1307.   StreamIn(fmt, edStrm);
  1308.   return edStrm.dwError == 0;
  1309. }
  1310.  
  1311. //
  1312. // Write the contents of the rich edit control to the specified data stream.
  1313. // The 'fmt' parameter can be one of the following values, optionally
  1314. // combined with the SFF_SELECTION flag:
  1315. //
  1316. //    Value               Meaning
  1317. //    -----               -------
  1318. //    SF_TEXT             Text with spaces in place of OLE objects
  1319. //    SF_RTF              Rich-text format (RTF)
  1320. //    SF_RTFNOOBJS        RTF with spaces in place of OLE object.
  1321. //    SF_TEXTIZED         Text with a text representation of OLE objects.
  1322. //
  1323. // NOTE: The SF_RTFNOOBJS option is useful if an application stores OLE
  1324. //       objects itself, as RTF representation of OLE objects is not very
  1325. //       compact.
  1326. //       If the SFF_SELECTION flag is specified, only the contents of the
  1327. //       current selection are streamed out. Otherwise, the entire contents of
  1328. //       the control are streamed out.
  1329. //
  1330. bool
  1331. TRichEdit::WriteToStream(ostream& os, uint fmt)
  1332. {
  1333.   TEditStream edStrm(DWORD((ostream*)&os), RichEditStrmOutWithOstream);
  1334.   StreamOut(fmt, edStrm);
  1335.   return edStrm.dwError == 0;
  1336. }
  1337.  
  1338. //
  1339. // Read the contents of the specified file in the rich edit control. Returns
  1340. // 'true' if successful, or false otherwise.
  1341. //
  1342. bool
  1343. TRichEdit::Read(const char far* fileName)
  1344. {
  1345.   if (!fileName)
  1346.     if (FileName)
  1347.       fileName = FileName;
  1348.     else
  1349.       return false;
  1350.  
  1351.   ifstream ifs(fileName, ios::in|ios::binary);
  1352.   if (ifs) {
  1353.     // Could check for a valid file (eg. FileSize != 0)
  1354.     // before proceeding with a call to Clear() here.
  1355.     //
  1356.     Clear();
  1357.  
  1358.     // Stream in data from file
  1359.     //
  1360.     if (ReadFromStream(ifs, Format)) {
  1361.       ClearModify();
  1362.       return true;
  1363.     }
  1364.   }
  1365.   return false;
  1366. }
  1367.  
  1368. //
  1369. // Write the contents of the edit control to the specified file. Returns
  1370. // 'true' if successful, or false otherwise.
  1371. //
  1372. bool
  1373. TRichEdit::Write(const char far* fileName)
  1374. {
  1375.   if (!fileName)
  1376.     if (FileName)
  1377.       fileName = FileName;
  1378.     else
  1379.       return false;
  1380.  
  1381.   ofstream ofs(fileName, ios::out|ios::binary);
  1382.   if (ofs) {
  1383.     if (WriteToStream(ofs, Format)) {
  1384.       ClearModify();
  1385.       return true;
  1386.     }
  1387.   }
  1388.   return false;
  1389. }
  1390.  
  1391. //
  1392. // Object wrapper which loads the RichEdit DLL
  1393. //
  1394. TRichEditModule::TRichEditModule() 
  1395.              :TModule(RichEditDllName, true, true)
  1396. {
  1397. }
  1398.  
  1399.