home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK8 / MFC / SAMPLES / MULTIPAD / MPMAIN.CP$ / mpmain
Encoding:
Text File  |  1992-03-16  |  19.9 KB  |  857 lines

  1. // mpmain.cpp : Defines the class behaviors for the frame and children.
  2. //              Multipad is a standard MDI application where each child
  3. //              window is similar to the "Notepad" application.  This
  4. //              example illustrates document-maintenance techniques such
  5. //              as typical file Open and Save processing, printing, and
  6. //              managing MDI document children windows.
  7. //
  8. // This is a part of the Microsoft Foundation Classes C++ library.
  9. // Copyright (C) 1992 Microsoft Corporation
  10. // All rights reserved.
  11. //
  12. // This source code is only intended as a supplement to the
  13. // Microsoft Foundation Classes Reference and Microsoft
  14. // QuickHelp documentation provided with the library.
  15. // See these sources for detailed information regarding the
  16. // Microsoft Foundation Classes product.
  17.  
  18. #include "multipad.h"
  19. #include <direct.h>
  20.  
  21. #pragma code_seg("_MPTEXT")
  22.  
  23. // a simple way to reduce size of C runtimes
  24. // disable the use of getenv and argv/argc
  25. extern "C" void _setargv() { }
  26. extern "C" void _setenvp() { }
  27.  
  28. // MRU information
  29. static CString mruFileNames [4];
  30.  
  31. /////////////////////////////////////////////////////////////////////////////
  32. // The one global application object.
  33. //
  34. CMultiPad multiPad("MultiPad");
  35.  
  36.  
  37. /////////////////////////////////////////////////////////////////////////////
  38. // MPError:
  39. // A useful printf()-style error routine, which formats and displays a
  40. // message box.  Note that "idFmt" is a resource ID, which should be an
  41. // fprintf()-style format string.
  42. //
  43. short MPError(int bFlags, int idFmt, ...)
  44. {
  45.     char sz[160];
  46.     CString strFmt;
  47.     
  48.     strFmt.LoadString(idFmt);
  49.     wvsprintf(sz, (LPCSTR)strFmt, (LPCSTR)(&idFmt + 1));
  50.     
  51.     return multiPad.m_pMainWnd->MessageBox(sz, AfxGetAppName(), bFlags);
  52. }
  53.  
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CMPFrame
  56.  
  57. CMPFrame::CMPFrame(const char* szTitle) : m_statBar()
  58. {
  59.     m_bShortMenu = FALSE;
  60.     m_pActiveChild = NULL;
  61.     Create(NULL, szTitle, WS_OVERLAPPEDWINDOW, rectDefault, NULL,
  62.         MAKEINTRESOURCE(IDMULTIPAD));
  63. }
  64.  
  65. // OnMenuSelect:
  66. // As the user highlights different menu items, we are called.  We decide
  67. // which string would be appropriate to put in our status bar.
  68. //
  69. // Note some OnMenuSelect messages go to the active child; we just ask the
  70. // frame to handle these.
  71. //
  72. void CMPChild::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
  73. {
  74.     GetParentFrame()->SendMessage(WM_MENUSELECT, nItemID,
  75.         MAKELONG(nFlags, hSysMenu));
  76. }
  77. void CMPFrame::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
  78. {
  79.     char szBuf [128];
  80.     
  81.     UINT ids = 0;
  82.     
  83.     if (nFlags == 0xFFFF && hSysMenu == NULL)
  84.     {
  85.         ids = IDS_ALTPMT;
  86.     }
  87.     else if (nFlags & MF_POPUP)
  88.     {
  89.         ids = IDS_MENUPMT;
  90.     }
  91.     else if ((nFlags & MF_SEPARATOR) == 0)
  92.     {
  93.         if (nItemID >= AFX_IDM_FIRST_MDICHILD)
  94.             ids = IDS_ACTTHISWIN;
  95.         else if (nItemID >= IDM_FILE1 && nItemID <= IDM_FILE4)
  96.             ids = IDS_OPENTHISFILE;
  97.         else
  98.             ids = nItemID;
  99.     }
  100.     
  101.     if (ids != 0)
  102.         LoadString(AfxGetResourceHandle(), ids, szBuf, sizeof (szBuf));
  103.     else
  104.         szBuf[0] = '\0';
  105.     
  106.     m_statBar.SetText(szBuf);
  107. }
  108.  
  109. // OnCreate:
  110. // When we're created, in addition to the usual CMDIFrameWnd::OnCreate work,
  111. // we create a CStatBar status bar window (defined in bar.h and bar.cpp).
  112. //
  113. int CMPFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
  114. {
  115.     char szBuf [128];
  116.  
  117.     // Create the status bar, with the usual "Press ALT to choose commands".
  118.     //
  119.     m_statBar.Create(this, CRect(0, 0, 0, 0));
  120.     LoadString(AfxGetResourceHandle(), IDS_ALTPMT, szBuf, sizeof (szBuf));
  121.     m_statBar.SetText(szBuf);
  122.  
  123.     return CMDIFrameWnd::OnCreate(lpCreateStruct);
  124. }
  125.  
  126. // OnSize:
  127. // The Windows 3.0 SDK documentation says that, in the case of an MDI Frame
  128. // window, the ON_SIZE message MUST be passed on to the system after any
  129. // processing.  This sizes the MDI Client window to the whole client area
  130. // of the frame.
  131. //
  132. // Note that instead, you can simply use the MoveWindow function to move the
  133. // MDI Client window yourself.  In fact, you must do this yourself if you
  134. // don't want the MDI Client to take up the whole Frame client area.  If you
  135. // use MoveWindow, do not pass the ON_SIZE message on for default processing.
  136. //
  137. // In our case, we leave some room at the bottom for a status bar.
  138. //
  139. void CMPFrame::OnSize(UINT size, int cx, int cy)
  140. {
  141.     if (size != SIZEICONIC)
  142.     {
  143.         int cxBorder = GetSystemMetrics(SM_CXBORDER);
  144.         int cyBorder = GetSystemMetrics(SM_CYBORDER);
  145.         CRect rcStatBar;
  146.         int cyStatBar;
  147.         
  148.         m_statBar.GetWindowRect(rcStatBar);
  149.         cyStatBar = rcStatBar.bottom - rcStatBar.top;
  150.         HDWP hdwp = ::BeginDeferWindowPos(2);
  151.         ::DeferWindowPos(hdwp, m_statBar.m_hWnd, NULL, -cxBorder,
  152.             cy - cyStatBar + cyBorder, cx + cxBorder * 2, cyStatBar,
  153.             SWP_NOACTIVATE | SWP_NOZORDER);
  154.         ::DeferWindowPos(hdwp, m_hWndMDIClient, NULL, 0, 0,
  155.             cx, cy - cyStatBar + cyBorder, SWP_NOZORDER | SWP_NOACTIVATE);
  156.         ::EndDeferWindowPos(hdwp);
  157.     }
  158. }
  159.  
  160. // OnInitMenu:
  161. // The menu needs to be updated, so we observe our status and gray or check
  162. // any appropriate menu items.
  163. //
  164.  
  165. BOOL bUpdateMRU = TRUE;
  166.  
  167. void CMPFrame::OnInitMenu(CMenu* pMenu)
  168. {
  169.     extern char szSearch[];
  170.     
  171.     UINT nStatus;
  172.     int i;
  173.  
  174.     if (IsIconic())
  175.         return;
  176.  
  177.     if (bUpdateMRU)
  178.     {
  179.         BOOL bMaximized = HIWORD(::SendMessage(m_hWndMDIClient,
  180.             WM_MDIGETACTIVE, 0, 0));
  181.         CMenu * pFileMenu = pMenu->GetSubMenu(bMaximized ? 1 : 0);
  182.         
  183.         if (mruFileNames[0].GetLength() > 0)
  184.         {
  185.             char szCurDir [64];
  186.             
  187.             pFileMenu->DeleteMenu(IDM_FILEMRU, MF_BYCOMMAND);
  188.             pFileMenu->DeleteMenu(IDM_FILE1, MF_BYCOMMAND);
  189.             pFileMenu->DeleteMenu(IDM_FILE2, MF_BYCOMMAND);
  190.             pFileMenu->DeleteMenu(IDM_FILE3, MF_BYCOMMAND);
  191.             pFileMenu->DeleteMenu(IDM_FILE4, MF_BYCOMMAND);
  192.  
  193.             _getcwd(szCurDir, sizeof (szCurDir));
  194.             int cchCurDir = strlen(szCurDir);
  195.             if (szCurDir[cchCurDir - 1] != '\\')
  196.             {
  197.                 szCurDir[cchCurDir++] = '\\';
  198.                 szCurDir[cchCurDir] = '\0';
  199.             }
  200.             
  201.             for (i = 0; i < 4; i += 1)
  202.             {
  203.                 char szBuf [128];
  204.                 char* pch;
  205.                 
  206.                 if (mruFileNames[i].GetLength() == 0)
  207.                     break;
  208.                 
  209.                 pch = szBuf;
  210.                 *pch++ = '&';
  211.                 *pch++ = '1' + i;
  212.                 *pch++ = ' ';
  213.                 strcpy(pch, (const char*)mruFileNames[i]);
  214.                 if (strncmp(szCurDir, (const char*)mruFileNames[i],
  215.                     cchCurDir) == 0)
  216.                 {
  217.                     strcpy(pch, pch + cchCurDir);
  218.                 }
  219.                                     
  220.                 pFileMenu->InsertMenu(IDM_FILEEXIT, MF_STRING | MF_BYCOMMAND,
  221.                     IDM_FILE1 + i, szBuf);
  222.             }
  223.             
  224.             pFileMenu->InsertMenu(IDM_FILEEXIT, MF_SEPARATOR, IDM_FILEMRU);
  225.         }
  226.         
  227.         pFileMenu->Detach();
  228.         bUpdateMRU = FALSE;
  229.     }
  230.     
  231.     if (m_pActiveChild != NULL)
  232.     {
  233.         if (m_pActiveChild->m_edit.CanUndo())
  234.             nStatus = MF_ENABLED;
  235.         else
  236.             nStatus = MF_GRAYED;
  237.         
  238.         pMenu->EnableMenuItem(IDM_EDITUNDO, nStatus);
  239.         
  240.         LONG lSel = m_pActiveChild->m_edit.GetSel();
  241.         nStatus = (HIWORD(lSel) == LOWORD(lSel)) ? MF_GRAYED : MF_ENABLED;
  242.         pMenu->EnableMenuItem(IDM_EDITCUT, nStatus);
  243.         pMenu->EnableMenuItem(IDM_EDITCOPY, nStatus);
  244.         pMenu->EnableMenuItem(IDM_EDITCLEAR, nStatus);
  245.         
  246.         nStatus = MF_GRAYED;
  247.         if (OpenClipboard())
  248.         {
  249.             int nFmt = 0;
  250.             
  251.             while ((nFmt = EnumClipboardFormats(nFmt)) != 0)
  252.             {
  253.                 if (nFmt == CF_TEXT)
  254.                 {
  255.                     nStatus = MF_ENABLED;
  256.                     break;
  257.                 }
  258.             }
  259.             
  260.             CloseClipboard();
  261.         }
  262.         pMenu->EnableMenuItem(IDM_EDITPASTE, nStatus);
  263.         
  264.         if (m_pActiveChild->m_bWordWrap)
  265.             nStatus = MF_CHECKED;
  266.         else
  267.             nStatus = MF_UNCHECKED;
  268.         pMenu->CheckMenuItem(IDM_EDITWRAP, nStatus);
  269.  
  270.         if (m_pFindReplace != NULL)
  271.             pMenu->EnableMenuItem(IDM_SEARCHFIND, MF_GRAYED);
  272.         else
  273.             pMenu->EnableMenuItem(IDM_SEARCHFIND, MF_ENABLED);
  274.  
  275.         if (m_strFind.GetLength() == 0)
  276.             nStatus = MF_GRAYED;
  277.         else
  278.             nStatus = MF_ENABLED;
  279.         pMenu->EnableMenuItem(IDM_SEARCHNEXT, nStatus);
  280.         pMenu->EnableMenuItem(IDM_SEARCHPREV, nStatus);
  281.  
  282.         // Select All and Wrap toggle always enabled.
  283.         //
  284.         nStatus = MF_ENABLED;
  285.         pMenu->EnableMenuItem(IDM_EDITSELECT, nStatus);
  286.         pMenu->EnableMenuItem(IDM_EDITWRAP, nStatus);
  287.         pMenu->EnableMenuItem(IDM_EDITSETFONT, nStatus);
  288.     }
  289.     else
  290.     {
  291.         nStatus = MF_GRAYED;
  292.         
  293.         for (i = IDM_EDITFIRST; i <= IDM_EDITLAST; i += 1)
  294.             pMenu->EnableMenuItem(i, nStatus);
  295.         
  296.         pMenu->CheckMenuItem(IDM_EDITWRAP, MF_UNCHECKED);
  297.  
  298.         pMenu->EnableMenuItem(IDM_SEARCHFIND, nStatus);
  299.         pMenu->EnableMenuItem(IDM_SEARCHNEXT, nStatus);
  300.         pMenu->EnableMenuItem(IDM_SEARCHPREV, nStatus);
  301.  
  302.         pMenu->EnableMenuItem(IDM_FILEPRINT, nStatus);
  303.     }
  304.  
  305.     // nStatus is last value in m_pActiveChild test
  306.     pMenu->EnableMenuItem(IDM_FILEPRINT, nStatus);
  307.     pMenu->EnableMenuItem(IDM_FILESAVE, nStatus);
  308.     pMenu->EnableMenuItem(IDM_FILESAVEAS, nStatus);
  309.     pMenu->EnableMenuItem(IDM_WINDOWTILE, nStatus);
  310.     pMenu->EnableMenuItem(IDM_WINDOWCASCADE, nStatus);
  311.     pMenu->EnableMenuItem(IDM_WINDOWICONS, nStatus);
  312.     pMenu->EnableMenuItem(IDM_WINDOWCLOSEALL, nStatus);
  313.     
  314. }
  315.  
  316. void AddFileToMRU(const char* szFileName)
  317. {
  318.     int i;
  319.     
  320.     bUpdateMRU = TRUE;
  321.     
  322.     for (i = 0; i < 4; i += 1)
  323.     {
  324.         if (szFileName == mruFileNames[i])
  325.         {
  326.             if (i != 0)
  327.             {
  328.                 CString temp = mruFileNames[0];
  329.                 mruFileNames[0] = mruFileNames[i];
  330.                 mruFileNames[i] = temp;
  331.             }
  332.             return;
  333.         }
  334.     }
  335.  
  336.     for (i = 3; i > 0; i -= 1)
  337.         mruFileNames[i] = mruFileNames[i - 1];
  338.     mruFileNames[0] = szFileName;
  339. }
  340.  
  341.  
  342. /////////////////////////////////////////////////////////////////////////////
  343. // File menu commands
  344.  
  345. void CMPFrame::CmdFileNew()
  346. {
  347.     new CMPChild(NULL);
  348. }
  349.  
  350. void CMPFrame::CmdFileOpen()
  351. {
  352.     ReadFile();
  353. }
  354.  
  355. void CMPFrame::CmdWinCloseAll()
  356. {
  357.     if (QueryCloseAllChildren())
  358.     {
  359.         CloseAllChildren();
  360.         ::ShowWindow(m_hWndMDIClient, SW_SHOW);
  361.     }
  362. }
  363.  
  364. BOOL CMPFrame::QueryCloseAllChildren()
  365. {
  366.     CWnd* pWnd;
  367.     
  368.     for (pWnd = CWnd::FromHandle(::GetWindow(m_hWndMDIClient, GW_CHILD)); pWnd != NULL;
  369.         pWnd = pWnd->GetNextWindow())
  370.     {
  371.         if (pWnd->GetWindow(GW_OWNER) != NULL)
  372.             continue;
  373.         
  374.         if (pWnd->SendMessage(WM_QUERYENDSESSION))
  375.             return FALSE;
  376.     }
  377.     
  378.     return TRUE;
  379. }
  380.  
  381. void CMPFrame::CloseAllChildren()
  382. {
  383.     CWnd* pWnd;
  384.     
  385.     // Hide the MDI client window to avoid multiple repaints.
  386.     //
  387.     ::ShowWindow(m_hWndMDIClient, SW_HIDE);
  388.     
  389.     // As long as the MDI client has a child, destroy it.
  390.     //
  391.     while ((pWnd = CWnd::FromHandle(m_hWndMDIClient)->GetWindow(GW_CHILD)) != NULL)
  392.     {
  393.         // Skip the icon title windows.
  394.         //
  395.         while (pWnd != NULL && pWnd->GetWindow(GW_OWNER) != NULL)
  396.             pWnd = pWnd->GetNextWindow();
  397.         
  398.         if (pWnd == NULL)
  399.             break;
  400.         
  401.         pWnd->DestroyWindow();
  402.     }
  403. }
  404.  
  405. BOOL CMPFrame::OnQueryEndSession()
  406. {
  407.     return QueryCloseAllChildren();
  408. }
  409.  
  410. void CMPFrame::OnClose()
  411. {
  412.     if (QueryCloseAllChildren())
  413.     {
  414.         if (m_pFindReplace != NULL)
  415.         {
  416.             // Do not delete, use DestroyWindow
  417.             m_pFindReplace->SendMessage(WM_COMMAND, IDCANCEL, 0L);
  418.         }
  419.         this->DestroyWindow();
  420.     }
  421. }
  422.  
  423. void CMPFrame::CmdMDITile()
  424. {
  425.     MDITile();
  426. }
  427.  
  428. void CMPFrame::CmdMDICascade()
  429. {
  430.     MDICascade();
  431. }
  432.  
  433. void CMPFrame::CmdMDIIconArrange()
  434. {
  435.     MDIIconArrange();
  436. }
  437.  
  438. void CMPFrame::CmdFileExit()
  439. {
  440.     OnClose();
  441. }
  442.  
  443. // CmdToggleMenu:
  444. // Switch between "Full" and "Short" menus.
  445. //
  446. void CMPFrame::CmdToggleMenu()
  447. {
  448.     CMenu menu;
  449.     UINT id, i;
  450.     
  451.     if (m_bShortMenu)
  452.     {
  453.         id = IDMULTIPAD;
  454.         i = WINDOWMENU;
  455.         m_bShortMenu = FALSE;
  456.     }
  457.     else
  458.     {
  459.         id = IDMULTIPAD2;
  460.         i = SHORTMENU;
  461.         m_bShortMenu = TRUE;
  462.     }
  463.     
  464.     menu.LoadMenu(id);
  465.     MDISetMenu(&menu, menu.GetSubMenu(i))->DestroyMenu();
  466.     menu.Detach(); // Keep it from being destroyed.
  467.     DrawMenuBar();
  468.  
  469.     bUpdateMRU = TRUE;
  470. }
  471.  
  472. /////////////////////////////////////////////////////////////////////////////
  473. // Handle profile stuff
  474. static char BASED_CODE szIniFile[] = "multipad.ini";
  475. void LoadMRU()
  476. {
  477.     char szBuf [128];
  478.     
  479.     GetPrivateProfileString(AfxGetAppName(), "File1", "", 
  480.         szBuf, sizeof (szBuf), szIniFile);
  481.     mruFileNames[0] = szBuf;
  482.  
  483.     GetPrivateProfileString(AfxGetAppName(), "File2", "", 
  484.         szBuf, sizeof (szBuf), szIniFile);
  485.     mruFileNames[1] = szBuf;
  486.  
  487.     GetPrivateProfileString(AfxGetAppName(), "File3", "", 
  488.         szBuf, sizeof (szBuf), szIniFile);
  489.     mruFileNames[2] = szBuf;
  490.  
  491.     GetPrivateProfileString(AfxGetAppName(), "File4", "", 
  492.         szBuf, sizeof (szBuf), szIniFile);
  493.     mruFileNames[3] = szBuf;
  494.  
  495.     bUpdateMRU = TRUE;
  496. }
  497.  
  498. void SaveMRU()
  499. {
  500.     WritePrivateProfileString(AfxGetAppName(), "File1", 
  501.         mruFileNames[0], szIniFile);
  502.     WritePrivateProfileString(AfxGetAppName(), "File2", 
  503.         mruFileNames[1], szIniFile);
  504.     WritePrivateProfileString(AfxGetAppName(), "File3", 
  505.         mruFileNames[2], szIniFile);
  506.     WritePrivateProfileString(AfxGetAppName(), "File4", 
  507.         mruFileNames[3], szIniFile);
  508. }
  509.  
  510. void CMPFrame::CmdFileMRU()
  511. {
  512.     int mruIndex = (GetCurrentMessage()->wParam) - IDM_FILE1;
  513.     ReadFile(mruFileNames[mruIndex]);
  514. }
  515.  
  516. /////////////////////////////////////////////////////////////////////////////
  517. // Help menu commands
  518.  
  519. void CMPFrame::CmdHelpAbout()
  520. {
  521.     CModalDialog aboutBox(IDD_ABOUT, this);
  522.     aboutBox.DoModal();
  523. }
  524.  
  525. /////////////////////////////////////////////////////////////////////////////
  526. // CMPFrame message map
  527. BEGIN_MESSAGE_MAP(CMPFrame, CMDIFrameWnd)
  528.     ON_WM_INITMENU()
  529.     ON_WM_MENUSELECT()
  530.     ON_WM_CLOSE()
  531.     ON_WM_QUERYENDSESSION()
  532.     ON_WM_SIZE()
  533.     ON_WM_CREATE()
  534.         
  535.     ON_COMMAND(IDM_FILENEW, CmdFileNew)
  536.     ON_COMMAND(IDM_FILEOPEN, CmdFileOpen)
  537.     ON_COMMAND(IDM_FILEMENU, CmdToggleMenu)
  538.     ON_COMMAND(IDM_FILE1, CmdFileMRU)
  539.     ON_COMMAND(IDM_FILE2, CmdFileMRU)
  540.     ON_COMMAND(IDM_FILE3, CmdFileMRU)
  541.     ON_COMMAND(IDM_FILE4, CmdFileMRU)
  542.     ON_COMMAND(IDM_FILEEXIT, CmdFileExit)
  543.     
  544.     ON_COMMAND(IDM_WINDOWTILE, CmdMDITile)
  545.     ON_COMMAND(IDM_WINDOWCASCADE, CmdMDICascade)
  546.     ON_COMMAND(IDM_WINDOWICONS, CmdMDIIconArrange)
  547.     ON_COMMAND(IDM_WINDOWCLOSEALL, CmdWinCloseAll)
  548.  
  549.     ON_COMMAND(IDM_HELPABOUT, CmdHelpAbout)
  550.  
  551.     // Find stuff
  552.     ON_REGISTERED_MESSAGE(m_nMsgFind, CmdFindHelper) 
  553.             /* helper for CFindReplace */
  554.  
  555.     ON_COMMAND(IDM_SEARCHFIND, CmdFind)
  556.     ON_COMMAND(IDM_SEARCHNEXT, CmdFindNext)
  557.     ON_COMMAND(IDM_SEARCHPREV, CmdFindPrev)
  558.  
  559. END_MESSAGE_MAP()
  560.  
  561.  
  562. //////////////////////////////////////////////////////////////////////////
  563. // CMPChild routines
  564. int CMPChild::OnCreate(LPCREATESTRUCT)
  565. {
  566.     CRect rect(0, 0, 0, 0);
  567.  
  568.     m_edit.Create(WS_BORDER | WS_HSCROLL | WS_VISIBLE | WS_VSCROLL |
  569.         ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | ES_NOHIDESEL |
  570.         WS_MAXIMIZE, rect, this, ID_EDIT);
  571.     
  572.     m_bChanged = FALSE;
  573.     m_bWordWrap = FALSE;
  574.     m_bUntitled = TRUE;
  575.     m_edit.SetFocus();
  576.  
  577.     return 0;
  578. }
  579.  
  580. void CMPChild::OnSize(UINT nFlags, int cx, int cy)
  581. {
  582.     CRect rc;
  583.     
  584.     GetClientRect(&rc);
  585.     rc.InflateRect(GetSystemMetrics(SM_CXBORDER),
  586.         GetSystemMetrics(SM_CYBORDER));
  587.     m_edit.MoveWindow(rc);
  588.     
  589.     // This MUST be passed along for MDI to work properly.  It handles all
  590.     // of the maximize, minimize, restore logic.
  591.     //
  592.     CMDIChildWnd::OnSize(nFlags, cx, cy);
  593. }
  594.  
  595. // CMPChild:
  596. // We keep tabs on who the active child is.
  597. //
  598. void CMPChild::OnMDIActivate(BOOL bActivate, CWnd* pWndActivate,
  599.     CWnd* pWndDeactivate)
  600. {
  601.     if (bActivate)
  602.         CMPFrame::SetActiveChild((CMPChild*)pWndActivate);
  603.     else if (CMPFrame::GetActiveChild() == pWndDeactivate)
  604.         CMPFrame::SetActiveChild(NULL);
  605. }
  606.  
  607. // OnEditChange:
  608. // The user's been editing the buffer.  Remember that it no longer matches
  609. // the original disk file.
  610. //
  611. void CMPChild::OnEditChange()
  612. {
  613.     m_bChanged = TRUE;
  614. }
  615.  
  616. // OnEditErrSpace:
  617. // No more room in this buffer!  Windows limits the size of the CEdit's text
  618. // to 32Kb.
  619. //
  620. void CMPChild::OnEditErrSpace()
  621. {
  622.     MessageBeep(0);
  623. }
  624.  
  625. BOOL CMPChild::OnQueryEndSession()
  626. {
  627.     return !QueryCloseChild();
  628. }
  629.  
  630. // OnSetFocus:
  631. // Whenever a child gets the focus, it gives it to its child CEdit instead.
  632. //
  633. void CMPChild::OnSetFocus(CWnd* pWndOldFocus)
  634. {
  635.     m_edit.SetFocus();
  636.     CMDIChildWnd::OnSetFocus(pWndOldFocus);
  637. }
  638.  
  639. // SetWrap:
  640. // Edit windows are difficult to wrap/unwrap the text within.  This code
  641. // uses a temporary edit window scheme, transferring the old text into
  642. // a new window to make it wrap properly.
  643. //
  644. void CMPChild::SetWrap(BOOL bWrap)
  645. {
  646.     LONG    dws;
  647.     HANDLE  hText;
  648.     HANDLE  hDummyText;
  649.  
  650.     // Change word wrap mode.
  651.     //
  652.     m_bWordWrap = bWrap;
  653.  
  654.     // Create the appropriate window style, adding a horizontal scroll
  655.     // facility if wrapping is not present.
  656.     //
  657.     dws = WS_BORDER | WS_CHILD | WS_VSCROLL | ES_AUTOVSCROLL | 
  658.             ES_NOHIDESEL | ES_MULTILINE;
  659.     if (!bWrap)
  660.         dws |= WS_HSCROLL | ES_AUTOHSCROLL;
  661.  
  662.     // Get the data handle of the old control.
  663.     //
  664.     hText = m_edit.GetHandle();
  665.  
  666.     // Create a dummy data handle and make it the handle to
  667.     // the old edit control (hText still references the text of
  668.     // old control).
  669.     //
  670.     hDummyText = LocalAlloc(LHND, 0);
  671.     m_edit.SetHandle(hDummyText);
  672.     m_edit.DestroyWindow();
  673.  
  674.     // Create a new child window.
  675.     //
  676.     CRect rc(0, 0, 0, 0);
  677.     m_edit.Create(dws, rc, this, ID_EDIT);
  678.  
  679.     // Cause the window to be properly sized.
  680.     //
  681.     SendMessage(WM_SIZE, 0, 0L);
  682.  
  683.     // Free the new window's old data handle and set it to
  684.     // hText (text of old edit control).
  685.     //
  686. //  LocalFree(m_edit.GetHandle());
  687.     m_edit.SetHandle(hText);
  688.     m_edit.SetFont(&m_font);
  689.  
  690.     m_edit.ShowWindow(SW_SHOW);
  691.  
  692.     // Set focus to the new edit control.
  693.     m_edit.SetFocus();
  694. }
  695.  
  696. /////////////////////////////////////////////////////////////////////////////
  697. // File menu commands
  698.  
  699. void CMPChild::CmdFileSave()
  700. {
  701.     if (m_bUntitled && !ChangeFile())
  702.         return;
  703.     
  704.     SaveFile();
  705. }
  706.  
  707. void CMPChild::CmdFileSaveAs()
  708. {
  709.     if (ChangeFile())
  710.         SaveFile();
  711. }
  712.  
  713. void CMPChild::OnClose()
  714. {
  715.     if (QueryCloseChild())
  716.         CMDIChildWnd::OnClose();
  717. }
  718.  
  719. void CMPChild::PostNcDestroy()
  720. {
  721.     delete this;
  722. }
  723.  
  724. BOOL CMPChild::QueryCloseChild()
  725. {
  726.     char sz[64];
  727.     
  728.     // Return OK if text has not changed.
  729.     //
  730.     if (!m_bChanged)
  731.         return TRUE;
  732.  
  733.     GetWindowText(sz, sizeof (sz));
  734.     
  735.     // Ask user whether to save, not save, or cancel.
  736.     //
  737.     switch (MPError(MB_YESNOCANCEL | MB_ICONQUESTION, IDS_CLOSESAVE,
  738.         (LPCSTR)sz))
  739.     {
  740.     case IDYES:
  741.         // User wants file saved.
  742.         //
  743.         SaveFile();
  744.         break;
  745.  
  746.     case IDNO:
  747.         // User doesn't want file saved.  OK to close child.
  748.         //
  749.         break;
  750.  
  751.     default:
  752.         // We couldn't do the message box, or not OK to close.
  753.         //
  754.         return FALSE;
  755.     }
  756.     
  757.     return TRUE;
  758. }
  759.  
  760. /////////////////////////////////////////////////////////////////////////////
  761. // Edit menu commands
  762.  
  763. void CMPChild::CmdSetFont()
  764. {
  765.     LOGFONT lfInitial;
  766.  
  767.     if (m_edit.GetFont() == NULL)
  768.     {
  769.         // using SystemFont
  770.         CFont sysFont;
  771.         VERIFY(sysFont.CreateStockObject(SYSTEM_FONT));
  772.         VERIFY(sysFont.GetObject(sizeof(lfInitial), &lfInitial));
  773.     }
  774.     else
  775.         m_edit.GetFont()->GetObject(sizeof(lfInitial), &lfInitial);
  776.  
  777.     CFontDialog fontDialog(&lfInitial, CF_SCREENFONTS);
  778.     
  779.     if (fontDialog.DoModal() == IDOK)
  780.     {
  781.         m_font.DeleteObject();
  782.         m_font.CreateFontIndirect(&fontDialog.m_lf);
  783.         m_edit.SetFont(&m_font);
  784.     }
  785. }
  786.  
  787. void CMPChild::CmdWordWrap()
  788. {
  789.     SetWrap(!m_bWordWrap);
  790. }
  791.  
  792. void CMPChild::CmdUndo()
  793. {
  794.     m_edit.Undo();
  795. }
  796.  
  797. void CMPChild::CmdCut()
  798. {
  799.     m_edit.Cut();
  800. }
  801.  
  802. void CMPChild::CmdCopy()
  803. {
  804.     m_edit.Copy();
  805. }
  806.  
  807. void CMPChild::CmdPaste()
  808. {
  809.     m_edit.Paste();
  810. }
  811.  
  812. void CMPChild::CmdClear()
  813. {
  814.     m_edit.ReplaceSel("");
  815. }
  816.  
  817. void CMPChild::CmdSelectAll()
  818. {
  819.     m_edit.SetSel(MAKELONG(0, 0xE000));
  820. }
  821.  
  822. /////////////////////////////////////////////////////////////////////////////
  823. // CMPChild message map
  824. BEGIN_MESSAGE_MAP(CMPChild, CMDIChildWnd)
  825.     ON_WM_CREATE()
  826.     ON_WM_MDIACTIVATE()
  827.     ON_WM_QUERYENDSESSION()
  828.     ON_WM_CLOSE()
  829.     ON_WM_SIZE()
  830.     ON_WM_SETFOCUS()
  831.     ON_WM_MENUSELECT()
  832.     
  833.     ON_EN_CHANGE(ID_EDIT, OnEditChange)
  834.     
  835.     ON_COMMAND(IDM_FILESAVE, CmdFileSave)
  836.     ON_COMMAND(IDM_FILESAVEAS, CmdFileSaveAs)
  837.     ON_COMMAND(IDM_FILEPRINT, PrintFile)
  838.     ON_COMMAND(IDM_EDITWRAP, CmdWordWrap)
  839.     ON_COMMAND(IDM_EDITUNDO, CmdUndo)
  840.     ON_COMMAND(IDM_EDITCUT, CmdCut)
  841.     ON_COMMAND(IDM_EDITCOPY, CmdCopy)
  842.     ON_COMMAND(IDM_EDITPASTE, CmdPaste)
  843.     ON_COMMAND(IDM_EDITCLEAR, CmdClear)
  844.     ON_COMMAND(IDM_EDITSETFONT, CmdSetFont)
  845.     ON_COMMAND(IDM_EDITSELECT, CmdSelectAll)
  846. END_MESSAGE_MAP()
  847.  
  848.  
  849. int CMultiPad::ExitInstance()
  850. {
  851.     extern CPrinter* thePrinter;
  852.     delete thePrinter;
  853.  
  854.     SaveMRU();
  855.     return CWinApp::ExitInstance();
  856. }
  857.