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 / chap12 / patron / pages.cpp < prev    next >
C/C++ Source or Header  |  1995-05-04  |  22KB  |  1,029 lines

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