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

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