//**********************************************************************
// File name: DOC.CPP
//
//      Implementation file for CSimpleDoc.
//
// Functions:
//
//      See DOC.H for Class Definition
//
// Copyright (c) 1992-1995 Microsoft Corporation. All rights reserved.
//**********************************************************************

#include "precomp.h"
#include <oledlg.h>     // for OleUIInsertObject and OleUIAddVerbMenu
#include "app.h"            
#include "site.h"
#include "doc.h"

//**********************************************************************
//
// CSimpleDoc::Create
// 
// Purpose:
//                       
//      Creation for the CSimpleDoc Class
//  
// Parameters:
//                                                                     
//      CSimpleApp *lpApp       -   Pointer to the CSimpleApp Class
//
//      LPRECT lpRect           -   Client area rect of "frame" window
//
//      HWND hWnd               -   Window Handle of "frame" window
// 
// Return Value:
//
//      None
//       
// Function Calls:
//      Function                    Location
//                  
//      StgCreateDocfile            OLE API
//      CreateWindow                Windows API
//      ShowWindow                  Windows API
//      UpdateWindow                Windows API
//
// Comments:
//               
//      This routine was added so that failure could be returned
//      from object creation.
//
//********************************************************************

CSimpleDoc* CSimpleDoc::Create(CSimpleApp *lpApp, LPRECT lpRect,HWND hWnd)
{   
    CSimpleDoc *lpTemp = new CSimpleDoc(lpApp, hWnd);
    
    if (!lpTemp)
        return NULL;
    
    // create storage for the doc.
    HRESULT hErr = StgCreateDocfile(NULL,
                                    STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,
                                    0,
                                    &lpTemp->m_lpStorage);
                                     
    if (hErr != NOERROR)
        goto error;
    
    // create the document Window                                
    lpTemp->m_hDocWnd = CreateWindow(TEXT("SimpCntrDocWClass"),
                                     NULL,
                                     WS_CHILD | WS_CLIPCHILDREN,
                                     lpRect->left,                 
                                     lpRect->top,                  
                                     lpRect->right,                
                                     lpRect->bottom,               
                                     hWnd,    
                                     NULL,                      
                                     lpApp->m_hInst,                     
                                     NULL); 
            
    if (!lpTemp->m_hDocWnd)
        goto error; 
        
    ShowWindow(lpTemp->m_hDocWnd, SW_SHOWNORMAL);  // Show the window
    UpdateWindow(lpTemp->m_hDocWnd);               // Sends WM_PAINT message

    // Ensable InsertObject menu choice
    EnableMenuItem(lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_ENABLED);

    // we will add one ref count on our document. later in CSimpleDoc::Close 
    // we will release this  ref count. when the document's ref count goes
    // to 0, the document will be deleted.
    lpTemp->AddRef();

    return lpTemp;

error:
    delete lpTemp;
    return NULL;
}                             

//**********************************************************************
//
// CSimpleDoc::Close
// 
// Purpose:
//                       
//      Close CSimpleDoc object.
//      when the document's reference count goes to 0, the document 
//      will be destroyed.
//  
// Parameters:
//                                                                     
// 
// Return Value:
//
//      None
//       
// Function Calls:
//      Function                    Location
//                  
//      RevokeDragDrop              OLE API
//      CoLockObjectExternal        OLE API
//      OleFlushClipboard           OLE API
//      ShowWindow                  Windows API
//
// Comments:
//               
//********************************************************************

void CSimpleDoc::Close(void)
{   
    OutputDebugString(TEXT("In CSimpleDoc::Close\r\n"));

    ShowWindow(m_hDocWnd, SW_HIDE);  // Hide the window

    // Close the OLE object in our document
    if (m_lpSite)
        m_lpSite->CloseOleObject();

    // Release the ref count added in CSimpleDoc::Create. this will make
    // the document's ref count go to 0, and the document will be deleted.
    Release();
}                             

