⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dragdrp.cpp

📁 Windows CE 6.0 Word Application 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
 *	DRAGDRP.C
 *
 *	Purpose:
 *		Implementation of Richedit's OLE drag drop objects (namely,
 *		the drop target and drop source objects)
 *
 *	Author:
 *		alexgo (4/24/95)
 */

#include "_common.h"
#include "_edit.h"
#include "_dragdrp.h"
#include "_disp.h"
#include "_select.h"
#include "_font.h"


ASSERTDATA

//
//	CDropSource PUBLIC methods
//

/*
 *	CDropSource::QueryInterface (riid, ppv)
 */

STDMETHODIMP CDropSource::QueryInterface(REFIID riid, void ** ppv)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropSource::QueryInterface");

	if( IsEqualIID(riid, IID_IUnknown) )
	{
		*ppv = (IUnknown *)this;
	}
	else if( IsEqualIID(riid, IID_IDropSource) )
	{
		*ppv = (IDropSource *)this;
	}
	else
	{
		*ppv = NULL;
		return E_NOINTERFACE;
	}

	AddRef();
	return NOERROR;
}

/*
 *	CDropSource::AddRef
 */
STDMETHODIMP_(ULONG) CDropSource::AddRef()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropSource::AddRef");

	return ++_crefs;
}

/*
 *	CDropSource::Release
 *
 *	@devnote.  Do not even think about making an outgoing call here.
 *			   If you do, be sure make sure all callers use a 
 *			   SafeReleaseAndNULL (null the pointer before releasing)
 *			   technique to avoid re-entrancy problems.
 */
STDMETHODIMP_(ULONG) CDropSource::Release()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropSource::Release");

	_crefs--;

	if( _crefs == 0 )
	{
		delete this;
		return 0;
	}

	return _crefs;
}

/*
 *	CDropSource::QueryContinueDrag (fEscapePressed, grfKeyState)
 *
 *	Purpose:
 *		determines whether or not to continue a drag drop operation
 *
 *	Algorithm:
 *		if the escape key has been pressed, cancel 
 *		if the left mouse button has been release, then attempt to 
 *			do a drop
 */
STDMETHODIMP CDropSource::QueryContinueDrag(BOOL fEscapePressed, 
	DWORD grfKeyState)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropSource::QueryContinueDrag");

    if (fEscapePressed)
	{
        return DRAGDROP_S_CANCEL;
	}
    else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
	{
        return DRAGDROP_S_DROP;
	}
    else
	{
        return NOERROR;
	}
}

/*
 *	CDropSource::GiveFeedback (dwEffect)
 *
 *	Purpose:
 *		gives feedback during a drag drop operation
 *
 *	Notes:
 *		FUTURE (alexgo): maybe put in some neater feedback effects
 *		than the standard OLE stuff??
 */
STDMETHODIMP CDropSource::GiveFeedback(DWORD dwEffect)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropSource::GiveFeedback");

	return DRAGDROP_S_USEDEFAULTCURSORS;
}

/*
 *	CDropSource::CDropSource
 */
CDropSource::CDropSource()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropSource::CDropSource");

	_crefs = 1;
}

//
//	CDropSource PRIVATE methods
//

/*
 *	CDropSource::~CDropSource
 */
CDropSource::~CDropSource()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropSource::~CDropSource");

	;
}


//
//	CDropTarget PUBLIC methods
//

/*
 *	CDropTarget::QueryInterface (riid, ppv)
 */
STDMETHODIMP CDropTarget::QueryInterface (REFIID riid, void ** ppv)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::QueryInterface");

	if( IsEqualIID(riid, IID_IUnknown) )
	{
		*ppv = (IUnknown *)this;
	}
	else if( IsEqualIID(riid, IID_IDropTarget) )
	{
		*ppv = (IDropTarget *)this;
	}
	else
	{
		*ppv = NULL;
		return E_NOINTERFACE;
	}

	AddRef();

	return NOERROR;
}

/*
 *	CDropTarget::AddRef
 */
STDMETHODIMP_(ULONG) CDropTarget::AddRef()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::AddRef");

	return ++_crefs;
}

/*
 *	CDropTarget::Release()
 */
STDMETHODIMP_(ULONG) CDropTarget::Release()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::Release");

	_crefs--;

	if( _crefs == 0 )
	{
		delete this;
		return 0;
	}

	return _crefs;
}

/*
 *	CDropTarget::DragEnter (pdo, grfKeyState, pt, pdwEffect)
 *
 *	Purpose: 
 *		called when OLE drag drop enters our "window"
 *
 *	Algorithm:
 *		first we check to see if the data object being transferred contains
 *		any data that we support.  Then we verify that the 'type' of drag
 *		is acceptable (i.e., currently, we do not accept links).
 *
 *
 *	FUTURE: (alexgo): we may want to accept links as well.
 */
