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

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