home *** CD-ROM | disk | FTP | other *** search
/ Prima Shareware 3 / DuCom_Prima-Shareware-3_cd1.bin / PROGRAMO / C / RICHCT / RCHEDTCN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-05  |  25.7 KB  |  975 lines

  1. /*  Project richctrl
  2.     DHB Software
  3.     Copyright ⌐ 1996. All Rights Reserved.
  4.  
  5.     SUBSYSTEM:    richctrl.apx Application
  6.     FILE:         rchedtcn.cpp
  7.     AUTHOR:       David H. Borg
  8.  
  9.  
  10.     OVERVIEW
  11.     ========
  12.     Source file for implementation of RichEditControl (TEdit).
  13. */
  14.  
  15. #include <owl\owlpch.h>
  16. #pragma hdrstop
  17.  
  18. #include <dir.h>
  19. #include "rchctrla.h"
  20. #include "flopndlg.h"
  21. #include "filsvdlg.h"
  22. #include "rchedtcn.h"
  23.  
  24.  
  25. //
  26. // Build a response table for all messages/commands handled
  27. // by the application.
  28. //
  29. DEFINE_RESPONSE_TABLE1(RichEditControl, TEdit)
  30. //{{RichEditControlRSP_TBL_BEGIN}}
  31.     EV_MESSAGE( WM_CHANGEFONTFACE, CmChangeFontFace),
  32.     EV_COMMAND_ENABLE( IDC_FONTFACE, CmEnFontFace),
  33.     EV_MESSAGE( WM_CHANGEFONTSIZE, CmChangeFontSize),
  34.     EV_COMMAND_ENABLE( IDC_FONTSIZE, CmEnFontSize),
  35.     EV_COMMAND(CM_FILENEW, CmFileNew),
  36.     EV_COMMAND(CM_FILESAVE1, CmFileSave),
  37.     EV_COMMAND_ENABLE(CM_FILESAVE1, CmEnFileSave),
  38.     EV_COMMAND(CM_FILEOPENRTF, CmFileOpenRtf),
  39.     EV_COMMAND(CM_FILEOPENTEXT, CmFileOpenText),
  40.     EV_COMMAND(CM_SAVEASRTF, CmSaveAsRtf),
  41.     EV_COMMAND(CM_SAVEASTEXT, CmSaveAsText),
  42.     EV_COMMAND_ENABLE(CM_SAVEASRTF, CmEnSaveAs),
  43.     EV_COMMAND_ENABLE(CM_SAVEASTEXT, CmEnSaveAs),
  44.     EV_COMMAND(CM_EDITFIND, CmEditFind),
  45.     EV_COMMAND_ENABLE(CM_EDITFIND, CmEnEditFindReplace),
  46.     EV_COMMAND(CM_EDITFINDNEXT, CmEditFindNext),
  47.     EV_COMMAND_ENABLE(CM_EDITFINDNEXT, CmEnEditFindNext),
  48.     EV_REGISTERED(FINDMSGSTRING, EvFindMsg),
  49.     EV_COMMAND(CM_FORMATBOLD, CmFormatBold),
  50.     EV_COMMAND_ENABLE(CM_FORMATBOLD, CmEnFormatBold),
  51.     EV_COMMAND(CM_FORMATITALIC, CmFormatItalic),
  52.     EV_COMMAND_ENABLE(CM_FORMATITALIC, CmEnFormatItalic),
  53.     EV_COMMAND(CM_FORMATUNDERLINE, CmFormatUnderline),
  54.     EV_COMMAND_ENABLE(CM_FORMATUNDERLINE, CmEnFormatUnderline),
  55.     EV_COMMAND(CM_FORMATLEFT, CmFormatLeft),
  56.     EV_COMMAND_ENABLE(CM_FORMATLEFT, CmEnFormatLeft),
  57.     EV_COMMAND(CM_FORMATCENTER, CmFormatCenter),
  58.     EV_COMMAND_ENABLE(CM_FORMATCENTER, CmEnFormatCenter),
  59.     EV_COMMAND(CM_FORMATRIGHT, CmFormatRight),
  60.     EV_COMMAND_ENABLE(CM_FORMATRIGHT, CmEnFormatRight),
  61.     EV_COMMAND(CM_FORMATFONT, CmFormatFont),
  62.     EV_COMMAND_ENABLE(CM_FORMATFONT, CmEnFormatFont),
  63.     EV_WM_KEYDOWN,
  64.     EV_WM_LBUTTONDOWN,
  65. //{{RichEditControlRSP_TBL_END}}
  66. END_RESPONSE_TABLE;
  67.  
  68.  
  69. //{{RichEditControl Implementation}}
  70.  
  71.  
  72. RichEditControl::RichEditControl (TWindow* parent, int id, const char far* text, int x, int y, int w, int h, uint textLen, bool multiline, TModule* module):
  73.     TEdit(parent, id, text, x, y, w, h, textLen, multiline, module),
  74.             FileName(0), FindReplaceDialog(0), FindReplaceCmd(0),
  75.             streamFormat(SF_RTF), updtFontFace(true), updtFontSize(true)
  76. {
  77.     // INSERT>> Your constructor code here.
  78.  
  79.     // add custom styles for this control
  80.     Attr.ExStyle = WS_EX_CLIENTEDGE;
  81.     Attr.Param = 0;
  82.     Attr.Style = WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_SAVESEL |
  83.                  ES_NOHIDESEL | ECO_AUTOVSCROLL | WS_VSCROLL;
  84.  
  85.     // Common file file flags and filters for Open/Save As dialogs.  Filename and directory are
  86.     // computed in the member functions CmFileOpen, and CmSaveAs.
  87.     FileData.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
  88.     FileData.SetFilter(    "Rich Text Files (*.rtf)|*.RTF|"
  89.                         "Text Files (*.txt)|*.TXT|"
  90.                         "All Files (*.*)|*.*|");
  91.     FileData.FilterIndex = 0;
  92.  
  93.     // initialize flags to create a plain and simple find dialog
  94.     FindReplaceData.Flags = FR_HIDEUPDOWN | FR_HIDEMATCHCASE | FR_HIDEWHOLEWORD;
  95. }
  96.  
  97.  
  98. RichEditControl::~RichEditControl ()
  99. {
  100.     Destroy();
  101.  
  102.     // INSERT>> Your destructor code here.
  103.  
  104. }
  105.  
  106.  
  107. // this identifies that the window is a rich edit control
  108. char far* RichEditControl::GetClassName ()
  109. {
  110.     return "RICHEDIT";
  111. }
  112.  
  113.  
  114. void RichEditControl::CmFileNew ()
  115. {
  116.     // INSERT>> Your code here.
  117.  
  118.     if (CanClear()) {
  119.         streamFormat = SF_RTF;
  120.         Clear();
  121.         ClearModify();
  122.         SetFileName(0);
  123.         Invalidate();
  124.     }
  125. }
  126.  
  127.  
  128. void RichEditControl::CmFileSave ()
  129. {
  130.     // INSERT>> Your code here.
  131.  
  132.     if( IsModified()){
  133.         if( FileName == 0){
  134.             DoSaveAsCmd();
  135.         } else if( Save( FileName)) {
  136.             ClearModify();
  137.         } else {
  138.             string message( GetModule()->LoadString( IDS_UNABLEWRITE));
  139.             char*  buf = new char[MAXPATH + message.length()];
  140.             wsprintf( buf, message.c_str(), FileName);
  141.             MessageBox( buf, GetApplication()->GetName(), MB_ICONEXCLAMATION | MB_OK);
  142.             delete buf;
  143.         }
  144.     }
  145.     return;
  146. }
  147.  
  148.  
  149. void RichEditControl::CmEnFileSave (TCommandEnabler &tce)
  150. {
  151.     // INSERT>> Your code here.
  152.  
  153.     tce.Enable( IsModified());
  154. }
  155.  
  156.  
  157. void RichEditControl::CmFileOpenRtf ()
  158. {
  159.     // INSERT>> Your code here.
  160.  
  161.     // open a file as an rtf document
  162.     streamFormat = SF_RTF;
  163.     DoFileOpenCmd();
  164. }
  165.  
  166.  
  167. void RichEditControl::CmFileOpenText ()
  168. {
  169.     // INSERT>> Your code here.
  170.  
  171.     // open a file as a text only document
  172.     streamFormat = SF_TEXT;
  173.     DoFileOpenCmd();
  174. }
  175.  
  176.  
  177. void RichEditControl::CmSaveAsRtf ()
  178. {
  179.     // INSERT>> Your code here.
  180.  
  181.     streamFormat = SF_RTF;
  182.     DoSaveAsCmd();
  183. }
  184.  
  185.  
  186. void RichEditControl::CmSaveAsText ()
  187. {
  188.     // INSERT>> Your code here.
  189.  
  190.     streamFormat = SF_TEXT;
  191.     DoSaveAsCmd();
  192. }
  193.  
  194.  
  195. void RichEditControl::DoFileOpenCmd ()
  196. {
  197.     // INSERT>> Your code here.
  198.  
  199.     if( CanClear()) {
  200.         Clear();
  201.         SetFileName(0);
  202.         *FileData.FileName = 0;
  203.         if( streamFormat == SF_RTF)
  204.             FileData.FilterIndex = 1;
  205.         else
  206.             FileData.FilterIndex = 2;
  207.         if( FileOpenDialog( this, FileData).Execute() == IDOK)
  208.             if( Open( FileData.FileName)){
  209.                 SetFileName( FileData.FileName);
  210.                 Invalidate();
  211.             } else {
  212.                 string message( GetModule()->LoadString(IDS_UNABLEREAD));
  213.                 char*  buf = new char[MAXPATH + message.length()];
  214.                 wsprintf( buf, message.c_str(), FileData.FileName);
  215.                 MessageBox( buf, GetApplication()->GetName(), MB_ICONEXCLAMATION | MB_OK);
  216.                 delete buf;
  217.             }
  218.     }
  219. }
  220.  
  221.  
  222. void RichEditControl::DoSaveAsCmd ()
  223. {
  224.     // INSERT>> Your code here.
  225.  
  226.     if( FileName == 0)
  227.         *FileData.FileName = 0;
  228.     else
  229.         strcpy( FileData.FileName, FileName);
  230.  
  231.     if( streamFormat == SF_RTF)
  232.         FileData.FilterIndex = 1;
  233.     else
  234.         FileData.FilterIndex = 2;
  235.  
  236.     if( FileSaveDialog( this, FileData).Execute() == IDOK) {
  237.         if( Save( FileData.FileName)){
  238.             ClearModify();
  239.             SetFileName( FileData.FileName);
  240.         } else {
  241.             string message( GetModule()->LoadString( IDS_UNABLEWRITE));
  242.             char* buf = new char[MAXPATH + message.length()];
  243.             wsprintf( buf, message.c_str(), FileData.FileName);
  244.             MessageBox( buf, GetApplication()->GetName(), MB_ICONEXCLAMATION | MB_OK);
  245.             delete buf;
  246.         }
  247.     }
  248.     return;
  249. }
  250.  
  251.  
  252. void RichEditControl::CmEditFind ()
  253. {
  254.     // INSERT>> Your code here.
  255.  
  256.     if (!FindReplaceCmd) {
  257.         delete FindReplaceDialog;
  258.         FindReplaceCmd = CM_EDITFIND;
  259.         FindReplaceDialog = new TFindDialog( this, FindReplaceData);
  260.         FindReplaceDialog->Create();
  261.     }
  262. }
  263.  
  264.  
  265. void RichEditControl::CmEnEditFindReplace (TCommandEnabler &tce)
  266. {
  267.     // INSERT>> Your code here.
  268.  
  269.     tce.Enable( !FindReplaceCmd);
  270. }
  271.  
  272.  
  273. void RichEditControl::CmEditFindNext ()
  274. {
  275.     // INSERT>> Your code here.
  276.  
  277.     if (FindReplaceDialog)
  278.         FindReplaceDialog->UpdateData();
  279.     FindReplaceData.Flags |= FR_FINDNEXT;
  280.     DoFind();
  281. }
  282.  
  283.  
  284. void RichEditControl::CmEnEditFindNext (TCommandEnabler &tce)
  285. {
  286.     // INSERT>> Your code here.
  287.  
  288.     tce.Enable((FindReplaceData.FindWhat && *(FindReplaceData.FindWhat)) ? true : false);
  289. }
  290.  
  291.  
  292. // Perform a search or replace operation based on information in FindReplaceData
  293. void RichEditControl::DoFind()
  294. {
  295.     FINDTEXT findText;
  296.  
  297.     uint startSel, endSel;
  298.     GetSelection( startSel, endSel);
  299.     findText.chrg.cpMin = endSel;
  300.     findText.chrg.cpMax = -1;
  301.     findText.lpstrText = FindReplaceData.FindWhat;
  302.     long position = (long)SendMessage( EM_FINDTEXT, (WPARAM)true, (LPARAM)&findText);
  303.  
  304.     if( position >= 0) {
  305.         SetSelection( position, position + strlen( FindReplaceData.FindWhat));
  306.     } else {
  307.         if( FindReplaceData.Flags & (FR_FINDNEXT)) {
  308.             string errTemplate(GetModule()->LoadString(IDS_CANNOTFIND));
  309.             char  errMsg[81];
  310.             wsprintf(errMsg, errTemplate.c_str(), (const char far*)FindReplaceData.FindWhat);
  311.             TWindow* w = FindReplaceDialog ? (TWindow*)FindReplaceDialog : (TWindow*)this;
  312.             w->MessageBox(errMsg, GetApplication()->GetName(), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
  313.             SetSelection( 0, 0);
  314.         }
  315.     }
  316. }
  317.  
  318.  
  319. // Respond to the message sent by the modeless find/replace dialog by
  320. // performing a search. Or, if the dialog has terminated, zero search command
  321. LRESULT RichEditControl::EvFindMsg(WPARAM, LPARAM lParam)
  322. {
  323.     PRECONDITION(FindReplaceDialog);
  324.  
  325.     FindReplaceDialog->UpdateData(lParam);
  326.     if (FindReplaceData.Flags & FR_DIALOGTERM)
  327.         FindReplaceCmd = 0;
  328.     else
  329.         DoFind();
  330.     return 0;
  331. }
  332.  
  333.  
  334. // returns true if the text is unchanged, or if it is ok to delete it
  335. bool RichEditControl::CanClear()
  336. {
  337.     bool retVal = true;
  338.     int choice;
  339.  
  340.     if( IsModified()) {
  341.         string message( GetModule()->LoadString( IDS_FILECHANGED));
  342.         string empty( GetModule()->LoadString( IDS_UNTITLEDFILE));
  343.         char*  buf = new char[MAXPATH+message.length()];
  344.  
  345.         wsprintf( buf, message.c_str(), FileName ? (const char far*)FileName : empty.c_str());
  346.         choice = MessageBox( buf, GetApplication()->GetName(), MB_YESNOCANCEL|MB_ICONQUESTION);
  347.  
  348.         if( choice == IDYES){
  349.             CmFileSave();
  350.         } else if( choice == IDCANCEL){
  351.             retVal = false;
  352.         }
  353.         delete buf;
  354.     }
  355.     return retVal;
  356. }
  357.  
  358.  
  359. // set the new file name and update the window's caption
  360. void RichEditControl::SetFileName (const char far* newName)
  361. {
  362.     if( newName != FileName) {
  363.         delete FileName;
  364.         FileName = newName != 0 ? strnewdup(newName) : 0;
  365.     }
  366.     if( FileName != 0){
  367.         SetDocTitle( FileName, 0);
  368.     } else {
  369.         string noName( GetModule()->LoadString(IDS_UNTITLEDFILE));
  370.         SetDocTitle(  noName.c_str(), 0);
  371.     }
  372. }
  373.  
  374.  
  375. bool RichEditControl::Open (  const char far* fileName)
  376. {
  377.     HFILE hFile;
  378.     OFSTRUCT ofStruct;
  379.     EDITSTREAM editStream;
  380.  
  381.     ofStruct.cBytes = sizeof(ofStruct);
  382.  
  383.     if( (hFile = OpenFile( fileName, &ofStruct, OF_READ)) != HFILE_ERROR)
  384.     {
  385.         // dwCookie is an app-defined value that holds
  386.         // the handle to the file.
  387.         editStream.dwCookie = hFile;
  388.         editStream.pfnCallback = OpenCallback;
  389.         editStream.dwError = 0;
  390.         long bytesRead = 0;
  391.         while( bytesRead == editStream.dwError){
  392.             bytesRead = (long)SendMessage( EM_STREAMIN, (WPARAM)streamFormat, (LPARAM)&editStream);
  393.         }
  394.         if( bytesRead >= 0)
  395.             editStream.dwError = 0;
  396.  
  397.         // Reset the dirty bit.
  398.         ClearModify();
  399.  
  400.         CloseHandle((HANDLE)hFile);
  401.         return !editStream.dwError;
  402.     }
  403.     return false;
  404. }
  405.  
  406.  
  407. DWORD CALLBACK RichEditControl::OpenCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
  408. {
  409.     return( !ReadFile( (HANDLE)dwCookie, pbBuff, cb, (unsigned long *)pcb, 0));
  410. }
  411.  
  412.  
  413. bool RichEditControl::Save( const char far* fileName)
  414. {
  415.     HFILE hFile;
  416.     OFSTRUCT ofStruct;
  417.     EDITSTREAM editStream;
  418.  
  419.     if( (hFile = OpenFile( fileName, &ofStruct, OF_CREATE)) != HFILE_ERROR)
  420.     {
  421.         editStream.dwCookie = hFile;
  422.         editStream.dwError = 0;
  423.         editStream.pfnCallback = SaveCallback;
  424.         SendMessage( EM_STREAMOUT, (WPARAM)streamFormat, (LPARAM)&editStream);
  425.         CloseHandle( (HANDLE)hFile);
  426.         return true;
  427.     }
  428.     return false;
  429. }
  430.  
  431.  
  432. DWORD CALLBACK RichEditControl::SaveCallback (DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb)
  433. {
  434.     return( !WriteFile( (HANDLE)dwCookie, pbBuff, cb, (unsigned long *)pcb, 0));
  435. }
  436.  
  437.  
  438. void RichEditControl::CmFormatBold ()
  439. {
  440.     // INSERT>> Your code here.
  441.  
  442.     // fill out character format structure to get bold format information
  443.     charFormat.cbSize = sizeof(charFormat);
  444.     charFormat.dwMask = CFM_BOLD;
  445.  
  446.     // get current character format
  447.     SendMessage( EM_GETCHARFORMAT, true, (LPARAM)&charFormat);
  448.  
  449.     // toggle the bold effect
  450.     charFormat.dwEffects ^= CFE_BOLD;
  451.  
  452.     // set the new character format
  453.     SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFormat);
  454.  
  455.     UpdateFormats();
  456. }
  457.  
  458.  
  459. void RichEditControl::CmEnFormatBold (TCommandEnabler &tce)
  460. {
  461.     // INSERT>> Your code here.
  462.  
  463.     // toggle the bold effect button
  464.     tce.SetCheck( (charFormat.dwEffects & CFE_BOLD) == CFE_BOLD);
  465. }
  466.  
  467.  
  468. void RichEditControl::CmFormatItalic ()
  469. {
  470.     // INSERT>> Your code here.
  471.  
  472.     // fill out character format structure to get italic format information
  473.     charFormat.cbSize = sizeof(charFormat);
  474.     charFormat.dwMask = CFM_ITALIC;
  475.  
  476.     // get current character format
  477.     SendMessage( EM_GETCHARFORMAT, true, (LPARAM)&charFormat);
  478.  
  479.     // toggle the italic effect
  480.     charFormat.dwEffects ^= CFE_ITALIC;
  481.  
  482.     // set the new character format
  483.     SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFormat);
  484.  
  485.     UpdateFormats();
  486. }
  487.  
  488.  
  489. void RichEditControl::CmEnFormatItalic (TCommandEnabler &tce)
  490. {
  491.     // INSERT>> Your code here.
  492.  
  493.     // toggle the italic effect button
  494.     tce.SetCheck( (charFormat.dwEffects & CFE_ITALIC) == CFE_ITALIC);
  495. }
  496.  
  497.  
  498. void RichEditControl::CmFormatUnderline ()
  499. {
  500.     // INSERT>> Your code here.
  501.  
  502.     // fill out character format structure to get underline format information
  503.     charFormat.cbSize = sizeof(charFormat);
  504.     charFormat.dwMask = CFM_UNDERLINE;
  505.  
  506.     // get current character format
  507.     SendMessage( EM_GETCHARFORMAT, true, (LPARAM)&charFormat);
  508.  
  509.     // toggle the underline effect
  510.     charFormat.dwEffects ^= CFE_UNDERLINE;
  511.  
  512.     // set the new character format
  513.     SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFormat);
  514.  
  515.     UpdateFormats();
  516. }
  517.  
  518.  
  519. void RichEditControl::CmEnFormatUnderline (TCommandEnabler &tce)
  520. {
  521.     // INSERT>> Your code here.
  522.  
  523.     // toggle the underline effect button
  524.     tce.SetCheck( (charFormat.dwEffects & CFE_UNDERLINE) == CFE_UNDERLINE);
  525. }
  526.  
  527.  
  528. void RichEditControl::CmFormatLeft ()
  529. {
  530.     // INSERT>> Your code here.
  531.  
  532.     // fill out paragraph format structure with left alignment information
  533.     paraFormat.cbSize = sizeof(paraFormat);
  534.     paraFormat.dwMask = PFM_ALIGNMENT;
  535.     paraFormat.wAlignment = PFA_LEFT;
  536.  
  537.     // set the new paragraph alignment
  538.     SendMessage( EM_SETPARAFORMAT, 0, (LPARAM)¶Format);
  539. }
  540.  
  541.  
  542. void RichEditControl::CmEnFormatLeft (TCommandEnabler &tce)
  543. {
  544.     // INSERT>> Your code here.
  545.  
  546.     // toggle the left justify effect button
  547.     tce.SetCheck( paraFormat.wAlignment == PFA_LEFT);
  548. }
  549.  
  550.  
  551. void RichEditControl::CmFormatCenter ()
  552. {
  553.     // INSERT>> Your code here.
  554.  
  555.     // fill out paragraph format structure with left alignment information
  556.     paraFormat.cbSize = sizeof(paraFormat);
  557.     paraFormat.dwMask = PFM_ALIGNMENT;
  558.     paraFormat.wAlignment = PFA_CENTER;
  559.  
  560.     // set the new paragraph alignment
  561.     SendMessage( EM_SETPARAFORMAT, 0, (LPARAM)¶Format);
  562. }
  563.  
  564.  
  565. void RichEditControl::CmEnFormatCenter (TCommandEnabler &tce)
  566. {
  567.     // INSERT>> Your code here.
  568.  
  569.     // toggle the center effect button
  570.     tce.SetCheck( paraFormat.wAlignment == PFA_CENTER);
  571. }
  572.  
  573.  
  574. void RichEditControl::CmFormatRight ()
  575. {
  576.     // INSERT>> Your code here.
  577.  
  578.     // fill out paragraph format structure with left alignment information
  579.     paraFormat.cbSize = sizeof(paraFormat);
  580.     paraFormat.dwMask = PFM_ALIGNMENT;
  581.     paraFormat.wAlignment = PFA_RIGHT;
  582.  
  583.     // set the new paragraph alignment
  584.     SendMessage( EM_SETPARAFORMAT, 0, (LPARAM)¶Format);
  585. }
  586.  
  587.  
  588. void RichEditControl::CmEnFormatRight (TCommandEnabler &tce)
  589. {
  590.     // INSERT>> Your code here.
  591.  
  592.     // toggle the right justify effect button
  593.     tce.SetCheck( paraFormat.wAlignment == PFA_RIGHT);
  594. }
  595.  
  596.  
  597. void RichEditControl::CmFormatFont ()
  598. {
  599.     // INSERT>> Your code here.
  600.  
  601.     // set all FontData structure parameters based on charFormat information
  602.     FontData.DC = 0;
  603.     FontData.Flags = CF_EFFECTS | CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
  604.     FontData.Color = TColor(charFormat.crTextColor);
  605.     FontData.FontType = SCREEN_FONTTYPE;
  606.     TDC dc( ::GetDC( HWindow));
  607.     FontData.LogFont.lfHeight = MulDiv( -charFormat.yHeight / 20, dc.GetDeviceCaps(LOGPIXELSY), 72);
  608.     ::ReleaseDC( HWindow, dc);
  609.     FontData.LogFont.lfWeight = (charFormat.dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
  610.     FontData.LogFont.lfItalic = (charFormat.dwEffects & CFE_ITALIC) ? (BYTE)1 : (BYTE)0;
  611.     FontData.LogFont.lfUnderline = (charFormat.dwEffects & CFE_UNDERLINE) ? (BYTE)1 : (BYTE)0;
  612.     FontData.LogFont.lfStrikeOut = (charFormat.dwEffects & CFE_STRIKEOUT) ? (BYTE)1 : (BYTE)0;
  613.     strncpy( FontData.LogFont.lfFaceName, charFormat.szFaceName, LF_FACESIZE);
  614.     FontData.SizeMin = 0;
  615.     FontData.SizeMax = 0;
  616.  
  617.     // execute Windows 95 standard choosefont dialog
  618.     if (TChooseFontDialog(this, FontData).Execute() == IDOK) {
  619.         // fill out character format structure to get font type information
  620.         charFormat.cbSize = sizeof(charFormat);
  621.         charFormat.dwMask = CFM_ITALIC | CFM_BOLD | CFM_UNDERLINE | CFM_COLOR |
  622.                             CFM_SIZE | CFM_FACE | CFM_STRIKEOUT;
  623.         charFormat.dwEffects = 0;        // clear old effects
  624.         charFormat.dwEffects |= FontData.LogFont.lfWeight == FW_BOLD ? CFE_BOLD : 0;
  625.         charFormat.dwEffects |= FontData.LogFont.lfItalic ? CFE_ITALIC : 0;
  626.         charFormat.dwEffects |= FontData.LogFont.lfUnderline ? CFE_UNDERLINE : 0;
  627.         charFormat.dwEffects |= FontData.LogFont.lfStrikeOut ? CFE_STRIKEOUT : 0;
  628.         strncpy( charFormat.szFaceName, FontData.LogFont.lfFaceName, LF_FACESIZE);
  629.         charFormat.yHeight = FontData.PointSize / 10 * 20;
  630.         charFormat.crTextColor = (COLORREF)FontData.Color;
  631.  
  632.         // set the new character format
  633.         SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFormat);
  634.     }
  635.     updtFontSize = true;
  636.     updtFontFace = true;
  637.     UpdateFormats();
  638. }
  639.  
  640.  
  641. void RichEditControl::CmEnFormatFont (TCommandEnabler &tce)
  642. {
  643.     // INSERT>> Your code here.
  644.  
  645.     tce.Enable();
  646. }
  647.  
  648.  
  649. LRESULT RichEditControl::CmChangeFontFace(WPARAM /*wParam*/, LPARAM lParam)
  650. {
  651.     char far* faceName = (char far*)lParam;
  652.  
  653.     // fill out character format structure to get font type information
  654.     charFormat.cbSize = sizeof(charFormat);
  655.     charFormat.dwMask = CFM_ITALIC | CFM_BOLD | CFM_UNDERLINE;
  656.     SendMessage( EM_GETCHARFORMAT, true, (LPARAM)&charFormat);
  657.  
  658.     // set mask for rich edit control to change font typeface
  659.     charFormat.dwMask |= CFM_FACE;
  660.  
  661.     // set the new font typeface while preserving old effects
  662.     strcpy( charFormat.szFaceName, faceName);
  663.     SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFormat);
  664.  
  665.     return 0;
  666. }
  667.  
  668.  
  669. LRESULT RichEditControl::CmChangeFontSize(WPARAM wParam, LPARAM /*lParam*/)
  670. {
  671.     int pointSize = (int)wParam;
  672.  
  673.     // fill out character format structure to get font size information
  674.     charFormat.cbSize = sizeof(charFormat);
  675.     charFormat.dwMask = CFM_SIZE;
  676.  
  677.     // convert units to twips
  678.     charFormat.yHeight = pointSize * 20;
  679.  
  680.     // set the new font point size
  681.     SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFormat);
  682.  
  683.     return 0;
  684. }
  685.  
  686.  
  687. void RichEditControl::Clear ()
  688. {
  689.     TEdit::Clear();
  690.  
  691.     // INSERT>> Your code here.
  692.  
  693.     CHARRANGE    charRange;
  694.  
  695.     // select entire contents
  696.     charRange.cpMin = 0;
  697.     charRange.cpMax = -1;
  698.  
  699.     //    clear contents
  700.     SetRedraw( false);
  701.     SendMessage( EM_EXSETSEL, 0, (LPARAM)&charRange);
  702.  
  703.     // fill out character format structure with default information
  704.     charFormat.cbSize = sizeof(charFormat);
  705.  
  706.     // set mask for rich edit control to change all effects
  707.     charFormat.dwMask = CFM_FACE | CFM_SIZE | CFM_ITALIC | CFM_BOLD | CFM_UNDERLINE;
  708.  
  709.     // clear all effects
  710.     charFormat.dwEffects = 0;
  711.  
  712.     // set text height convert units to twips
  713.     charFormat.yHeight = 12 * 20;
  714.  
  715.     // set the new font typeface while preserving old effects
  716.     strcpy( charFormat.szFaceName, "Times New Roman");
  717.  
  718.     SendMessage( EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&charFormat);
  719.  
  720.     // clear everything from the rtf control
  721.     SetRedraw( true);
  722.     SendMessage( EM_REPLACESEL, 0, (LPARAM)"");
  723.  
  724.     ClearModify();
  725.     UpdateFormats();
  726. }
  727.  
  728.  
  729. void RichEditControl::SetupWindow ()
  730. {
  731.     TEdit::SetupWindow();
  732.  
  733.     // INSERT>> Your code here.
  734.  
  735.     Clear();
  736. }
  737.  
  738.  
  739. void RichEditControl::CmEnSaveAs (TCommandEnabler &tce)
  740. {
  741.     // INSERT>> Your code here.
  742.  
  743.     tce.Enable();
  744. }
  745.  
  746.  
  747. bool RichEditControl::CanClose ()
  748. {
  749.     return CanClear();
  750. }
  751.  
  752.  
  753. void RichEditControl::CmEnFontFace (TCommandEnabler &tce)
  754. {
  755.     // INSERT>> Your code here.
  756.  
  757.     if( updtFontFace){
  758.         tce.SetText( charFormat.szFaceName);
  759.         updtFontFace = false;
  760.     }
  761. }
  762.  
  763.  
  764. void RichEditControl::CmEnFontSize (TCommandEnabler &tce)
  765. {
  766.     // INSERT>> Your code here.
  767.  
  768.     static char buf[17];
  769.  
  770.     // get text height convert units from twips
  771.     int height = charFormat.yHeight / 20;
  772.  
  773.     if( updtFontSize){
  774.         tce.SetText( itoa( height, buf, 10));
  775.         updtFontSize = false;
  776.     }
  777. }
  778.  
  779.  
  780. void RichEditControl::UpdateFormats ()
  781. {
  782.     // INSERT>> Your code here.
  783.  
  784.     // fill out character format structure to get font type information
  785.     charFormat.cbSize = sizeof(charFormat);
  786.  
  787.     // set mask for rich edit control to read all character formats
  788.     charFormat.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE |CFM_STRIKEOUT |
  789.                         CFM_PROTECTED | CFM_SIZE | CFM_COLOR | CFM_FACE |
  790.                         CFM_OFFSET | CFM_CHARSET;
  791.  
  792.     // get the new font typeface
  793.     SendMessage( EM_GETCHARFORMAT, true, (LPARAM)&charFormat);
  794.  
  795.     // fill out paragraph format structure with alignment information
  796.     paraFormat.cbSize = sizeof(paraFormat);
  797.     paraFormat.dwMask = PFM_ALIGNMENT;
  798.  
  799.     // set the new paragraph alignment
  800.     SendMessage( EM_GETPARAFORMAT, 0, (LPARAM)¶Format);
  801.  
  802.     // flags to indicate time to update combo boxes
  803.     updtFontFace = updtFontSize = true;
  804. }
  805.  
  806.  
  807. void RichEditControl::EvKeyDown (uint key, uint repeatCount, uint flags)
  808. {
  809.     TEdit::EvKeyDown(key, repeatCount, flags);
  810.  
  811.     // INSERT>> Your code here.
  812.  
  813.     UpdateFormats();
  814. }
  815.  
  816.  
  817. void RichEditControl::EvLButtonDown (uint modKeys, TPoint& point)
  818. {
  819.     TEdit::EvLButtonDown(modKeys, point);
  820.  
  821.     // INSERT>> Your code here.
  822.  
  823.     UpdateFormats();
  824. }
  825.  
  826.  
  827. void RichEditControl::CmFilePrint ()
  828. {
  829.     // INSERT>> Your code here.
  830.  
  831.     PRINTDLG pDlg;
  832.     FORMATRANGE fmtRng;
  833.     DOCINFO docInfo;
  834.     LONG textSent, totalAmount;
  835.  
  836.     // Initialize the PRINTDLG structure.
  837.     pDlg.lStructSize = sizeof(PRINTDLG);
  838.     pDlg.hwndOwner = HWindow;
  839.     pDlg.hDevMode = (HANDLE)0;
  840.     pDlg.hDevNames = (HANDLE)0;
  841.     pDlg.nFromPage = 0;
  842.     pDlg.nToPage = 0;
  843.     pDlg.nMinPage = 0;
  844.     pDlg.nMaxPage = 0;
  845.     pDlg.nCopies = 0;
  846.     pDlg.hInstance = GetApplication()->GetInstance();
  847.     pDlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION | PD_PRINTSETUP;
  848.     pDlg.lpfnSetupHook = (LPSETUPHOOKPROC)(FARPROC)0;
  849.     pDlg.lpSetupTemplateName = (LPTSTR)0;
  850.     pDlg.lpfnPrintHook = (LPPRINTHOOKPROC)(FARPROC)0;
  851.     pDlg.lpPrintTemplateName = (LPTSTR)0;
  852.  
  853.     // Get the printer DC.
  854.     if (PrintDlg(&pDlg) == TRUE)
  855.     {
  856.         // Fill out the FORMATRANGE structure for the RTF output.
  857.         fmtRng.hdc = fmtRng.hdcTarget = pDlg.hDC; // HDC
  858.         fmtRng.chrg.cpMin = 0;              // Print
  859.         fmtRng.chrg.cpMax = -1;             // entire contents
  860.         fmtRng.rc.top = fmtRng.rcPage.top = fmtRng.rc.left = fmtRng.rcPage.left = 0;
  861.         fmtRng.rc.right = fmtRng.rcPage.right = ::GetDeviceCaps(pDlg.hDC, HORZRES);
  862.         fmtRng.rc.bottom = fmtRng.rcPage.bottom = ::GetDeviceCaps(pDlg.hDC, VERTRES );
  863.  
  864.         // Fill out the DOCINFO structure.
  865.         docInfo.cbSize = sizeof(DOCINFO);
  866.         docInfo.lpszDocName = "(RTF Test)";
  867.         docInfo.lpszOutput = NULL;
  868.  
  869.         // Be sure that the printer DC is in text mode.
  870.         SetMapMode(pDlg.hDC, MM_TEXT);
  871.  
  872.         StartDoc( pDlg.hDC, &docInfo);
  873.         StartPage( pDlg.hDC );
  874.  
  875.         textSent = 0;
  876.         totalAmount = SendMessage( WM_GETTEXTLENGTH, 0, 0);
  877.  
  878.         while (textSent < totalAmount)
  879.         {
  880.             textSent = SendMessage( EM_FORMATRANGE, TRUE, (LPARAM) &fmtRng);
  881.  
  882.             if (textSent < totalAmount)
  883.             {
  884.                 EndPage( pDlg.hDC );
  885.                 StartPage( pDlg.hDC );
  886.                 fmtRng.chrg.cpMin = textSent;
  887.                 fmtRng.chrg.cpMax = -1;
  888.             }
  889.         }
  890.         // Reset the formatting of the rich edit control.
  891.         SendMessage( EM_FORMATRANGE, TRUE, (LPARAM)NULL);
  892.  
  893.         // Finish the document.
  894.         EndPage( pDlg.hDC );
  895.         EndDoc( pDlg.hDC );
  896.  
  897.         // Delete the printer DC.
  898.         DeleteDC( pDlg.hDC );
  899.     }
  900. }
  901.  
  902.  
  903. //
  904. // Paint routine for Window, Printer, and PrintPreview for an TEdit client.
  905. //
  906. void RichEditControl::Paint (TDC& dc, bool /*erase*/, TRect& rect)
  907. {
  908.     RichCtrlApp *theApp = TYPESAFE_DOWNCAST(GetApplication(), RichCtrlApp);
  909.     if (theApp) {
  910.         // Only paint if we're printing and we have something to paint, otherwise do nothing.
  911.         if (theApp->Printing && theApp->Printer && !rect.IsEmpty()) {
  912.             // Use pageSize to get the size of the window to render into.  For a Window it's the client area,
  913.             // for a printer it's the printer DC dimensions and for print preview it's the layout window.
  914.             TSize   pageSize(rect.right - rect.left, rect.bottom - rect.top);
  915.  
  916.             TPrintDialog::TData &printerData = theApp->Printer->GetSetup();
  917.  
  918.             // Do the text stuff:
  919.             int fromPage = printerData.FromPage == -1 ? 1 : printerData.FromPage;
  920.             int nPages;
  921.  
  922.             // rich text edit control stuff
  923.             FORMATRANGE fmtRng;
  924.             LONG textSent, totalAmount, textBegin;
  925.  
  926.             // Fill out the FORMATRANGE structure for the RTF output.
  927.             fmtRng.hdc = fmtRng.hdcTarget = dc;     // print device HDC
  928.             fmtRng.chrg.cpMin = 0;
  929.             fmtRng.chrg.cpMax = -1;             // print entire contents
  930.             fmtRng.rc.top = fmtRng.rcPage.top = fmtRng.rc.left = fmtRng.rcPage.left = 0;
  931.  
  932.             // get printer device capacity
  933.             TSize printRes( dc.GetDeviceCaps(LOGPIXELSX), dc.GetDeviceCaps(LOGPIXELSY));
  934.  
  935.             // Convert to TWIPS
  936.             fmtRng.rc.right = fmtRng.rcPage.right = pageSize.cx * 1440 / printRes.cx;
  937.             fmtRng.rc.bottom = fmtRng.rcPage.bottom = pageSize.cy * 1440 / printRes.cy;
  938.  
  939.             // minimum number of pages to print
  940.             printerData.MinPage = 1;
  941.             printerData.MaxPage = 1;
  942.  
  943.             // move to current page
  944.             textBegin = textSent = 0;
  945.             nPages = 1;
  946.             totalAmount = SendMessage( WM_GETTEXTLENGTH, 0, 0);
  947.  
  948.             // determine how many pages are needed to print document
  949.             while( textSent < totalAmount){
  950.                 if( nPages == fromPage)
  951.                     textBegin = textSent;
  952.                 // format range but don't actually print it
  953.                 fmtRng.chrg.cpMin = textSent = SendMessage( EM_FORMATRANGE, false, (LPARAM) &fmtRng);
  954.                 printerData.MaxPage = nPages++;
  955.             }
  956.  
  957.             // reset formatrange
  958.             SendMessage( EM_FORMATRANGE, false, (LPARAM)0);
  959.  
  960.             fmtRng.chrg.cpMin = textBegin;
  961.  
  962.             // reset rc to rcPage size (rc was adjusted to area printed)
  963.             fmtRng.rc.right = fmtRng.rcPage.right;
  964.             fmtRng.rc.bottom = fmtRng.rcPage.bottom;
  965.  
  966.             // output text to printer or preview DC
  967.             SendMessage( EM_FORMATRANGE, true, (LPARAM) &fmtRng);
  968.  
  969.             // reset formatrange
  970.             SendMessage( EM_FORMATRANGE, true, (LPARAM)0);
  971.         }
  972.     }
  973. }
  974.  
  975.