//**********************************************************************
//
// CSimpleDoc::CSimpleDoc
// 
// Purpose:
//                       
//      Constructor for the CSimpleDoc Class
//  
// Parameters:
//                                                                     
//      CSimpleApp *lpApp       -   Pointer to the CSimpleApp Class
//
//      HWND hWnd               -   Window Handle of "frame" window
// 
// Return Value:
//
//      None
//       
// Function Calls:
//      Function                    Location
//                  
//      OutputDebugString           Windows API
//      GetMenu                     Windows API
//      GetSubMenu                  Windows API
//
// Comments:
//
//********************************************************************
    
CSimpleDoc::CSimpleDoc(CSimpleApp *lpApp, HWND hWnd)
{   
    OutputDebugString(TEXT("In CSimpleDoc's Constructor\r\n")); 

    m_lpApp = lpApp;
    m_lpSite = NULL;
    m_lpStorage = NULL;
    m_nCount = 0;                                                                      

    // set up menu handles
    m_lpApp->m_hMainMenu = GetMenu(hWnd);
    m_lpApp->m_hFileMenu = GetSubMenu(m_lpApp->m_hMainMenu, 0);
    m_lpApp->m_hEditMenu = GetSubMenu(m_lpApp->m_hMainMenu, 1);
    m_lpApp->m_hHelpMenu = GetSubMenu(m_lpApp->m_hMainMenu, 2);
    m_lpApp->m_hCascadeMenu = NULL;           
    
    m_lpActiveObject = NULL;
    
    // flags
    m_fInPlaceActive = FALSE;
    m_fAddMyUI = FALSE;                   
    m_fModifiedMenu = FALSE;
}                                          

//**********************************************************************
//
// CSimpleDoc::~CSimpleDoc
// 
// Purpose:
//                        
//      Destructor for CSimpleDoc
//  
// Parameters:                   
//      
//      None
// 
// Return Value:
//          
//      None
//
// Function Calls:
//      Function                    Location
//
//      OutputDebugString           Windows API
//      CSimpleSite::Release        SITE.CPP
//      IStorage::Release           OLE API
//
// Comments:
//
//********************************************************************

CSimpleDoc::~CSimpleDoc()
{      
    OutputDebugString(TEXT("In CSimpleDoc's Destructor\r\n"));

    // Release all pointers we hold to the OLE object. also release
    // the ref count added in CSimpleSite::Create. this will make
    // the Site's ref count go to 0, and the Site will be deleted.
    if (m_lpSite)
    {
        m_lpSite->UnloadOleObject();
        m_lpSite->Release();
        m_lpSite = NULL;
    }
        
    // Release the Storage  
    if (m_lpStorage)
    {
        m_lpStorage->Release();
        m_lpStorage = NULL;
    }
    
    // if the edit menu was modified, remove the menu item and
    // destroy the popup if it exists    
    if (m_fModifiedMenu)
    {
        int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);
        RemoveMenu(m_lpApp->m_hEditMenu, nCount-1, MF_BYPOSITION);
        if (m_lpApp->m_hCascadeMenu)
            DestroyMenu(m_lpApp->m_hCascadeMenu);
    }

    DestroyWindow(m_hDocWnd);                                                
}                     


//**********************************************************************
//
// CSimpleDoc::QueryInterface
// 
// Purpose:
//                                 
//      Return a pointer to a requested interface
//  
// Parameters:
//                           
//      REFIID riid         -   ID of interface to be returned
//      LPVOID* ppvObj      -   Location to return the interface
// 
// Return Value:
//                                                              
//      S_FALSE -   Always
//
// Function Calls:
//      Function                    Location
//
//      OutputDebugString           Windows API
//
// Comments:
//
//      In this implementation, there are no doc level interfaces.
//      In an MDI application, there would be an IOleInPlaceUIWindow 
//      associated with the document to provide document level tool
 //     space negotiation.
