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 / chap21 / patron / pages.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-04  |  26.2 KB  |  1,277 lines

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