home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap17 / patron / pages.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-04  |  22.9 KB  |  1,091 lines

  1. /*
  2.  * PAGES.CPP
  3.  * Patron Chapter 17
  4.  *
  5.  * Implementation of the CPages class.  See PAGEWIN.CPP and PRINT.CPP
  6.  * for additional member functions.
  7.  *
  8.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Microsoft
  11.  * Internet  :  kraigb@microsoft.com
  12.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  13.  */
  14.  
  15.  
  16. #include "patron.h"
  17.  
  18.  
  19. /*
  20.  * CPages:CPages
  21.  * CPages::~CPages
  22.  *
  23.  * Constructor Parameters:
  24.  *  hInst           HINSTANCE of the application we're in.
  25.  *  cf              UINT application clipboard format.
  26.  */
  27.  
  28. CPages::CPages(HINSTANCE hInst, UINT cf)
  29.     : CWindow(hInst)
  30.     {
  31.     m_pPageCur=NULL;
  32.     m_iPageCur=NOVALUE;  //Pages are 0 indexed, this is one before
  33.     m_cPages=0;
  34.     m_hWndPageList=NULL;
  35.     m_hFont=NULL;
  36.     m_fSystemFont=FALSE;
  37.  
  38.     //Initialize to 8.5*11 inch with .25 inch margins as a default.
  39.     m_cx=(LOMETRIC_PER_INCH*17)/2;
  40.     m_cy=LOMETRIC_PER_INCH*11;
  41.  
  42.     m_xMarginLeft=LOMETRIC_PER_INCH/4;
  43.     m_xMarginRight=LOMETRIC_PER_INCH/4;
  44.     m_yMarginTop=LOMETRIC_PER_INCH/4;
  45.     m_yMarginBottom=LOMETRIC_PER_INCH/4;
  46.  
  47.     m_xPos=0L;
  48.     m_yPos=0L;
  49.  
  50.     m_dwIDNext=0;
  51.     m_pIStorage=NULL;
  52.  
  53.     m_fDirty=FALSE;
  54.     m_cf=cf;
  55.  
  56.     m_fDragSource=FALSE;
  57.     m_fMoveInPage=FALSE;
  58.  
  59.     m_fDragRectShown=FALSE;
  60.  
  61.     m_uScrollInset=GetProfileInt(TEXT("windows")
  62.         , TEXT("DragScrollInset"), DD_DEFSCROLLINSET);
  63.     m_uScrollDelay=GetProfileInt(TEXT("windows")
  64.         , TEXT("DragScrollDelay"), DD_DEFSCROLLDELAY);
  65.  
  66.     m_uHScrollCode=0;
  67.     m_uVScrollCode=0;
  68.     return;
  69.     }
  70.  
  71.  
  72. CPages::~CPages(void)
  73.     {
  74.     //Ensure memory cleaned up in list; do final IStorage::Release
  75.     StorageSet(NULL, FALSE, FALSE);
  76.  
  77.     if (NULL!=m_hFont && !m_fSystemFont)
  78.         DeleteObject(m_hFont);
  79.  
  80.     if (NULL!=m_hWndPageList)
  81.         DestroyWindow(m_hWndPageList);
  82.  
  83.     //m_hWnd destroyed with the document.
  84.     return;
  85.     }
  86.  
  87.  
  88.  
  89. /*
  90.  * CPages::FIsDirty
  91.  *
  92.  * Purpose:
  93.  *  Tells the caller (document) if anything's happened to dirty us.
  94.  *
  95.  * Parameters:
  96.  *  None
  97.  *
  98.  * Return Value:
  99.  *  None
  100.  */
  101.  
  102. BOOL CPages::FIsDirty(void)
  103.     {
  104.     return m_fDirty;
  105.     }
  106.  
  107.  
  108.  
  109. /*
  110.  * CPages::Init
  111.  *
  112.  * Purpose:
  113.  *  Instantiates a pages window within a given parent.  The
  114.  *  parent may be a main application window, could be an MDI child
  115.  *  window. We really do not care.
  116.  *
  117.  * Parameters:
  118.  *  hWndParent      HWND of the parent of this window
  119.  *  pRect           LPRECT that this window should occupy
  120.  *  dwStyle         DWORD containing the window's style flags.
  121.  *                  Should contain WS_CHILD | WS_VISIBLE in
  122.  *                  typical circumstances.
  123.  *  uID             UINT ID to associate with this window
  124.  *  pv              LPVOID unused for now.
  125.  *
  126.  * Return Value:
  127.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  128.  */
  129.  
  130. BOOL CPages::Init(HWND hWndParent, LPRECT pRect, DWORD dwStyle
  131.     , UINT uID, LPVOID pv)
  132.     {
  133.     int     cy;
  134.  
  135.     m_hWnd=CreateWindowEx(WS_EX_NOPARENTNOTIFY, SZCLASSPAGES
  136.         , SZCLASSPAGES, dwStyle, pRect->left, pRect->top
  137.         , pRect->right-pRect->left, pRect->bottom-pRect->top
  138.         , hWndParent, (HMENU)uID, m_hInst, this);
  139.  
  140.     if (NULL==m_hWnd)
  141.         return FALSE;
  142.  
  143.     /*
  144.      * Create the hidden listbox we'll use to track pages.  We give
  145.      * it the owner-draw style so we can just store pointers in it.
  146.      */
  147.     m_hWndPageList=CreateWindow(TEXT("listbox"), TEXT("Page List")
  148.         , WS_POPUP | LBS_OWNERDRAWFIXED, 0, 0, 100, 100
  149.         , HWND_DESKTOP, NULL, m_hInst, NULL);
  150.  
  151.     if (NULL==m_hWndPageList)
  152.         return FALSE;
  153.  
  154.     //Create a 14 point Arial font, or use the system variable font.
  155.     cy=MulDiv(-14, LOMETRIC_PER_INCH, 72);
  156.     m_hFont=CreateFont(cy, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE
  157.         , ANSI_CHARSET, OUT_TT_PRECIS, CLIP_TT_ALWAYS, PROOF_QUALITY
  158.         , VARIABLE_PITCH | FF_SWISS, TEXT("Arial"));
  159.  
  160.     if (NULL==m_hFont)
  161.         {
  162.         m_hFont=(HFONT)GetStockObject(ANSI_VAR_FONT);
  163.         m_fSystemFont=TRUE;
  164.         }
  165.  
  166.     return TRUE;
  167.     }
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174. /*
  175.  * CPages::StorageSet
  176.  *
  177.  * Purpose:
  178.  *  Provides the document's IStorage to the pages for its own use.
  179.  *  If this is a new storage, we initalize it with streams that we
  180.  *  want to always exists.  If this is an open, then we create
  181.  *  our page list from the PageList string we wrote before.
  182.  *
  183.  * Parameters:
  184.  *  pIStorage       LPSTORAGE to the new or opened storage.  If
  185.  *                  NULL, we just clean up and exit.
  186.  *  fChange         BOOL indicating is this was a Save As operation,
  187.  *                  meaning that we have the structure already and
  188.  *                  just need to change the value of m_pIStorage.
  189.  *  fInitNew        BOOL indicating if this is a new storage or one
  190.  *                  opened from a previous save.
  191.  *
  192.  * Return Value:
  193.  *  BOOL            TRUE if successful, FALSE otherwise.
  194.  */
  195.  
  196. BOOL CPages::StorageSet(LPSTORAGE pIStorage, BOOL fChange
  197.     , BOOL fInitNew)
  198.     {
  199.     DWORD           dwMode=STGM_DIRECT | STGM_READWRITE
  200.                         | STGM_SHARE_EXCLUSIVE;
  201.     HRESULT         hr;
  202.     PCPage          pPage;
  203.     BOOL            fRet=FALSE;
  204.     ULONG           cbRead;
  205.     PAGELIST        pgList;
  206.     LPSTREAM        pIStream;
  207.     LPMALLOC        pIMalloc;
  208.     LPDWORD         pdwID;
  209.     UINT            i;
  210.  
  211.     //If we're changing saved roots, simply open current page again
  212.     if (fChange)
  213.         {
  214.         if (NULL==pIStorage)
  215.             return FALSE;
  216.  
  217.         m_pIStorage->Release();
  218.         m_pIStorage=pIStorage;
  219.         m_pIStorage->AddRef();
  220.  
  221.         PageGet(m_iPageCur, &m_pPageCur, TRUE);
  222.         m_fDirty=FALSE;
  223.         return TRUE;
  224.         }
  225.  
  226.     if (NULL!=m_hWndPageList)
  227.         {
  228.         //On new or open, clean out whatever it is we have.
  229.         for (i=0; i < m_cPages; i++)
  230.             {
  231.             if (PageGet(i, &pPage, FALSE))
  232.                 delete pPage;
  233.             }
  234.  
  235.         SendMessage(m_hWndPageList, LB_RESETCONTENT, 0, 0L);
  236.         }
  237.  
  238.     if (NULL!=m_pIStorage)
  239.         m_pIStorage->Release();
  240.  
  241.     m_pIStorage=NULL;
  242.  
  243.     //If we're just cleaning up, then we're done.
  244.     if (NULL==pIStorage)
  245.         return TRUE;
  246.  
  247.     m_pIStorage=pIStorage;
  248.     m_pIStorage->AddRef();
  249.  
  250.     //If this is a new storage, create the streams we require
  251.     if (fInitNew)
  252.         {
  253.         //Page list header.
  254.         hr=m_pIStorage->CreateStream(SZSTREAMPAGELIST, dwMode
  255.             | STGM_CREATE, 0, 0, &pIStream);
  256.  
  257.         if (FAILED(hr))
  258.             return FALSE;
  259.  
  260.         pIStream->Release();
  261.  
  262.         //Device Configuration
  263.         hr=m_pIStorage->CreateStream(SZSTREAMDEVICECONFIG, dwMode
  264.             | STGM_CREATE, 0, 0, &pIStream);
  265.  
  266.         if (FAILED(hr))
  267.             return FALSE;
  268.  
  269.         pIStream->Release();
  270.         return TRUE;
  271.         }
  272.  
  273.  
  274.     /*
  275.      * We're opening an existing file:
  276.      *  1)  Configure for the device we're on
  277.      *  2)  Read the Page List and create page entries for each.
  278.      */
  279.  
  280.     ConfigureForDevice();
  281.  
  282.     //Read the page list.
  283.     hr=m_pIStorage->OpenStream(SZSTREAMPAGELIST, NULL, dwMode, 0
  284.         , &pIStream);
  285.  
  286.     if (FAILED(hr))
  287.         return FALSE;
  288.  
  289.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  290.         {
  291.         pIStream->Read(&pgList, sizeof(PAGELIST), &cbRead);
  292.         m_cPages  =(UINT)pgList.cPages;
  293.         m_iPageCur=(UINT)pgList.iPageCur;
  294.         m_dwIDNext=pgList.dwIDNext;
  295.  
  296.         fRet=TRUE;
  297.         cbRead=pgList.cPages*sizeof(DWORD);
  298.  
  299.         if (0!=cbRead)
  300.             {
  301.             pdwID=(LPDWORD)pIMalloc->Alloc(cbRead);
  302.  
  303.             if (NULL!=pdwID)
  304.                 {
  305.                 pIStream->Read(pdwID, cbRead, &cbRead);
  306.  
  307.                 for (i=0; i < m_cPages; i++)
  308.                     fRet &=PageAdd(NOVALUE, *(pdwID+i), FALSE);
  309.  
  310.                 pIMalloc->Free(pdwID);
  311.                 }
  312.             }
  313.  
  314.         pIMalloc->Release();
  315.         }
  316.  
  317.     pIStream->Release();
  318.  
  319.     if (!fRet)
  320.         return FALSE;
  321.  
  322.     PageGet(m_iPageCur, &m_pPageCur, TRUE);
  323.     m_fDirty=FALSE;
  324.  
  325.     InvalidateRect(m_hWnd, NULL, FALSE);
  326.     UpdateWindow(m_hWnd);
  327.  
  328.     return TRUE;
  329.     }
  330.  
  331.  
  332.  
  333.  
  334.  
  335. /*
  336.  * CPages::StorageUpdate
  337.  *
  338.  * Purpose:
  339.  *  Insures that all pages are committed before a root save.
  340.  *
  341.  * Parameters:
  342.  *  fCloseAll       BOOL directing us to close all open storages
  343.  *                  and streams.
  344.  *
  345.  * Return Value:
  346.  *  BOOL            TRUE if successful, FALSE otherwise.
  347.  */
  348.  
  349. BOOL CPages::StorageUpdate(BOOL fCloseAll)
  350.     {
  351.     PCPage          pPage;
  352.     LPSTREAM        pIStream;
  353.     LPMALLOC        pIMalloc;
  354.     LPDWORD         pdwID;
  355.     ULONG           cb;
  356.     HRESULT         hr;
  357.     PAGELIST        pgList;
  358.     BOOL            fRet=FALSE;
  359.     UINT            i;
  360.  
  361.     //We only need to close the current page--nothing else is open.
  362.     if (NULL!=m_pPageCur)
  363.         {
  364.         m_pPageCur->Update();
  365.  
  366.         if (fCloseAll)
  367.             m_pPageCur->Close(FALSE);
  368.         }
  369.  
  370.     //We don't hold anything else open, so write the page list.
  371.     hr=m_pIStorage->OpenStream(SZSTREAMPAGELIST, NULL, STGM_DIRECT
  372.         | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  373.  
  374.     if (FAILED(hr))
  375.         return FALSE;
  376.  
  377.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
  378.         {
  379.         pgList.cPages=m_cPages;
  380.         pgList.iPageCur=m_iPageCur;
  381.         pgList.dwIDNext=m_dwIDNext;
  382.  
  383.         pIStream->Write(&pgList, sizeof(PAGELIST), &cb);
  384.  
  385.         cb=m_cPages*sizeof(DWORD);
  386.         pdwID=(LPDWORD)pIMalloc->Alloc(cb);
  387.  
  388.         if (NULL!=pdwID)
  389.             {
  390.             for (i=0; i < m_cPages; i++)
  391.                 {
  392.                 PageGet(i, &pPage, FALSE);
  393.                 *(pdwID+i)=pPage->GetID();
  394.                 }
  395.  
  396.             pIStream->Write(pdwID, cb, &cb);
  397.             pIMalloc->Free(pdwID);
  398.             fRet=TRUE;
  399.             }
  400.         pIMalloc->Release();
  401.         }
  402.  
  403.     pIStream->Release();
  404.  
  405.     //Clean up the dirty flag when we do an update.
  406.     m_fDirty=!fRet;
  407.     return fRet;
  408.     }
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416. /*
  417.  * CPages::RectGet
  418.  *
  419.  * Purpose:
  420.  *  Returns the rectangle of the Pages window in parent coordinates.
  421.  *
  422.  * Parameters:
  423.  *  pRect           LPRECT in which to return the rectangle.
  424.  *
  425.  * Return Value:
  426.  *  None
  427.  */
  428.  
  429. void CPages::RectGet(LPRECT pRect)
  430.     {
  431.     RECT        rc;
  432.     POINT       pt;
  433.  
  434.     //Retrieve the size of our rectangle in parent coordinates.
  435.     GetWindowRect(m_hWnd, &rc);
  436.     SETPOINT(pt, rc.left, rc.top);
  437.     ScreenToClient(GetParent(m_hWnd), &pt);
  438.  
  439.     SetRect(pRect, pt.x, pt.y, pt.x+(rc.right-rc.left)
  440.         , pt.y+(rc.bottom-rc.top));
  441.  
  442.     return;
  443.     }
  444.  
  445.  
  446.  
  447.  
  448.  
  449.  
  450. /*
  451.  * CPages::RectSet
  452.  *
  453.  * Purpose:
  454.  *  Sets a new rectangle for the Pages window which sizes to fit.
  455.  *  Coordinates are given in parent terms.
  456.  *
  457.  * Parameters:
  458.  *  pRect           LPRECT containing the new rectangle.
  459.  *  fNotify         BOOL indicating if we're to notify anyone of
  460.  *                  the change.
  461.  *
  462.  * Return Value:
  463.  *  None
  464.  */
  465.  
  466. void CPages::RectSet(LPRECT pRect, BOOL fNotify)
  467.     {
  468.     UINT        cx, cy;
  469.  
  470.     if (NULL==pRect)
  471.         return;
  472.  
  473.     cx=pRect->right-pRect->left;
  474.     cy=pRect->bottom-pRect->top;
  475.  
  476.     SetWindowPos(m_hWnd, NULL, pRect->left, pRect->top
  477.         , (UINT)cx, (UINT)cy, SWP_NOZORDER);
  478.  
  479.     UpdateScrollRanges();
  480.     return;
  481.     }
  482.  
  483.  
  484.  
  485.  
  486. /*
  487.  * CPages::SizeGet
  488.  *
  489.  * Purpose:
  490.  *  Retrieves the size of the pages window in parent coordinates.
  491.  *
  492.  * Parameters:
  493.  *  pRect           LPRECT in which to return the size.  The right
  494.  *                  and bottom fields will contain the dimensions.
  495.  *
  496.  * Return Value:
  497.  *  None
  498.  */
  499.  
  500. void CPages::SizeGet(LPRECT pRect)
  501.     {
  502.     RectGet(pRect);
  503.     return;
  504.     }
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512. /*
  513.  * CPages::SizeSet
  514.  *
  515.  * Purpose:
  516.  *  Sets a new size in parent coordinates for the Pages window.
  517.  *
  518.  * Parameters:
  519.  *  pRect           LPRECT containing the new rectangle.
  520.  *  fNotify         BOOL indicating if we're to notify anyone of
  521.  *                  the change.
  522.  *
  523.  * Return Value:
  524.  *  None
  525.  */
  526.  
  527. void CPages::SizeSet(LPRECT pRect, BOOL fNotify)
  528.     {
  529.     UINT        cx, cy;
  530.  
  531.     if (NULL==pRect)
  532.         return;
  533.  
  534.     cx=pRect->right-pRect->left;
  535.     cy=pRect->bottom-pRect->top;
  536.  
  537.     SetWindowPos(m_hWnd, NULL, 0, 0, (UINT)cx, (UINT)cy
  538.         , SWP_NOMOVE | SWP_NOZORDER);
  539.  
  540.     UpdateScrollRanges();
  541.     return;
  542.     }
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549. /*
  550.  * CPages::ActivePage
  551.  *
  552.  * Purpose:
  553.  *  Returns a CPage pointer to the current page.
  554.  *
  555.  * Parameters:
  556.  *  None
  557.  *
  558.  * Return Value:
  559.  *  PCPage          Pointer to the current page.
  560.  */
  561.  
  562. PCPage CPages::ActivePage(void)
  563.     {
  564.     PCPage      pPage;
  565.     BOOL        fRet;
  566.  
  567.     fRet=PageGet(m_iPageCur, &pPage, FALSE);
  568.     return fRet ? pPage : NULL;
  569.     }
  570.  
  571.  
  572.  
  573.  
  574.  
  575. /*
  576.  * CPages::PageInsert
  577.  *
  578.  * Purpose:
  579.  *  Creates a new page immediately after the current page.  If
  580.  *  there are no pages then this creates page 1.
  581.  *
  582.  * Parameters:
  583.  *  uReserved       UINT unused
  584.  *
  585.  * Return Value:
  586.  *  UINT            Index of the new page, 0 on failure.
  587.  */
  588.  
  589. UINT CPages::PageInsert(UINT uReserved)
  590.     {
  591.     if (0!=m_cPages && NULL!=m_pPageCur)
  592.         {
  593.         //Close the current page, committing changes.
  594.         m_pPageCur->Close(TRUE);
  595.         }
  596.  
  597.     //Create and open the new page.
  598.     if (!PageAdd(m_iPageCur, m_dwIDNext, TRUE))
  599.         return 0;
  600.  
  601.     m_dwIDNext++;
  602.     m_iPageCur++;
  603.     m_cPages++;
  604.  
  605.     InvalidateRect(m_hWnd, NULL, FALSE);
  606.     UpdateWindow(m_hWnd);
  607.  
  608.     PageGet(m_iPageCur, &m_pPageCur, FALSE);
  609.     return m_iPageCur;
  610.     }
  611.  
  612.  
  613.  
  614.  
  615.  
  616.  
  617.  
  618. /*
  619.  * CPages::PageDelete
  620.  *
  621.  * Removes the current page from the page list.
  622.  *
  623.  * Parameters:
  624.  *  uReserved       UINT unused
  625.  *
  626.  * Return Value:
  627.  *  UINT            Index to the now current page from the page
  628.  *                  list, NOVALUE on error.
  629.  */
  630.  
  631. UINT CPages::PageDelete(UINT uReserved)
  632.     {
  633.     PCPage      pPage;
  634.  
  635.     if (!PageGet(m_iPageCur, &pPage, FALSE))
  636.         return NOVALUE;
  637.  
  638.     //Delete the page in both the storage and in memory.
  639.     SendMessage(m_hWndPageList, LB_DELETESTRING, m_iPageCur, 0L);
  640.  
  641.     m_pPageCur->Destroy(m_pIStorage);
  642.  
  643.     delete m_pPageCur;   //Does final pPage->Close
  644.     m_pPageCur=NULL;
  645.  
  646.     /*
  647.      * If this is the last page then the current is one less.  If
  648.      * it's the only page the current is zero.  Otherwise the
  649.      * current is the next page.
  650.      */
  651.  
  652.     if (m_iPageCur==m_cPages-1)   //Covers last or only page.
  653.         m_iPageCur--;
  654.  
  655.     m_cPages--;
  656.  
  657.     //Insure the new visible page is open.
  658.     if (0!=m_cPages)
  659.         {
  660.         PageGet(m_iPageCur, &m_pPageCur, TRUE);
  661.         InvalidateRect(m_hWnd, NULL, FALSE);
  662.         }
  663.     else
  664.         InvalidateRect(m_hWnd, NULL, TRUE);
  665.  
  666.     UpdateWindow(m_hWnd);
  667.     return m_iPageCur;
  668.     }
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675. /*
  676.  * CPages::CurPageGet
  677.  *
  678.  * Purpose:
  679.  *  Retrieves the index of the current page we're viewing.
  680.  *
  681.  * Parameters:
  682.  *  None
  683.  *
  684.  * Return Value:
  685.  *  UINT            Index of the current page.
  686.  */
  687.  
  688. UINT CPages::CurPageGet(void)
  689.     {
  690.     return m_iPageCur;
  691.     }
  692.  
  693.  
  694.  
  695.  
  696.  
  697. /*
  698.  * CPages::CurPageSet
  699.  *
  700.  * Purpose:
  701.  *  Sets the index of the current page to view.
  702.  *
  703.  * Parameters:
  704.  *  iPage           UINT index of the page to view. 0 means first
  705.  *                  page, NOVALUE means last page.
  706.  *
  707.  * Return Value:
  708.  *  UINT            Index of the previous current page, NOVALUE on
  709.  *                  error.
  710.  */
  711.  
  712. UINT CPages::CurPageSet(UINT iPage)
  713.     {
  714.     UINT    iPageNew;
  715.     UINT    iPagePrev=m_iPageCur;
  716.     PCPage  pPage;
  717.  
  718.     switch (iPage)
  719.         {
  720.         case 0:
  721.             iPageNew=0;
  722.             break;
  723.  
  724.         case NOVALUE:
  725.             iPageNew=m_cPages-1;
  726.             break;
  727.  
  728.         default:
  729.             if (iPage >= m_cPages)
  730.                 iPage=0;
  731.  
  732.             iPageNew=iPage;
  733.             break;
  734.         }
  735.  
  736.     //No reason to switch to the same page.
  737.     if (iPagePrev==iPageNew)
  738.         return iPage;
  739.  
  740.     //Close the old page committing changes.
  741.     if (!PageGet(iPagePrev, &pPage, FALSE))
  742.         return NOVALUE;
  743.  
  744.     pPage->Close(TRUE);
  745.  
  746.     m_iPageCur=iPageNew;
  747.  
  748.     //Open the new page.
  749.     PageGet(m_iPageCur, &m_pPageCur, TRUE);
  750.  
  751.     InvalidateRect(m_hWnd, NULL, FALSE);
  752.     UpdateWindow(m_hWnd);
  753.     return iPagePrev;
  754.     }
  755.  
  756.  
  757.  
  758.  
  759.  
  760. /*
  761.  * CPages::NumPagesGet
  762.  *
  763.  * Purpose:
  764.  *  Returns the number of pages this object current contains.
  765.  *
  766.  * Parameters:
  767.  *  None
  768.  *
  769.  * Return Value:
  770.  *  UINT            Number of pages we contain.
  771.  */
  772.  
  773. UINT CPages::NumPagesGet(void)
  774.     {
  775.     return m_cPages;
  776.     }
  777.  
  778.  
  779.  
  780.  
  781.  
  782. /*
  783.  * CPages::TenantCreate
  784.  * CPages::TenantDestroy
  785.  *
  786.  * Purpose:
  787.  *  Pass-throughs for CPage members on the current page.
  788.  */
  789.  
  790. BOOL CPages::TenantCreate(TENANTTYPE tType, LPVOID pv
  791.     , LPFORMATETC pFE, PPATRONOBJECT ppo, DWORD dwData)
  792.     {
  793.     BOOL    fRet;
  794.  
  795.     if (NULL==m_pPageCur)
  796.         return FALSE;
  797.  
  798.     fRet=m_pPageCur->TenantCreate(tType, pv, pFE, ppo, dwData);
  799.     m_fDirty |= fRet;
  800.     return fRet;
  801.     }
  802.  
  803.  
  804. BOOL CPages::TenantDestroy(void)
  805.     {
  806.     BOOL    fRet;
  807.  
  808.     if (NULL==m_pPageCur)
  809.         return FALSE;
  810.  
  811.     fRet=m_pPageCur->TenantDestroy();
  812.     m_fDirty |= fRet;
  813.     return fRet;
  814.     }
  815.  
  816.  
  817.  
  818. /*
  819.  * CPages::TenantClip
  820.  *
  821.  * Purpose:
  822.  *  Copies or cuts the currently selected tenant to the clipoard.
  823.  *
  824.  * Parameters:
  825.  *  fCut            BOOL TRUE to cut the object, FALSE to copy.
  826.  *
  827.  * Return Value:
  828.  *  BOOL            TRUE if successful, FALSE otherwise.
  829.  */
  830.  
  831. BOOL CPages::TenantClip(BOOL fCut)
  832.     {
  833.     BOOL    fRet;
  834.  
  835.     if (NULL==m_pPageCur)
  836.         return FALSE;
  837.  
  838.     fRet=m_pPageCur->TenantClip(fCut);
  839.     m_fDirty |= (fRet && fCut);
  840.     return fRet;
  841.     }
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848. /*
  849.  * CPages::FQueryObjectSelected
  850.  *
  851.  * Purpose:
  852.  *  Returns whether or not there is an object selected on this
  853.  *  page for Cut, Copy, Delete functions.
  854.  *
  855.  * Parameters:
  856.  *  hMenu           HMENU on which object related items live.
  857.  *
  858.  * Return Value:
  859.  *  BOOL            TRUE if we have an object, FALSE otherwise.
  860.  */
  861.  
  862. BOOL CPages::FQueryObjectSelected(HMENU hMenu)
  863.     {
  864.     if (NULL==m_pPageCur)
  865.         return FALSE;
  866.  
  867.     return m_pPageCur->FQueryObjectSelected(hMenu);
  868.     }
  869.  
  870.  
  871.  
  872. //CHAPTER17MOD
  873. /*
  874.  * CPages::ActivateObject
  875.  *
  876.  * Purpose:
  877.  *  Executes a verb on the currently selected object.
  878.  *
  879.  * Parameters:
  880.  *  iVerb           LONG of the selected verb.
  881.  *
  882.  * Return Value:
  883.  *  None
  884.  */
  885.  
  886. void CPages::ActivateObject(LONG iVerb)
  887.     {
  888.     if (NULL==m_pPageCur)
  889.         return;
  890.  
  891.     m_pPageCur->ActivateObject(iVerb);
  892.     return;
  893.     }
  894.  
  895.  
  896. /*
  897.  * CPages::NotifyTenantsOfRename
  898.  *
  899.  * Purpose:
  900.  *  Pass-through to CPage to tell tenants that the document
  901.  *  changes names.
  902.  *
  903.  * Parameters:
  904.  *  pszFile         LPTSTR of the new filename.
  905.  *  pvReserved      LPVOID reserved for future use.
  906.  *
  907.  * Return Value:
  908.  *  None
  909.  */
  910.  
  911. void CPages::NotifyTenantsOfRename(LPTSTR pszFile, LPVOID pvReserved)
  912.     {
  913.     if (NULL==m_pPageCur)
  914.         return;
  915.  
  916.     m_pPageCur->NotifyTenantsOfRename(pszFile, pvReserved);
  917.     return;
  918.     }
  919.  
  920.  
  921. /*
  922.  * CPages::ConvertObject
  923.  *
  924.  * Purpose:
  925.  *  Pass-through to the current page.
  926.  *
  927.  * Parameters:
  928.  *  hWndFrame       HWND of the frame window.
  929.  *
  930.  * Return Value:
  931.  *  BOOL            TRUE if the function is successful, FALSE
  932.  *                  otherwise.
  933.  */
  934.  
  935. BOOL CPages::ConvertObject(HWND hWndFrame)
  936.     {
  937.     if (NULL==m_pPageCur)
  938.         return FALSE;
  939.  
  940.     return m_pPageCur->ConvertObject(hWndFrame, FALSE);
  941.     }
  942.  
  943. //End CHAPTER17MOD
  944.  
  945.  
  946.  
  947.  
  948. /*
  949.  * CPages::CalcBoundingRect
  950.  * (Protected)
  951.  *
  952.  * Purpose:
  953.  *  Calculates a rectangle that bounds the printed page and the
  954.  *  current scroll state of the window.
  955.  *
  956.  * Parameters:
  957.  *  prc             LPRECT to fill with window (device) coordinates.
  958.  *  fWindow         BOOL indicating to include the window in this
  959.  *                  calculation or return only the printed page
  960.  *                  coordinates.
  961.  *
  962.  * Return Value:
  963.  *  None
  964.  */
  965.  
  966. void CPages::CalcBoundingRect(LPRECT prc, BOOL fWindow)
  967.     {
  968.     RECT        rc, rcT;
  969.  
  970.     if (NULL==prc)
  971.         return;
  972.  
  973.     //Calculate the boundaries for sizing: intersect page & screen
  974.     rc.left=LOMETRIC_BORDER+m_xMarginLeft;
  975.     rc.top =-LOMETRIC_BORDER-m_yMarginTop;
  976.     rc.right =rc.left+(UINT)m_cx;
  977.     rc.bottom=rc.top -(UINT)m_cy;
  978.     RectConvertMappings(&rc, NULL, TRUE);
  979.     OffsetRect(&rc, -(int)m_xPos, -(int)m_yPos);
  980.  
  981.     if (!fWindow)
  982.         {
  983.         *prc=rc;
  984.         return;
  985.         }
  986.  
  987.     //Intersect with window to make the size bounds.
  988.     GetClientRect(m_hWnd, &rcT);
  989.     IntersectRect(prc, &rc, &rcT);
  990.     return;
  991.     }
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998. /*
  999.  * CPages::PageGet
  1000.  * (Protected)
  1001.  *
  1002.  * Purpose:
  1003.  *  Returns a page of a given index returning a BOOL so it's simple
  1004.  *  to use this function inside if statements.
  1005.  *
  1006.  * Parameters:
  1007.  *  iPage           UINT page to retrieve 0 based.
  1008.  *  ppPage          PCPage * in which to return the page pointer
  1009.  *  fOpen           BOOL indicating if we should open this page as
  1010.  *                  well.
  1011.  *
  1012.  * Return Value:
  1013.  *  BOOL            TRUE if successful, FALSE otherwise.
  1014.  */
  1015.  
  1016. BOOL CPages::PageGet(UINT iPage, PCPage *ppPage, BOOL fOpen)
  1017.     {
  1018.     if (NULL==ppPage)
  1019.         return FALSE;
  1020.  
  1021.     if (LB_ERR!=SendMessage(m_hWndPageList, LB_GETTEXT
  1022.         , iPage, (LONG)ppPage))
  1023.         {
  1024.         if (fOpen)
  1025.             (*ppPage)->Open(m_pIStorage);
  1026.  
  1027.         return TRUE;
  1028.         }
  1029.  
  1030.     return FALSE;
  1031.     }
  1032.  
  1033.  
  1034.  
  1035.  
  1036.  
  1037.  
  1038. /*
  1039.  * CPages::PageAdd
  1040.  * (Protected)
  1041.  *
  1042.  * Purpose:
  1043.  *  Creates a new page initialized to the given values.  The new
  1044.  *  page's storage is created if it does not already exist.  If
  1045.  *  fOpenStorage is set the page's storage is opened and left
  1046.  *  opened.
  1047.  *
  1048.  * Parameters:
  1049.  *  iPage           UINT Location at which to insert page; new page
  1050.  *                  is inserted after this position.  NOVALUE for
  1051.  *                  the end.
  1052.  *  dwID            DWORD ID for this page.
  1053.  *  fOpenStorage    BOOL indicating if we're to leave the storage
  1054.  *                  open.
  1055.  *
  1056.  * Return Value:
  1057.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  1058.  */
  1059.  
  1060. BOOL CPages::PageAdd(UINT iPage, DWORD dwID, BOOL fOpenStorage)
  1061.     {
  1062.     PCPage      pPage;
  1063.     LRESULT     lr;
  1064.  
  1065.     pPage=new CPage(dwID, m_hWnd, this);
  1066.  
  1067.     if (NULL==pPage)
  1068.         return FALSE;
  1069.  
  1070.     if (fOpenStorage)
  1071.         pPage->Open(m_pIStorage);
  1072.  
  1073.     if (NOVALUE==iPage)
  1074.         iPage--;
  1075.  
  1076.     //Now try to add to the listbox.
  1077.     lr=SendMessage(m_hWndPageList, LB_INSERTSTRING, iPage+1
  1078.         , (LONG)pPage);
  1079.  
  1080.     if (LB_ERRSPACE==lr)
  1081.         {
  1082.         if (fOpenStorage)
  1083.             pPage->Close(FALSE);
  1084.  
  1085.         delete pPage;
  1086.         return FALSE;
  1087.         }
  1088.  
  1089.     return TRUE;
  1090.     }
  1091.