//
//********************************************************************

STDMETHODIMP CSimpleDoc::QueryInterface(REFIID riid, LPVOID* ppvObj)
{
    OutputDebugString(TEXT("In CSimpleDoc::QueryInterface\r\n"));

    *ppvObj = NULL;     // must set out pointer parameters to NULL

    // Not a supported interface
    return E_NOINTERFACE;
}
    
//**********************************************************************
//
// CSimpleDoc::AddRef
// 
// Purpose:
//                   
//      Increments the document reference count
//  
// Parameters:                                       
//
//      None 
// 
// Return Value:
//          
//      UINT    -   The current reference count on the document
//
// Function Calls:
//      Function                    Location
//
//      OutputDebugString           Windows API 
//      CSimpleApp::AddRef          APP.CPP
//
// Comments:
//
//********************************************************************

STDMETHODIMP_(ULONG) CSimpleDoc::AddRef()
{
    OutputDebugString(TEXT("In CSimpleDoc::AddRef\r\n"));

    return ++m_nCount;
}

//**********************************************************************
//
// CSimpleDoc::Release
// 
// Purpose:
//                   
//      Decrements the document reference count
//  
// Parameters:                                       
//
//      None 
// 
// Return Value:
//          
//      UINT    -   The current reference count on the document
//
// Function Calls:
//      Function                    Location
//
//      OutputDebugString           Windows API 
//
// Comments:
//
//********************************************************************

STDMETHODIMP_(ULONG) CSimpleDoc::Release()
{
    OutputDebugString(TEXT("In CSimpleDoc::Release\r\n"));

    if (--m_nCount == 0)
    {
        delete this;
        return 0;
    }
    return m_nCount;
}

//**********************************************************************
//
// CSimpleDoc::InsertObject
// 
// Purpose:
//                         
//      Inserts a new object to this document
//  
// Parameters:
//                                           
//      None
// 
// Return Value:
//
//      None
//       
// Function Calls:
//      Function                    Location
//          
//      CSimpleSite::CSimpleSite    SITE.CPP
//      CSimpleSite::InitObject     SITE.CPP
//      memset                      C Runtime
//      OleUIInsertObject           OLE2UI function
//      CSimpleDoc::DisableInsertObject DOC.CPP
//
// Comments:
//                                        
//      This implementation only allows one object to be inserted
//      into a document.  Once the object has been inserted, then
//      the Insert Object menu choice is greyed out, to prevent
//      the user from inserting another.
//
//********************************************************************

void CSimpleDoc::InsertObject() 
{
    OLEUIINSERTOBJECT io;
    UINT iret;    
    TCHAR szFile[MAX_PATH];

    assert(m_lpSite == NULL);

    m_lpSite = CSimpleSite::Create(this);

    // clear the structure
    _fmemset(&io, 0, sizeof(OLEUIINSERTOBJECT));
    szFile[0] = 0;
    
    // fill the structure
    io.cbStruct         = sizeof(OLEUIINSERTOBJECT);
    io.dwFlags          = IOF_SELECTCREATENEW | 
                            IOF_DISABLELINK | IOF_DISABLEDISPLAYASICON |
                            IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT;
    io.hWndOwner        = m_hDocWnd;
    io.lpszFile         = szFile;
    io.cchFile          = MAX_PATH;
    io.iid              = IID_IOleObject;
    io.oleRender        = OLERENDER_DRAW;
    io.lpIStorage       = m_lpSite->m_lpObjStorage;
    io.ppvObj           = (LPVOID*)&m_lpSite->m_lpOleObject;
    m_lpSite->QueryInterface(IID_IOleClientSite, (LPVOID*)&io.lpIOleClientSite);

    // let the system do all the hard work                     
    iret = OleUIInsertObject(&io);      

    io.lpIOleClientSite->Release(); // done with this now

    if (iret == OLEUI_OK)      
    {
        m_lpSite->InitObject((BOOL)(io.dwFlags & IOF_SELECTCREATENEW));

        // disable Insert Object menu item
        DisableInsertObject(); 
    }  
    else
    {
        m_lpSite->Release();
        m_lpSite = NULL;
        m_lpStorage->Revert();
    }
}