STDMETHODIMP CDropTarget::DragEnter(IDataObject *pdo, DWORD grfKeyState,
            POINTL pt, DWORD *pdwEffect)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::DragEnter");

	// We don't have a position yet.
	_cpCur = -1;

	HRESULT hr;
	DWORD result;
	CTxtSelection *psel;

	// At drag enter time, we should have no cached info about what the data
	// object supports.  This flag should be cleared in DragLeave.  Note
	// that we slightly override _dwFlags, as it's possible for a data object
	// given during drag drop to also generate DOI_NONE.

	if( !_ped )
	{
		return CO_E_RELEASED;
	}
	 
	Assert(_pcallmgr == NULL);
	Assert(_dwFlags == 0);

	_pcallmgr = new CCallMgr(_ped);

	if( !_pcallmgr )
	{
		return E_OUTOFMEMORY;
	}

	// Find out if we can paste the object

	result = _ped->GetDTE()->CanPaste(pdo, 0, RECO_DROP);

	if( result )
	{
		if( result == DF_CLIENTCONTROL )
		{
			_dwFlags |= DF_CLIENTCONTROL;
		}

		// Create the object that implements the drag caret
		_pdrgcrt = new CDropCaret(_ped);

		if ((NULL == _pdrgcrt) || !_pdrgcrt->Init())
		{
			// Initialization failed so go without a caret
			delete _pdrgcrt;
			_pdrgcrt = NULL;
		}
				
		// cache the current selection so we can restore it on return
		psel = _ped->GetSel();

		if (NULL == psel)
		{
		    Assert(psel);
		    hr = E_OUTOFMEMORY;
		}    
        else
        {
    		_cpSel	= psel->GetCp();
    		_cchSel	= psel->GetCch();
    		_dwFlags |= DF_CANDROP;

    		// just call DragOver to handle our visual feedback
	    	hr = DragOver(grfKeyState, pt, pdwEffect);
    	}
    	
	}
	else
	{
		// this is new behaviour for Win95 OLE; if we don't 
		// understand anything about the data object given to us,
		// we return S_FALSE to allow our parent to give the
		// drag drop a try.
		
		hr = S_FALSE;
	}

	if( hr != NOERROR )
	{
		delete _pcallmgr;
		_pcallmgr = NULL;
		_dwFlags = 0;
	}

	return hr;
}

/*
 *	CDropTarget::DragOver (grfKeyState, pt, pdwEffect)
 *
 *	Purpose:
 *		handles the visual feedback for a drag drop operation zooming
 *		around over text
 *
 *	FUTURE (alexgo): maybe we should do some snazzy visuals here
 */
STDMETHODIMP CDropTarget::DragOver(DWORD grfKeyState, POINTL pt, 
		DWORD *pdwEffect)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::DragOver");

	LONG	cpCur = _cpCur;

	if( !_ped )
	{
		return CO_E_RELEASED;
	}
	Assert(_pcallmgr);

	// note if we're doing right mouse drag drop; note that we 
	// can't do this in UpdateEffect as it's called from Drop
	// as well (and the mouse button is up then!)
	if( (grfKeyState & MK_RBUTTON) )
	{
		_dwFlags |= DF_RIGHTMOUSEDRAG;
	}
	else
	{
		_dwFlags &= ~DF_RIGHTMOUSEDRAG;
	}

	UpdateEffect(grfKeyState, pt, pdwEffect);

	// only draw if we've changed position	
	if( *pdwEffect != DROPEFFECT_NONE 
		&& ((cpCur != _cpCur) 
			|| (_pdrgcrt && _pdrgcrt->NoCaret())))
	{
		DrawFeedback();
	}	

	return NOERROR;
}

/*
 *	CDropTarget::DragLeave
 *
 *	Purpose:
 *		called when the mouse leaves our window during drag drop.  Here we clean
 *		up any temporary state setup for the drag operation.
 */
STDMETHODIMP CDropTarget::DragLeave()
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::DragLeave");

	CTxtSelection *psel = _ped->GetSel();
	if (NULL == psel)
	{
	    Assert(psel);
	    return E_OUTOFMEMORY;
    }
    

	if( !_ped )
	{
		return CO_E_RELEASED;
	}
	Assert(_pcallmgr);

	_dwFlags = 0;

	// now restore the selection

	psel->SetSelection(_cpSel - _cchSel, _cpSel);
	psel->Update(FALSE);

	_cpSel = _cchSel = 0;

	delete _pcallmgr;
	_pcallmgr = NULL;

	delete _pdrgcrt;
	_pdrgcrt = NULL;

	return NOERROR;
}

/*
 *	CDropTarget::Drop (pdo, grfKeyState, pt, pdwEffect)
 *
 *	Purpose:
 *		called when the mouse button is released.  We should attempt
 *		to 'paste' the data object into a selection corresponding to
 *		the mouse location
 *
 *	Algorithm:
 *		first, we make sure that we can still do a paste (via UpdateEffect).
 *		If so, then set the selection to the current point and then insert
 *		the text.
 *
 */
