home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / WORDPAD.PAK / WORDPVW.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  24.2 KB  |  880 lines

  1. // wordpvw.cpp : implementation of the CWordPadView class
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "wordpad.h"
  15. #include "cntritem.h"
  16. #include "srvritem.h"
  17.  
  18. #include "wordpdoc.h"
  19. #include "wordpvw.h"
  20. #include "formatta.h"
  21. #include "datedial.h"
  22. #include "formatpa.h"
  23. #include "formatba.h"
  24. #include "ruler.h"
  25. #include "strings.h"
  26. #include "colorlis.h"
  27. #include "pageset.h"
  28. #include <penwin.h>
  29.  
  30. extern CLIPFORMAT cfEmbeddedObject;
  31. extern CLIPFORMAT cfRTO;
  32.  
  33. #ifdef _DEBUG
  34. #undef THIS_FILE
  35. static char BASED_CODE THIS_FILE[] = __FILE__;
  36. #endif
  37.  
  38. BOOL CCharFormat::operator==(CCharFormat& cf)
  39. {
  40.     return 
  41.     dwMask == cf.dwMask
  42.     && dwEffects == cf.dwEffects
  43.     && yHeight == cf.yHeight
  44.     && yOffset == cf.yOffset
  45.     && crTextColor == cf.crTextColor
  46.     && bPitchAndFamily == cf.bPitchAndFamily
  47.     && (lstrcmpA(szFaceName, cf.szFaceName) == 0);
  48. }
  49.  
  50. BOOL CParaFormat::operator==(PARAFORMAT& pf)
  51. {
  52.     if(
  53.         dwMask != pf.dwMask
  54.         || wNumbering != pf.wNumbering
  55.         || wReserved != pf.wReserved
  56.         || dxStartIndent != pf.dxStartIndent
  57.         || dxRightIndent != pf.dxRightIndent
  58.         || dxOffset != pf.dxOffset
  59.         || cTabCount != pf.cTabCount
  60.         )
  61.     {
  62.         return FALSE;
  63.     }
  64.     for (int i=0;i<pf.cTabCount;i++)
  65.     {
  66.         if (rgxTabs[i] != pf.rgxTabs[i])
  67.             return FALSE;
  68.     }
  69.     return TRUE;
  70. }
  71.  
  72. /////////////////////////////////////////////////////////////////////////////
  73. // CWordPadView
  74.  
  75. IMPLEMENT_DYNCREATE(CWordPadView, CRichEditView)
  76.  
  77. //WM_WININICHANGE -- default printer might have changed
  78. //WM_FONTCHANGE -- pool of fonts changed
  79. //WM_DEVMODECHANGE -- printer settings changes
  80.  
  81. BEGIN_MESSAGE_MAP(CWordPadView, CRichEditView)
  82.     ON_COMMAND(ID_CANCEL_EDIT_CNTR, OnCancelEditCntr)
  83.     ON_COMMAND(ID_CANCEL_EDIT_SRVR, OnCancelEditSrvr)
  84.     //{{AFX_MSG_MAP(CWordPadView)
  85.     ON_COMMAND(ID_PAGE_SETUP, OnPageSetup)
  86.     ON_COMMAND(ID_CHAR_BOLD, OnCharBold)
  87.     ON_UPDATE_COMMAND_UI(ID_CHAR_BOLD, OnUpdateCharBold)
  88.     ON_COMMAND(ID_CHAR_ITALIC, OnCharItalic)
  89.     ON_UPDATE_COMMAND_UI(ID_CHAR_ITALIC, OnUpdateCharItalic)
  90.     ON_COMMAND(ID_CHAR_UNDERLINE, OnCharUnderline)
  91.     ON_UPDATE_COMMAND_UI(ID_CHAR_UNDERLINE, OnUpdateCharUnderline)
  92.     ON_COMMAND(ID_PARA_CENTER, OnParaCenter)
  93.     ON_UPDATE_COMMAND_UI(ID_PARA_CENTER, OnUpdateParaCenter)
  94.     ON_COMMAND(ID_PARA_LEFT, OnParaLeft)
  95.     ON_UPDATE_COMMAND_UI(ID_PARA_LEFT, OnUpdateParaLeft)
  96.     ON_COMMAND(ID_PARA_RIGHT, OnParaRight)
  97.     ON_UPDATE_COMMAND_UI(ID_PARA_RIGHT, OnUpdateParaRight)
  98.     ON_WM_CREATE()
  99.     ON_COMMAND(ID_INSERT_DATE_TIME, OnInsertDateTime)
  100.     ON_COMMAND(ID_FORMAT_PARAGRAPH, OnFormatParagraph)
  101.     ON_COMMAND(ID_FORMAT_TABS, OnFormatTabs)
  102.     ON_COMMAND(ID_COLOR16, OnColorDefault)
  103.     ON_WM_TIMER()
  104.     ON_WM_DESTROY()
  105.     ON_WM_MEASUREITEM()
  106.     ON_COMMAND(ID_PEN_BACKSPACE, OnPenBackspace)
  107.     ON_COMMAND(ID_PEN_NEWLINE, OnPenNewline)
  108.     ON_COMMAND(ID_PEN_PERIOD, OnPenPeriod)
  109.     ON_COMMAND(ID_PEN_SPACE, OnPenSpace)
  110.     ON_WM_SIZE()
  111.     ON_WM_KEYDOWN()
  112.     ON_COMMAND(ID_FILE_PRINT, OnFilePrint)
  113.     ON_COMMAND(ID_FILE_PRINT_DIRECT, OnFilePrint)
  114.     ON_WM_DROPFILES()
  115.     ON_COMMAND(ID_PEN_LENS, OnPenLens)
  116.     ON_COMMAND(ID_PEN_TAB, OnPenTab)
  117.     ON_WM_PALETTECHANGED()
  118.     ON_WM_QUERYNEWPALETTE()
  119.     ON_WM_WININICHANGE()
  120.     //}}AFX_MSG_MAP
  121.     // Standard printing commands
  122.     ON_COMMAND(ID_INSERT_BULLET, CRichEditView::OnBullet)
  123.     ON_UPDATE_COMMAND_UI(ID_INSERT_BULLET, CRichEditView::OnUpdateBullet)
  124.     ON_COMMAND(ID_FILE_PRINT_PREVIEW, CRichEditView::OnFilePrintPreview)
  125.     ON_COMMAND_RANGE(ID_COLOR0, ID_COLOR16, OnColorPick)
  126.     ON_EN_CHANGE(AFX_IDW_PANE_FIRST, OnEditChange)
  127.     ON_WM_MOUSEACTIVATE()
  128.     ON_REGISTERED_MESSAGE(CWordPadApp::m_nPrinterChangedMsg, OnPrinterChangedMsg)
  129.     ON_NOTIFY(FN_GETFORMAT, ID_VIEW_FORMATBAR, OnGetCharFormat)
  130.     ON_NOTIFY(FN_SETFORMAT, ID_VIEW_FORMATBAR, OnSetCharFormat)
  131.     ON_NOTIFY(NM_SETFOCUS, ID_VIEW_FORMATBAR, OnBarSetFocus)
  132.     ON_NOTIFY(NM_KILLFOCUS, ID_VIEW_FORMATBAR, OnBarKillFocus)
  133.     ON_NOTIFY(NM_RETURN, ID_VIEW_FORMATBAR, OnBarReturn)
  134. END_MESSAGE_MAP()
  135.  
  136. /////////////////////////////////////////////////////////////////////////////
  137. // CWordPadView construction/destruction
  138.  
  139. CWordPadView::CWordPadView()
  140. {
  141.     m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
  142.     m_uTimerID = 0;
  143.     m_bDelayUpdateItems = FALSE;
  144.     m_bOnBar = FALSE;
  145.     m_bInPrint = FALSE;
  146.     m_nPasteType = 0;
  147.     m_rectMargin = theApp.m_rectPageMargin;
  148. }
  149.  
  150. BOOL CWordPadView::PreCreateWindow(CREATESTRUCT& cs) 
  151. {
  152.     BOOL bRes = CRichEditView::PreCreateWindow(cs);
  153.     cs.style |= ES_SELECTIONBAR;
  154.     return bRes;
  155. }            
  156.  
  157. /////////////////////////////////////////////////////////////////////////////
  158. // CWordPadView attributes
  159.  
  160. BOOL CWordPadView::IsFormatText()
  161. {
  162.     // this function checks to see if any formatting is not default text
  163.     BOOL bRes = FALSE;
  164.     CHARRANGE cr;
  165.     CCharFormat cf;
  166.     CParaFormat pf;
  167.     GetRichEditCtrl().GetSel(cr);
  168.     GetRichEditCtrl().HideSelection(TRUE, FALSE);
  169.     GetRichEditCtrl().SetSel(0,-1);
  170.  
  171.     if (!(GetRichEditCtrl().GetSelectionType() & (SEL_OBJECT|SEL_MULTIOBJECT)))
  172.     {
  173.         GetRichEditCtrl().GetSelectionCharFormat(cf);
  174.         if (cf == m_defTextCharFormat)
  175.         {
  176.             GetRichEditCtrl().GetParaFormat(pf);
  177.             if (pf == m_defParaFormat) //compared using CParaFormat::operator==
  178.                 bRes = TRUE;
  179.         }
  180.     }
  181.  
  182.     GetRichEditCtrl().SetSel(cr);
  183.     GetRichEditCtrl().HideSelection(FALSE, FALSE);
  184.     return bRes;
  185. }
  186.  
  187. HMENU CWordPadView::GetContextMenu(WORD, LPOLEOBJECT, CHARRANGE* )
  188. {
  189.     CRichEditCntrItem* pItem = GetSelectedItem();
  190.     if (pItem == NULL || !pItem->IsInPlaceActive())
  191.     {
  192.         CMenu menuText;
  193.         menuText.LoadMenu(IDR_TEXT_POPUP);
  194.         CMenu* pMenuPopup = menuText.GetSubMenu(0);
  195.         menuText.RemoveMenu(0, MF_BYPOSITION);
  196.         if (!GetSystemMetrics(SM_PENWINDOWS))
  197.         {
  198.             //delete pen specific stuff
  199.             // remove Insert Keystrokes
  200.             pMenuPopup->DeleteMenu(ID_PEN_LENS, MF_BYCOMMAND);
  201.             int nIndex = pMenuPopup->GetMenuItemCount()-1; //index of last item
  202.             // remove Edit Text...
  203.             pMenuPopup->DeleteMenu(nIndex, MF_BYPOSITION);
  204.             // remove separator
  205.             pMenuPopup->DeleteMenu(nIndex-1, MF_BYPOSITION);
  206.         }
  207.         return pMenuPopup->Detach();
  208.     }
  209.     return NULL;
  210. }
  211.  
  212. /////////////////////////////////////////////////////////////////////////////
  213. // CWordPadView operations
  214.  
  215. void CWordPadView::WrapChanged()
  216. {
  217.     CWaitCursor wait;
  218.     CFrameWnd* pFrameWnd = GetParentFrame();
  219.     ASSERT(pFrameWnd != NULL);
  220.     pFrameWnd->SetMessageText(IDS_FORMATTING);
  221.     CWnd* pBarWnd = pFrameWnd->GetMessageBar();
  222.     if (pBarWnd != NULL)
  223.         pBarWnd->UpdateWindow();
  224.  
  225.     CRichEditView::WrapChanged();
  226.  
  227.     pFrameWnd->SetMessageText(AFX_IDS_IDLEMESSAGE);
  228.     if (pBarWnd != NULL)
  229.         pBarWnd->UpdateWindow();
  230. }
  231.  
  232. void CWordPadView::SetUpdateTimer()
  233. {
  234.     if (m_uTimerID != 0) // if outstanding timer kill it
  235.         KillTimer(m_uTimerID);
  236.     m_uTimerID = SetTimer(1, 1000, NULL); //set a timer for 1000 milliseconds
  237.     if (m_uTimerID == 0) // no timer available so force update now
  238.         GetDocument()->UpdateAllItems(NULL);
  239.     else
  240.         m_bDelayUpdateItems = TRUE;
  241. }
  242.  
  243. void CWordPadView::DeleteContents()
  244. {
  245.     ASSERT_VALID(this);
  246.     ASSERT(m_hWnd != NULL);
  247.     CRichEditView::DeleteContents();
  248.     SetDefaultFont(IsTextType(GetDocument()->m_nNewDocType));
  249. }
  250.  
  251. void CWordPadView::SetDefaultFont(BOOL bText)
  252. {
  253.     ASSERT_VALID(this);
  254.     ASSERT(m_hWnd != NULL);
  255.     m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
  256.     CHARFORMAT* pCharFormat = bText ? &m_defTextCharFormat : &m_defCharFormat;
  257.     // set the default character format -- the FALSE makes it the default
  258.     GetRichEditCtrl().SetSel(0,-1);
  259.     GetRichEditCtrl().SetDefaultCharFormat(*pCharFormat);
  260.     GetRichEditCtrl().SetSelectionCharFormat(*pCharFormat);
  261.  
  262.     GetRichEditCtrl().SetParaFormat(m_defParaFormat);
  263.  
  264.     GetRichEditCtrl().SetSel(0,0);
  265.     GetRichEditCtrl().EmptyUndoBuffer();
  266.     GetRichEditCtrl().SetModify(FALSE);
  267.     ASSERT_VALID(this);
  268. }
  269.  
  270. /////////////////////////////////////////////////////////////////////////////
  271. // CWordPadView drawing
  272.  
  273. /////////////////////////////////////////////////////////////////////////////
  274. // CWordPadView printing
  275.  
  276. void CWordPadView::OnPrint(CDC* pDC, CPrintInfo* pInfo) 
  277. {
  278.     CRichEditView::OnPrint(pDC, pInfo);
  279.     if (pInfo != NULL && pInfo->m_bPreview)
  280.         DrawMargins(pDC);
  281. }
  282.  
  283. void CWordPadView::DrawMargins(CDC* pDC)
  284. {
  285.     if (pDC->m_hAttribDC != NULL)
  286.     {
  287.         CRect rect;
  288.         rect.left = m_rectMargin.left;
  289.         rect.right = m_sizePaper.cx - m_rectMargin.right;
  290.         rect.top = m_rectMargin.top;
  291.         rect.bottom = m_sizePaper.cy - m_rectMargin.bottom;
  292.         //rect in twips
  293.         int logx = ::GetDeviceCaps(pDC->m_hDC, LOGPIXELSX);
  294.         int logy = ::GetDeviceCaps(pDC->m_hDC, LOGPIXELSY);
  295.         rect.left = MulDiv(rect.left, logx, 1440);
  296.         rect.right = MulDiv(rect.right, logx, 1440);
  297.         rect.top = MulDiv(rect.top, logy, 1440);
  298.         rect.bottom = MulDiv(rect.bottom, logy, 1440);
  299.         CPen pen(PS_DOT, 0, pDC->GetTextColor());
  300.         CPen* ppen = pDC->SelectObject(&pen);
  301.         pDC->MoveTo(0, rect.top);
  302.         pDC->LineTo(10000, rect.top);
  303.         pDC->MoveTo(rect.left, 0);
  304.         pDC->LineTo(rect.left, 10000);
  305.         pDC->MoveTo(0, rect.bottom);
  306.         pDC->LineTo(10000, rect.bottom);
  307.         pDC->MoveTo(rect.right, 0);
  308.         pDC->LineTo(rect.right, 10000);
  309.         pDC->SelectObject(ppen);
  310.     }
  311. }
  312.  
  313. BOOL CWordPadView::OnPreparePrinting(CPrintInfo* pInfo)
  314. {
  315.     return DoPreparePrinting(pInfo);
  316. }
  317.  
  318. /////////////////////////////////////////////////////////////////////////////
  319. // OLE Client support and commands
  320.  
  321. inline int roundleast(int n)
  322. {
  323.     int mod = n%10;
  324.     n -= mod;
  325.     if (mod >= 5)
  326.         n += 10;
  327.     else if (mod <= -5)
  328.         n -= 10;
  329.     return n;
  330. }
  331.  
  332. static void RoundRect(LPRECT r1)
  333. {
  334.     r1->left = roundleast(r1->left);
  335.     r1->right = roundleast(r1->right);
  336.     r1->top = roundleast(r1->top);
  337.     r1->bottom = roundleast(r1->bottom);
  338. }
  339.  
  340. static void MulDivRect(LPRECT r1, LPRECT r2, int num, int div)
  341. {
  342.     r1->left = MulDiv(r2->left, num, div);
  343.     r1->top = MulDiv(r2->top, num, div);
  344.     r1->right = MulDiv(r2->right, num, div);
  345.     r1->bottom = MulDiv(r2->bottom, num, div);
  346. }
  347.  
  348. void CWordPadView::OnPageSetup()
  349. {
  350.     CPageSetupDialog dlg;
  351.     PAGESETUPDLG& psd = dlg.m_psd;
  352.     BOOL bMetric = theApp.GetUnits() == 1; //centimeters
  353.     psd.Flags |= PSD_MARGINS | (bMetric ? PSD_INHUNDREDTHSOFMILLIMETERS : 
  354.         PSD_INTHOUSANDTHSOFINCHES);
  355.     int nUnitsPerInch = bMetric ? 2540 : 1000;
  356.     MulDivRect(&psd.rtMargin, m_rectMargin, nUnitsPerInch, 1440);
  357.     RoundRect(&psd.rtMargin);
  358.     // get the current device from the app
  359.     PRINTDLG pd;
  360.     pd.hDevNames = NULL;
  361.     pd.hDevMode = NULL;
  362.     theApp.GetPrinterDeviceDefaults(&pd);
  363.     psd.hDevNames = pd.hDevNames;
  364.     psd.hDevMode = pd.hDevMode;
  365.     if (dlg.DoModal() == IDOK)
  366.     {
  367.         RoundRect(&psd.rtMargin);
  368.         MulDivRect(m_rectMargin, &psd.rtMargin, 1440, nUnitsPerInch);
  369.         theApp.m_rectPageMargin = m_rectMargin;
  370.         theApp.SelectPrinter(psd.hDevNames, psd.hDevMode);
  371.         theApp.NotifyPrinterChanged();
  372.     }
  373.     // PageSetupDlg failed
  374.     if (CommDlgExtendedError() != 0)
  375.     {
  376.         CPageSetupDlg dlg;
  377.         dlg.m_nBottomMargin = m_rectMargin.bottom;
  378.         dlg.m_nLeftMargin = m_rectMargin.left;
  379.         dlg.m_nRightMargin = m_rectMargin.right;
  380.         dlg.m_nTopMargin = m_rectMargin.top;
  381.         if (dlg.DoModal() == IDOK)
  382.         {
  383.             m_rectMargin.SetRect(dlg.m_nLeftMargin, dlg.m_nTopMargin, 
  384.                 dlg.m_nRightMargin, dlg.m_nBottomMargin);
  385.             // m_page will be changed at this point
  386.             theApp.m_rectPageMargin = m_rectMargin;
  387.             theApp.NotifyPrinterChanged();
  388.         }
  389.     }
  390. }
  391.  
  392. /////////////////////////////////////////////////////////////////////////////
  393. // OLE Server support
  394.  
  395. // The following command handler provides the standard keyboard
  396. //  user interface to cancel an in-place editing session.  Here,
  397. //  the server (not the container) causes the deactivation.
  398. void CWordPadView::OnCancelEditSrvr()
  399. {
  400.     GetDocument()->OnDeactivateUI(FALSE);
  401. }
  402.  
  403. /////////////////////////////////////////////////////////////////////////////
  404. // CWordPadView diagnostics
  405.  
  406. #ifdef _DEBUG
  407. void CWordPadView::AssertValid() const
  408. {
  409.     CRichEditView::AssertValid();
  410. }
  411.  
  412. void CWordPadView::Dump(CDumpContext& dc) const
  413. {
  414.     CRichEditView::Dump(dc);
  415. }
  416.  
  417. CWordPadDoc* CWordPadView::GetDocument() // non-debug version is inline
  418. {
  419.     return (CWordPadDoc*)m_pDocument;
  420. }
  421. #endif //_DEBUG
  422.  
  423. /////////////////////////////////////////////////////////////////////////////
  424. // CWordPadView message helpers
  425.  
  426. /////////////////////////////////////////////////////////////////////////////
  427. // CWordPadView message handlers
  428.  
  429. int CWordPadView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  430. {
  431.     if (CRichEditView::OnCreate(lpCreateStruct) == -1)
  432.         return -1;
  433.     theApp.m_listPrinterNotify.AddTail(m_hWnd);
  434.  
  435.     if (theApp.m_bWordSel)
  436.         GetRichEditCtrl().SetOptions(ECOOP_OR, ECO_AUTOWORDSELECTION);
  437.     else
  438.         GetRichEditCtrl().SetOptions(ECOOP_AND, ~(DWORD)ECO_AUTOWORDSELECTION);
  439. //    GetRichEditCtrl().SetOptions(ECOOP_OR, ECO_SELECTIONBAR);
  440.  
  441.     GetDefaultFont(m_defTextCharFormat, IDS_DEFAULTTEXTFONT);
  442.     GetDefaultFont(m_defCharFormat, IDS_DEFAULTFONT);
  443.         
  444.     GetRichEditCtrl().GetParaFormat(m_defParaFormat);
  445.     m_defParaFormat.cTabCount = 0;
  446.  
  447.     return 0;
  448. }
  449.  
  450. void CWordPadView::GetDefaultFont(CCharFormat& cf, UINT nFontNameID)
  451. {
  452.     USES_CONVERSION;
  453.     CString strDefFont;
  454.     VERIFY(strDefFont.LoadString(nFontNameID));
  455.     ASSERT(cf.cbSize == sizeof(CHARFORMAT));
  456.     cf.dwMask = CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT|CFM_SIZE|
  457.         CFM_COLOR|CFM_OFFSET|CFM_PROTECTED;
  458.     cf.dwEffects = CFE_AUTOCOLOR;
  459.     cf.yHeight = 200; //10pt
  460.     cf.yOffset = 0;
  461.     cf.crTextColor = RGB(0, 0, 0);
  462.     cf.bCharSet = 0;
  463.     cf.bPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  464.     ASSERT(strDefFont.GetLength() < LF_FACESIZE);
  465.     lstrcpynA(cf.szFaceName, T2A(strDefFont), LF_FACESIZE);
  466.     cf.dwMask |= CFM_FACE;
  467. }
  468.  
  469. void CWordPadView::OnInsertDateTime() 
  470. {
  471.     CDateDialog dlg;
  472.     if (dlg.DoModal() == IDOK)
  473.         GetRichEditCtrl().ReplaceSel(dlg.m_strSel);;
  474. }
  475.  
  476. void CWordPadView::OnFormatParagraph() 
  477. {
  478.     CFormatParaDlg dlg(GetParaFormatSelection());
  479.     dlg.m_nWordWrap = m_nWordWrap;
  480.     if (dlg.DoModal() == IDOK)
  481.         SetParaFormat(dlg.m_pf);
  482. }
  483.  
  484. void CWordPadView::OnFormatTabs() 
  485. {
  486.     CFormatTabDlg dlg(GetParaFormatSelection());
  487.     if (dlg.DoModal() == IDOK)
  488.         SetParaFormat(dlg.m_pf);
  489. }
  490.  
  491. void CWordPadView::OnTextNotFound(LPCTSTR lpStr)
  492. {
  493.     ASSERT_VALID(this);
  494.     MessageBeep(0);
  495.     AfxMessageBox(IDS_FINISHED_SEARCH,MB_OK|MB_ICONINFORMATION);
  496.     CRichEditView::OnTextNotFound(lpStr);
  497. }
  498.  
  499. void CWordPadView::OnColorPick(UINT nID)
  500. {
  501.     CRichEditView::OnColorPick(CColorMenu::GetColor(nID));
  502. }
  503.  
  504. void CWordPadView::OnTimer(UINT nIDEvent) 
  505. {
  506.     if (m_uTimerID != nIDEvent) // not our timer
  507.         CRichEditView::OnTimer(nIDEvent);
  508.     else
  509.     {
  510.         KillTimer(m_uTimerID); // kill one-shot timer
  511.         m_uTimerID = 0;
  512.         if (m_bDelayUpdateItems)
  513.             GetDocument()->UpdateAllItems(NULL);
  514.         m_bDelayUpdateItems = FALSE;
  515.     }    
  516. }
  517.  
  518. void CWordPadView::OnEditChange()
  519. {
  520.     SetUpdateTimer();
  521. }
  522.  
  523. void CWordPadView::OnDestroy() 
  524. {
  525.     POSITION pos = theApp.m_listPrinterNotify.Find(m_hWnd);
  526.     ASSERT(pos != NULL);
  527.     theApp.m_listPrinterNotify.RemoveAt(pos);
  528.  
  529.     CRichEditView::OnDestroy();
  530.     
  531.     if (m_uTimerID != 0) // if outstanding timer kill it
  532.         OnTimer(m_uTimerID);
  533.     ASSERT(m_uTimerID == 0);
  534. }
  535.  
  536. void CWordPadView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType) 
  537. {
  538.     int nOldWidth = lpClientRect->right - lpClientRect->left;
  539.     CRichEditView::CalcWindowRect(lpClientRect, nAdjustType);
  540.  
  541.     if (theApp.m_bWin4 && nAdjustType != 0 && (GetStyle() & WS_VSCROLL))
  542.         lpClientRect->right--;
  543.  
  544.     // if the ruler is visible then slide the view up under the ruler to avoid
  545.     // showing the top border of the view
  546.     if (GetExStyle() & WS_EX_CLIENTEDGE)
  547.     {
  548.         CFrameWnd* pFrame = GetParentFrame();
  549.         if (pFrame != NULL)
  550.         {
  551.             CRulerBar* pBar = (CRulerBar*)pFrame->GetControlBar(ID_VIEW_RULER);
  552.             if (pBar != NULL)
  553.             {
  554.                 BOOL bVis = pBar->IsVisible();
  555.                 if (pBar->m_bDeferInProgress)
  556.                     bVis = !bVis;
  557.                 if (bVis)
  558.                     lpClientRect->top -= 2;
  559.             }
  560.         }
  561.     }
  562. }
  563.  
  564. void CWordPadView::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMIS) 
  565. {
  566.     lpMIS->itemID = (UINT)(WORD)lpMIS->itemID;
  567.     CRichEditView::OnMeasureItem(nIDCtl, lpMIS);
  568. }
  569.  
  570. void CWordPadView::OnPenBackspace() 
  571. {
  572.     SendMessage(WM_KEYDOWN, VK_BACK, 0);
  573.     SendMessage(WM_KEYUP, VK_BACK, 0);
  574. }
  575.  
  576. void CWordPadView::OnPenNewline() 
  577. {
  578.     SendMessage(WM_CHAR, '\n', 0);
  579. }
  580.  
  581. void CWordPadView::OnPenPeriod() 
  582. {
  583.     SendMessage(WM_CHAR, '.', 0);
  584. }
  585.  
  586. void CWordPadView::OnPenSpace() 
  587. {
  588.     SendMessage(WM_CHAR, ' ', 0);
  589. }
  590.  
  591. void CWordPadView::OnPenTab() 
  592. {
  593.     SendMessage(WM_CHAR, VK_TAB, 0);
  594. }
  595.  
  596. void CWordPadView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  597. {
  598.     if (nChar == VK_F10 && GetKeyState(VK_SHIFT) < 0)
  599.     {
  600.         long nStart, nEnd;
  601.         GetRichEditCtrl().GetSel(nStart, nEnd);
  602.         CPoint pt = GetRichEditCtrl().GetCharPos(nEnd);
  603.         SendMessage(WM_CONTEXTMENU, (WPARAM)m_hWnd, MAKELPARAM(pt.x, pt.y));
  604.     }
  605.         
  606.     CRichEditView::OnKeyDown(nChar, nRepCnt, nFlags);
  607. }
  608.  
  609. HRESULT CWordPadView::GetClipboardData(CHARRANGE* lpchrg, DWORD /*reco*/, 
  610.     LPDATAOBJECT lpRichDataObj,    LPDATAOBJECT* lplpdataobj)
  611. {
  612.     CHARRANGE& cr = *lpchrg;
  613.  
  614.     if ((cr.cpMax - cr.cpMin == 1) && 
  615.         GetRichEditCtrl().GetSelectionType() == SEL_OBJECT)
  616.     {
  617.         return E_NOTIMPL;
  618.     }
  619.  
  620.     BeginWaitCursor();
  621.     //create the data source
  622.     COleDataSource* pDataSource = new COleDataSource;
  623.  
  624.     // put the formats into the data source
  625.     LPENUMFORMATETC lpEnumFormatEtc;
  626.     lpRichDataObj->EnumFormatEtc(DATADIR_SET, &lpEnumFormatEtc);
  627.     if (lpEnumFormatEtc != NULL)
  628.     {
  629.         FORMATETC etc;
  630.         while (lpEnumFormatEtc->Next(1, &etc, NULL) == S_OK) 
  631.         {
  632.             STGMEDIUM stgMedium;
  633.             lpRichDataObj->GetData(&etc, &stgMedium);
  634.             pDataSource->CacheData(etc.cfFormat, &stgMedium, &etc);
  635.         }
  636.         lpEnumFormatEtc->Release();
  637.     }
  638.  
  639.     CEmbeddedItem item(GetDocument(), cr.cpMin, cr.cpMax);
  640.     item.m_lpRichDataObj = lpRichDataObj;
  641.     // get wordpad formats
  642.     item.GetClipboardData(pDataSource);
  643.  
  644.     // get the IDataObject from the data source
  645.     *lplpdataobj =     (LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);
  646.  
  647.     EndWaitCursor();
  648.     return S_OK;
  649. }
  650.  
  651. HRESULT CWordPadView::QueryAcceptData(LPDATAOBJECT lpdataobj,
  652.     CLIPFORMAT* lpcfFormat, DWORD reco, BOOL bReally, 
  653.     HGLOBAL hMetaPict)
  654. {
  655.     if (bReally && *lpcfFormat == 0 && (m_nPasteType == 0))
  656.     {
  657.         COleDataObject dataobj;
  658.         dataobj.Attach(lpdataobj, FALSE);
  659.         if (!dataobj.IsDataAvailable(cfRTO)) // native avail, let richedit do as it wants
  660.         {
  661.             if (dataobj.IsDataAvailable(cfEmbeddedObject))
  662.             {
  663.                 if (PasteNative(lpdataobj))
  664.                     return S_FALSE;
  665.             }
  666.         }
  667.     }
  668.     return CRichEditView::QueryAcceptData(lpdataobj, lpcfFormat, reco, bReally,
  669.         hMetaPict);
  670. }
  671.  
  672. BOOL CWordPadView::PasteNative(LPDATAOBJECT lpdataobj)
  673. {
  674.     // check data object for wordpad object
  675.     // if true, suck out RTF directly
  676.     FORMATETC etc = {NULL, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE};
  677.     etc.cfFormat = (CLIPFORMAT)cfEmbeddedObject;
  678.     STGMEDIUM stgMedium = {TYMED_ISTORAGE, 0, NULL};
  679.  
  680.     // create an IStorage to transfer the data in
  681.     LPLOCKBYTES lpLockBytes;
  682.     if (FAILED(::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes)))
  683.         return FALSE;
  684.     ASSERT(lpLockBytes != NULL);
  685.  
  686.     HRESULT hr = ::StgCreateDocfileOnILockBytes(lpLockBytes,
  687.         STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &stgMedium.pstg);
  688.     lpLockBytes->Release(); //storage addref'd
  689.     if (FAILED(hr))
  690.         return FALSE;
  691.  
  692.     ASSERT(stgMedium.pstg != NULL);
  693.     CLSID clsid;
  694.     BOOL bRes = FALSE; //let richedit do what it wants
  695.     if (SUCCEEDED(lpdataobj->GetDataHere(&etc, &stgMedium)) &&
  696.         SUCCEEDED(ReadClassStg(stgMedium.pstg, &clsid)) &&
  697.         clsid == GetDocument()->GetClassID())
  698.     {
  699.         //suck out RTF now
  700.         // open Contents stream
  701.         COleStreamFile file;
  702.         CFileException fe;
  703.         if (file.OpenStream(stgMedium.pstg, szContents,
  704.             CFile::modeReadWrite|CFile::shareExclusive, &fe))
  705.         {
  706.  
  707.             // load it with CArchive (loads from Contents stream)
  708.             CArchive loadArchive(&file, CArchive::load | 
  709.                 CArchive::bNoFlushOnDelete);
  710.             Stream(loadArchive, TRUE); //stream in selection
  711.             hr = TRUE; // don't let richedit do anything
  712.         }
  713.     }
  714.     ::ReleaseStgMedium(&stgMedium);
  715.     return bRes;
  716. }
  717.  
  718. // things to fix
  719. // if format==0 we are doing a straight EM_PASTE
  720. //     look for native formats
  721. //        richedit specific -- allow richedit to handle (these will be first)
  722. //         look for RTF, CF_TEXT.  If there paste special as these
  723. //     Do standard OLE scenario
  724.  
  725. // if pasting a particular format (format != 0)
  726. //    if richedit specific, allow through
  727. //    if RTF, CF_TEXT. paste special
  728. //    if OLE format, do standard OLE scenario
  729.  
  730.  
  731. void CWordPadView::OnFilePrint() 
  732. {
  733.     // don't allow winini changes to occur while printing
  734.     m_bInPrint = TRUE;
  735.     CRichEditView::OnFilePrint();
  736.     // printer may have changed
  737.     theApp.NotifyPrinterChanged(); // this will cause a GetDocument()->PrinterChanged();
  738.     m_bInPrint = FALSE;
  739. }
  740.  
  741. int CWordPadView::OnMouseActivate(CWnd* pWnd, UINT nHitTest, UINT message)
  742. {
  743.     if (m_bOnBar)
  744.     {
  745.         SetFocus();
  746.         return MA_ACTIVATEANDEAT;
  747.     }
  748.     else
  749.         return CRichEditView::OnMouseActivate(pWnd, nHitTest, message);
  750. }
  751.  
  752. typedef BOOL (WINAPI *PCWPROC)(HWND, LPSTR, UINT, LPVOID, DWORD, DWORD);
  753. void CWordPadView::OnPenLens() 
  754. {
  755.     USES_CONVERSION;
  756.     HINSTANCE hLib = LoadLibrary(_T("PENWIN32.DLL"));
  757.     if (hLib == NULL)
  758.         return;
  759.     PCWPROC pCorrectWriting = (PCWPROC)GetProcAddress(hLib, "CorrectWriting");
  760.     ASSERT(pCorrectWriting != NULL);
  761.     if (pCorrectWriting != NULL)
  762.     {
  763.         CHARRANGE cr;
  764.         GetRichEditCtrl().GetSel(cr);
  765.         int nCnt = 2*(cr.cpMax-cr.cpMin);
  766.         BOOL bSel = (nCnt != 0);
  767.         nCnt = max(1024, nCnt);
  768.         char* pBuf = new char[nCnt];
  769.         pBuf[0] = NULL;
  770.         if (bSel)
  771.             GetRichEditCtrl().GetSelText(pBuf);
  772.         if (pCorrectWriting(m_hWnd, pBuf, nCnt, 0, bSel ? 0 : CWR_INSERT, 0))
  773.             GetRichEditCtrl().ReplaceSel(A2T(pBuf));
  774.         delete [] pBuf;
  775.     }
  776.     FreeLibrary(hLib);
  777. }
  778.  
  779. LONG CWordPadView::OnPrinterChangedMsg(UINT, LONG)
  780. {
  781.     CDC dc;
  782.     AfxGetApp()->CreatePrinterDC(dc);
  783.     OnPrinterChanged(dc);
  784.     return 0;
  785. }
  786.  
  787. static void ForwardPaletteChanged(HWND hWndParent, HWND hWndFocus)
  788. {
  789.     // this is a quick and dirty hack to send the WM_QUERYNEWPALETTE to a window that is interested
  790.     HWND hWnd = NULL;
  791.     for (hWnd = ::GetWindow(hWndParent, GW_CHILD); hWnd != NULL; hWnd = ::GetWindow(hWnd, GW_HWNDNEXT))
  792.     {
  793.         if (hWnd != hWndFocus)
  794.         {
  795.             ::SendMessage(hWnd, WM_PALETTECHANGED, (WPARAM)hWndFocus, 0L);
  796.             ForwardPaletteChanged(hWnd, hWndFocus);
  797.         }
  798.     }
  799. }
  800.  
  801. void CWordPadView::OnPaletteChanged(CWnd* pFocusWnd) 
  802. {
  803.     ForwardPaletteChanged(m_hWnd, pFocusWnd->GetSafeHwnd());
  804.     // allow the richedit control to realize its palette
  805.     // remove this if if richedit fixes their code so that
  806.     // they don't realize their palette into foreground
  807.     if (::GetWindow(m_hWnd, GW_CHILD) == NULL)
  808.         CRichEditView::OnPaletteChanged(pFocusWnd);
  809. }
  810.  
  811. static BOOL FindQueryPalette(HWND hWndParent)
  812. {
  813.     // this is a quick and dirty hack to send the WM_QUERYNEWPALETTE to a window that is interested
  814.     HWND hWnd = NULL;
  815.     for (hWnd = ::GetWindow(hWndParent, GW_CHILD); hWnd != NULL; hWnd = ::GetWindow(hWnd, GW_HWNDNEXT))
  816.     {
  817.         if (::SendMessage(hWnd, WM_QUERYNEWPALETTE, 0, 0L))
  818.             return TRUE;
  819.         else if (FindQueryPalette(hWnd))
  820.             return TRUE;
  821.     }
  822.     return FALSE;
  823. }
  824.  
  825. BOOL CWordPadView::OnQueryNewPalette() 
  826. {
  827.     if(FindQueryPalette(m_hWnd))
  828.         return TRUE;
  829.     return CRichEditView::OnQueryNewPalette();
  830. }
  831.  
  832. void CWordPadView::OnWinIniChange(LPCTSTR lpszSection) 
  833. {
  834.     CRichEditView::OnWinIniChange(lpszSection);
  835.     //printer might have changed
  836.     if (!m_bInPrint)
  837.     {
  838.         if (lstrcmpi(lpszSection, _T("windows")) == 0)
  839.             theApp.NotifyPrinterChanged(TRUE); // force update to defaults
  840.     }
  841. }
  842.  
  843. void CWordPadView::OnSize(UINT nType, int cx, int cy)
  844. {
  845.     CRichEditView::OnSize(nType, cx, cy);
  846.     CRect rect(HORZ_TEXTOFFSET, VERT_TEXTOFFSET, cx, cy);
  847.     GetRichEditCtrl().SetRect(rect);
  848. }
  849.  
  850. void CWordPadView::OnGetCharFormat(NMHDR* pNMHDR, LRESULT* pRes)
  851. {
  852.     ASSERT(pNMHDR != NULL);
  853.     ASSERT(pRes != NULL);
  854.     ((CHARHDR*)pNMHDR)->cf = GetCharFormatSelection();
  855.     *pRes = 1;
  856. }
  857.  
  858. void CWordPadView::OnSetCharFormat(NMHDR* pNMHDR, LRESULT* pRes)
  859. {
  860.     ASSERT(pNMHDR != NULL);
  861.     ASSERT(pRes != NULL);
  862.     SetCharFormat(((CHARHDR*)pNMHDR)->cf);
  863.     *pRes = 1;
  864. }
  865.  
  866. void CWordPadView::OnBarSetFocus(NMHDR*, LRESULT*)
  867. {
  868.     m_bOnBar = TRUE;
  869. }
  870.  
  871. void CWordPadView::OnBarKillFocus(NMHDR*, LRESULT*)
  872. {
  873.     m_bOnBar = FALSE;
  874. }
  875.  
  876. void CWordPadView::OnBarReturn(NMHDR*, LRESULT* )
  877. {
  878.     SetFocus();
  879. }
  880.