//**********************************************************************
//
// CSimpleDoc::lResizeDoc
// 
// Purpose:
//                       
//      Resizes the document
//  
// Parameters:
//                          
//      LPRECT lpRect   -   The size of the client are of the "frame"
//                          Window.
// 
// Return Value:
//                                 
//      NULL
//
// Function Calls:
//      Function                                Location
//                                    
//      IOleInPlaceActiveObject::ResizeBorder   Object
//      MoveWindow                              Windows API
//
// Comments:
//
//********************************************************************

long CSimpleDoc::lResizeDoc(LPRECT lpRect)
{ 
    // if we are InPlace, then call ResizeBorder on the object, otherwise
    // just move the document window. 
    if (m_fInPlaceActive)
        m_lpActiveObject->ResizeBorder(lpRect, (LPOLEINPLACEUIWINDOW)m_lpApp, TRUE);
    else
        MoveWindow(m_hDocWnd, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, TRUE);
 
    return NULL;
}                    

//**********************************************************************
//
// CSimpleDoc::lAddVerbs
// 
// Purpose:
//                      
//      Adds the objects verbs to the edit menu.
//  
// Parameters:
//                                              
//      None
// 
// Return Value:
//
//      NULL
//       
// Function Calls:
//      Function                    Location
//                                   
//      GetMenuItemCount            Windows API
//      OleUIAddVerbMenu            OLE2UI function
//
// Comments:
//
//********************************************************************

long CSimpleDoc::lAddVerbs(void)
{                                                    
    // m_fModifiedMenu is TRUE if the menu has already been modified
    // once.  Since we only support one obect every time the application
    // is run, then once the menu is modified, it doesn't have
    // to be done again.   
    if (m_lpSite && !m_fInPlaceActive  && !m_fModifiedMenu)
    {                                
        int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);

        OleUIAddVerbMenu(m_lpSite->m_lpOleObject,
                         NULL,
                         m_lpApp->m_hEditMenu,
                         nCount + 1,
                         IDM_VERB0,
                         0,           // no maximum verb IDM enforced
                         FALSE,
                         0,
                         &m_lpApp->m_hCascadeMenu);

        m_fModifiedMenu = TRUE;
    }              
    return 0L;
}

//**********************************************************************
//
// CSimpleDoc::PaintDoc
// 
// Purpose:
//                     
//      Paints the Document
//  
// Parameters:
//                         
//      HDC hDC -   hDC of the document Window
// 
// Return Value:                              
//
//      None
//       
// Function Calls:
//      Function                    Location
//          
//      CSimpleSite::PaintObj       SITE.CPP
//
// Comments:
//
//********************************************************************
              
void CSimpleDoc::PaintDoc (HDC hDC)
{
    // if we supported multiple objects, then we would enumerate
    // the objects and call paint on each of them from here.
    
    if (m_lpSite)
        m_lpSite->PaintObj(hDC);
}

//**********************************************************************
//
// CSimpleDoc::DisableInsertObject
// 
// Purpose:
//                         
//      Disable the ability to insert a new object in this document.
//  
// Parameters:
//                                           
//      None
// 
// Return Value:
//
//      None
//       
// Function Calls:
//      Function                    Location
//          
//      EnableMenuItem              Windows API
//
// Comments:
//                                        
//      This implementation only allows one object to be inserted
//      into a document.  Once the object has been inserted, then
//      the Insert Object menu choice is greyed out, to prevent
//      the user from inserting another. 
//
//********************************************************************

void CSimpleDoc::DisableInsertObject(void) 
{
    // Disable InsertObject menu choice
    EnableMenuItem(m_lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
}