STDMETHODIMP CDropTarget::Drop(IDataObject *pdo, DWORD grfKeyState, 
		POINTL ptl, DWORD *pdwEffect)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::Drop");

	LONG			cchNext;
	LONG			cpNext;
	HRESULT			hr = NOERROR;
	CTxtSelection * psel;

	if( !_ped )
	{
		return CO_E_RELEASED;
	}

	Assert(_pcallmgr);
	CDropCleanup cleanup(this);
	CGenUndoBuilder undobldr( _ped, UB_AUTOCOMMIT);

	// see if we can still drop
	UpdateEffect(grfKeyState, ptl, pdwEffect);

	// UpdateEffect will show a drop cursor but at this point we don't need one
	// so we hide the drop cursor here.
	if (_pdrgcrt)
	{
		_pdrgcrt->HideCaret();
	}

	if (_dwFlags & DF_OVERSOURCE)
	{
		*pdwEffect = DROPEFFECT_NONE;
		_dwFlags = 0;
		return hr;
	}
	
	if( (*pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK)) )
	{
		IUndoBuilder *publdr;

		// if this is a right mouse drag drop; handle that
		if( (_dwFlags & DF_RIGHTMOUSEDRAG) )
		{
			hr = HandleRightMouseDrop(pdo, ptl);

			// if S_FALSE is returned; treat the drag drop normally.
			if( hr != S_FALSE )
			{
				goto Exit;
			}
		}

		// get an undo builder.  If we already have one cached, that means
		// we are dropping onto the same edit instance that started the drag
		// In this case, we want to use the cached undo builder so that 
		// a drag move can be undone as one "operation".

		if( _publdr == NULL )
		{
			publdr = &undobldr;
		}
		else
		{
			publdr = _publdr;
		}
		psel = _ped->GetSel();
		if (NULL == psel)
		{
		    Assert(psel);
		    hr = E_OUTOFMEMORY;
		    goto Exit;
	    }
	    
		psel->SetSelection(_cpCur, _cpCur);
		
		if( !_ped->IsProtectedRange(WM_PASTE, 0, 0, psel) )
		{
			hr = _ped->PasteDataObjectToRange(pdo, (CTxtRange *)psel, 
					0, NULL, publdr, PDOR_DROP);
		}


		// if we are dropping onto ourselves, the UI specifies
		// that we should select the entire range dragged.  We use
		// _publdr as an easy way to tell if the drop originated from
		// this instance

		if (SUCCEEDED(hr) && (_pdrgcrt != NULL))
		{
			// If the drop worked, then we don't want to restore the area
			// where the drop caret used to be since this is not out of date.
			_pdrgcrt->CancelRestoreCaretArea();
		}		

		// Now set the selection anti-events. If the selection preceded the
		// paste poiont subtract its length from the redo position, since
		// the selection will get deleted if we are doing a DRAGMOVE within
		// this instance.
		cpNext  = psel->GetCp();
		cchNext = cpNext - _cpCur;
		if( (_cpSel < _cpCur) && _publdr && (*pdwEffect & DROPEFFECT_MOVE))
			cpNext -= abs(_cchSel);

		HandleSelectionAEInfo(_ped, publdr, _cpCur, 0, cpNext, cchNext,
							  SELAE_FORCEREPLACE);
		if( _publdr )
		{
			// if we are doing a drag move, then *don't* set the
			// selection directly on the screen--doing so will result in
			// unsightly UI--we'llset the selection to one spot, draw it
			// and then immediately move the selection somewhere else

			// in this case, just change where the selection range exists.
			// Floating ranges and the drag-move code in ldte.c will take
			// care of the rest.

			if( *pdwEffect == DROPEFFECT_COPY )
			{
				psel->SetSelection(_cpCur, psel->GetCp());
			}
			else
			{
				psel->Set(psel->GetCp(), cchNext);
			}
		}
		else
		{
			// the drop call landed in us from outside, so we need
			// to fire the appropriate notifications.  First, however,
			// commit the undo builder.

			publdr->SetNameID(UID_DRAGDROP);
			publdr->Done();

			if (SUCCEEDED(hr))
			{
				// Make this window the foreground window after the drop. Note
				// that the host needs to support ITextHost2 to really get to
				// be the foreground window. If they don't this is a no-op.
				_ped->TxSetForegroundWindow();
			}
		}

		// If nothing changed on the drop && the effect is a move, then return
		// failure. This is an ugly hack to improve drag-move scenarios; if
		// nothing happened on the drop, then chances are, you don't want
		// to have the correspong "Cut" happen on the drag source side.
		//
		// Of course, this relies on the drag source responding gracefully to
		// E_FAIL w/o hitting too much trauma.
		if( *pdwEffect == DROPEFFECT_MOVE && 
				!_ped->GetCallMgr()->GetChangeEvent() )
		{
			hr = E_FAIL;
		}
	}


Exit:

	_dwFlags = 0;

	return hr;
}

/*
 *	CDropTarget::CDropTarget (ped)
 *
 */
CDropTarget::CDropTarget(CTxtEdit *ped)
{
	TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDropTarget::CDropTarget");

	_ped 		= ped;
	_crefs 		= 1;
	_dwFlags 	= 0;
	_publdr 	= NULL;
	_cpMin		= -1;
	_cpMost		= -1;
	_pcallmgr	= NULL;
}


/*
 *	CDropTarget::SetDragInfo (publdr, cpMin, cpMost)
 *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -