/*
 * IDROPTGT.CPP
 * Cosmo Chapter 8
 *
 * Implementation of the IDropTarget interface.
 *
 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved
 *
 * Kraig Brockschmidt, Software Design Engineer
 * Microsoft Systems Developer Relations
 *
 * Internet  :  kraigb@microsoft.com
 * Compuserve:  >INTERNET:kraigb@microsoft.com
 */


#include "cosmo.h"



/*
 * CDropTarget::CDropTarget
 * CDropTarget::~CDropTarget
 *
 * Constructor Parameters:
 *  pDoc            PCCosmoDoc of the document containing us.
 */

CDropTarget::CDropTarget(PCCosmoDoc pDoc)
    {
    m_cRef=0;
    m_pDoc=pDoc;

    m_pIDataObject=NULL;
    return;
    }


CDropTarget::~CDropTarget(void)
    {
    return;
    }




/*
 * CDropTarget::QueryInterface
 * CDropTarget::AddRef
 * CDropTarget::Release
 *
 * Purpose:
 *  IUnknown members for CDropTarget object.
 */

STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, PPVOID ppv)
    {
    *ppv=NULL;

    if (IID_IUnknown==riid || IID_IDropTarget==riid)
        *ppv=this;

    if (NULL!=*ppv)
        {
        ((LPUNKNOWN)*ppv)->AddRef();
        return NOERROR;
        }

    return ResultFromScode(E_NOINTERFACE);
    }


STDMETHODIMP_(ULONG) CDropTarget::AddRef(void)
    {
    return ++m_cRef;
    }

STDMETHODIMP_(ULONG) CDropTarget::Release(void)
    {
    ULONG           cRefT;

    cRefT=--m_cRef;

    if (0L==m_cRef)
        delete this;

    return cRefT;
    }





/*
 * CDropTarget::DragEnter
 *
 * Purpose:
 *  Indicates that data in a drag operation has been dragged over
 *  our window that's a potential target.  We are to decide if it's
 *  something we're interested in or not.
 *
 * Parameters:
 *  pIDataSource    LPDATAOBJECT providing the source data.
 *  grfKeyState     DWORD flags: states of keys and mouse buttons.
 *  pt              POINTL coordinates in the document client space.
 *  pdwEffect       LPDWORD into which we'll place the
 *                  appropriate effect flag for this point.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP CDropTarget::DragEnter(LPDATAOBJECT pIDataSource
    , DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
    {
    HWND        hWnd;

    /*
     * 1.  Check if we can paste from the pIDataSource we're
     *     provided. We already made this nice useful function
     *     to test.
     */

    m_pIDataObject=NULL;

    if (!m_pDoc->FQueryPasteFromData(pIDataSource))
        {
        *pdwEffect=DROPEFFECT_NONE;
        return NOERROR;
        }


    /*
     * 2.  We can always drop anywhere in our document,
     *     so pt is uninteresting.
     */


    /*
     * 3. We return either a COPY or MOVE effect flag, depending on
     *    the state of the grfKeyState flags.  We MOVE on no key or
     *    Shift key, COPY on Ctrl key.
     */

    //Default is move
    *pdwEffect=DROPEFFECT_MOVE;

    if (grfKeyState & MK_CONTROL)
        *pdwEffect=DROPEFFECT_COPY;

    /*
     * 4. We really don't need to keep the IDataObject around since
     *    we're not interested in it in DragOver.  However, we'll
     *    save it just for demonstration.
     */
    m_pIDataObject=pIDataSource;
    m_pIDataObject->AddRef();

    /*
     * 5.  We always accept drops of our data on us, so we only need
     *     to provide some UI feedback here which we do by inverting
     *     the edge of the polyline window in this document.  We'll
     *     remove this in DragLeave and in Drop.  DragOver won't
     *     effect it since we can always drop.
     *
     *     Since we're inverting a border, insure that this window is
     *     on top.
     */

    hWnd=m_pDoc->Window();
    BringWindowToTop(hWnd);
    UpdateWindow(hWnd);
    m_pDoc->DropSelectTargetWindow();

    return NOERROR;
    }






/*
 * CDropTarget::DragOver
 *
 * Purpose:
 *  Indicates that the mouse was moved inside the window represented
 *  by this drop target. This happens on every WM_MOUSEMOVE, so this
 *  function should be very efficient.
 *
 * Parameters:
 *  grfKeyState     DWORD providing current keyboard/mouse states
 *  pt              POINTL where the mouse currently is.
 *  pdwEffect       LPDWORD to store the effect flag for this point.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP CDropTarget::DragOver(DWORD grfKeyState, POINTL pt
    , LPDWORD pdwEffect)
    {
    if (NULL==m_pIDataObject)
        {
        *pdwEffect=DROPEFFECT_NONE;
        return NOERROR;
        }

    //We can always drop; return effect flags based on keys.
    *pdwEffect=DROPEFFECT_MOVE;

    if (grfKeyState & MK_CONTROL)
        *pdwEffect=DROPEFFECT_COPY;

    return NOERROR;
    }






/*
 * CDropTarget::DragLeave
 *
 * Purpose:
 *  Informs the drop target that the operation has left its window.
 *
 * Parameters:
 *  None
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP CDropTarget::DragLeave(void)
    {
    if (NULL==m_pIDataObject)
        return NOERROR;

    //1.  We don't scroll, so we don't worry about timers.

    //2.  Remove the UI feedback
    m_pDoc->DropSelectTargetWindow();

    //3.  Release the held IDataObject
    m_pIDataObject->Release();

    return NOERROR;
    }





/*
 * CDropTarget::Drop
 *
 * Purpose:
 *  Instructs the drop target to paste data that was just now
 *  dropped on it.
 *
 * Parameters:
 *  pIDataSource    LPDATAOBJECT from which we'll paste.
 *  grfKeyState     DWORD providing current keyboard/mouse state.
 *  pt              POINTL at which the drop occurred.
 *  pdwEffect       LPDWORD to store what you do with the data.
 *
 * Return Value:
 *  HRESULT         NOERROR
 */

STDMETHODIMP CDropTarget::Drop(LPDATAOBJECT pIDataSource
    , DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
    {
    BOOL        fRet=TRUE;

    *pdwEffect=DROPEFFECT_NONE;

    if (NULL==m_pIDataObject)
        return ResultFromScode(E_FAIL);

    //1.  We don't scroll, so we don't worry about timers.

    //2.  Remove the UI feedback
    m_pDoc->DropSelectTargetWindow();

    //3.  Release the held IDataObject from DragEnter
    m_pIDataObject->Release();


    //No point in drag-drop to ourselves (for Cosmo, at least)
    if (m_pDoc->m_fDragSource)
        return ResultFromScode(E_FAIL);

    //4, 5.  We can always drop, so we do the paste.
    fRet=m_pDoc->FPasteFromData(pIDataSource);

    //6.  Store what we're doing in pdwEffect.
    if (!fRet)
        return ResultFromScode(E_FAIL);

    *pdwEffect=DROPEFFECT_MOVE;

    if (grfKeyState & MK_CONTROL)
        *pdwEffect=DROPEFFECT_COPY;

    return NOERROR;
    }
