Milán Major

netscape-revival

1 branch
Code

lib/mac/VText/V_PowerPlant_Mods/LDataDragTask.cp

//	===========================================================================
//	LDataDragTask.cp				©1994 Metrowerks Inc. All rights reserved.
//	===========================================================================

#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif

#include	"LDataDragTask.h"
#include	<LDataDragEventHandler.h>
#include	<LDragTube.h>
#include	<LSelectableItem.h>
#include	<LSelectHandlerView.h>
#include	<LWindow.h>
#include	<UDesktop.h>

#include	<LAEAction.h>
#include	<UAppleEventsMgr.h>
#include	<UMemoryMgr.h>


#ifndef		__ERRORS__
#include	<Errors.h>
#endif

#ifndef		__AEOBJECTS__
#include	<AEOBJECTS.h>
#endif

/*
	LDataDragTask does the mapping and coordination of data transfer for a drag
	between:
		some other drag originator	-->	an LDataDragEventHandler
		an LDataDragEventHandler	-->	another LDataDragEventHandler
		an LDataDragEventHandler	-->	some other drag receiver
		
	LDataDragTask contains all the instance/state information for the single
	drag operation.
	
	LDataDragTask replaces much of the complexity and functionality found in
	the pre 9409 LDataDragEventHandler -- that code in that version of the
	handler was becoming unwieldy in trying to find the location of the
	correct state information.
*/

LDataDragTask	*LDataDragTask::sActiveTask = NULL;

LDataDragTask::LDataDragTask(LDataDragEventHandler *inHandler, Boolean inHandlerIsSource)
{
	OSErr	err;
	
	Assert_(sActiveTask == NULL);
	
	if (inHandlerIsSource) {
		mSourceHandler = inHandler;
		mReceiveHandler = NULL;
		
		err = NewDrag(&mDragRef);
		ThrowIfOSErr_(err);
	} else {
		mSourceHandler = NULL;
		mReceiveHandler = inHandler;
		mDragRef = NULL;
	}
	mReceiver = NULL;
	
	mDataTransferred = false;
	mNotified = false;
	mDragTube = NULL;
	mDragAction = NULL;
	
	mDragSemantic = dataDrag_Unknown;
	mDragFunction = dataDragFunc_Unknown;
	
	sActiveTask = this;
}

LDataDragTask::~LDataDragTask()
{
	OSErr	err;
	
	sActiveTask = NULL;
	
	if (mSourceHandler != NULL) {
		if (mDragRef != NULL) {
			err = DisposeDrag(mDragRef);
			ThrowIfOSErr_(err);
			mDragRef = NULL;
		}
		if (mDragTube != NULL) {
			delete mDragTube;
			mDragTube = NULL;
		}
	}
	SetReceiver(NULL);
}

void	LDataDragTask::SetReceiver(LSelectableItem *inReceiver)
{
	ReplaceSharable(mReceiver, inReceiver, this);
}

void	LDataDragTask::CheckTube(void)
{
	Assert_(mDragRef);
	
	if (mDragTube == NULL) {
		mDragTube = new LDragTube(mDragRef);
	}
}

LDataDragEventHandler *	LDataDragTask::GetReceiveHandler(void) const
{
	return mReceiveHandler;
}

void	LDataDragTask::NoteReceiveHandler(LDataDragEventHandler *inHandler)
{
	if (!mNotified)
		mReceiveHandler = inHandler;
}

void	LDataDragTask::NoteTransfer(void)
{
	OSErr			err;
	StAEDescriptor	dropLoc;
	Boolean			receivable = false;
	
	if (mNotified)
		return;
	
	mNotified = true;

	mDragFunction = dataDragFunc_Unknown;
	mDragSemantic = dataDrag_Unknown;
	
	//	Check receivability
	if (mReceiveHandler) {
		if (mReceiver && mDragTube) {
			receivable = (typeNull != mReceiver->PickFlavorFrom(mDragTube));
		}
		if (!receivable) {
			//	We really shouldn't be here...
			//	?
			return;
		}

		//	Drop location -- for sender's pleasure
		mReceiver->MakeSpecifier(dropLoc.mDesc);
		if (dropLoc.mDesc.descriptorType == typeInsertionLoc) {
			err = SetDropLocation(mDragRef, &dropLoc.mDesc);
		} else {
			StAEDescriptor	temp;
			UAEDesc::MakeInsertionLoc(dropLoc.mDesc, kAEReplace, &temp.mDesc);
			err = SetDropLocation(mDragRef, &temp.mDesc);
		}
		ThrowIfOSErr_(err);
	}
	
	//	Codify type of drag function...
	if (!mReceiveHandler && !mSourceHandler) {
		Assert_(false);	//	Impossible!
	}
	if (!mReceiveHandler && mSourceHandler) {
		err = GetDropLocation(mDragRef, &dropLoc.mDesc);
		if (err == noErr)
			mDragFunction = dataDragFunc_OSpecDrop;
		else
			mDragFunction = dataDragFunc_Drop;
	}
	if (mReceiveHandler && !mSourceHandler) {
		mDragFunction = dataDragFunc_Receive;
	}
	if (mReceiveHandler && mSourceHandler) {
		mDragFunction = dataDragFunc_Drag;
	}
	
	//	Delay or do the transfer...
	switch (mDragFunction) {

		case dataDragFunc_Receive:
			DoTransfer();
			break;

		case dataDragFunc_OSpecDrop:
			/*
				To bad we can't tell a smart, drop location aware
				receiver not to receive the data.  If that was the case,
				it would simplify things and we could package up a nice
				apple event for the receiver.
			*/
			//	Falls through for now...

		case dataDragFunc_Drop:
			DoTransfer();
			break;
			
		case dataDragFunc_Drag:
			/*
				DoFactoredDataDrag();
	
				Not!
	
				We are the sender & receiver and have more control.
				Don't do anything now -- the transfer will take place later
				outside of the TrackDrag function.
								
				As an added bonus of this technique, the response to the
				drag can be debugged with the source level debugger!
			*/
			/*
				What an ugly pain...
	
				If a flavor hasn't been "gotten" before a TrackDrag ends,
				it is forgotten.
				
				So, let's make sure the object specifier needed later
				has been loaded.
			*/
			mDragTube->GetFlavorSize(typeObjectSpecifier);
			break;

		default:
			Throw_(paramErr);	//	Drag must be codified by now
			break;
	}
}

void	LDataDragTask::DoTransfer(void)
{
	if (mDataTransferred)
		return;		//	Must have been done during NoteTransfer.

	//	Uglyness to the max.  This really should go somewhere else --
	//	maybe it is a complication with cross application drags & LDragAndDrap?
	if (mDragFunction == dataDragFunc_Receive) {
		if (mReceiveHandler && mDragRef) {
			if (mReceiver)
				mReceiver->UnDrawSelfReceiver();
			HideDragHilite(mDragRef);
		}
	}
	
	//	Make the drag action...
	mDragAction = MakeDragAction();
	
	//	Do the transfer...
	switch (mDragFunction) {

		case dataDragFunc_Receive:
			mReceiveHandler->PostAction(mDragAction);
			break;

		case dataDragFunc_OSpecDrop:
			//	Fall through...

		case dataDragFunc_Drop:
			//	Nothing to post!  Responsibility of unknown receiver.
			break;
			
		case dataDragFunc_Drag:
			mReceiveHandler->PostAction(mDragAction);
			break;

		case dataDragFunc_Unknown:
			Throw_(userCanceledErr);	//	User must have stopped
										//	before drag was determined.
			break;
			
		default:
			Throw_(paramErr);	//	Drag must be codified by now
			break;
	}

	//	Switch target if mouse up in same window
	//	
	//	From a user i/f standpoint, in the case of dragging
	//	to an active window of multiple select handler views,
	//	it might be more natural if the receiving select handler view
	//	automatically becomes the target...
	if (mReceiveHandler) {
		LSelectHandlerView	*view = (LSelectHandlerView *)mReceiveHandler->GetHandlerView();
		
		if (view) {
//			Assert_(member(view, LSelectHandlerView));
			view->ShouldBeTarget();
		}
	}
	
	mDataTransferred = true;
}

LAction	*	LDataDragTask::MakeDragAction(void)
{
	LAction	*action = NULL;
	
	switch(mDragFunction) {

		case dataDragFunc_Receive:
			//	can only be a create
			Assert_(mReceiveHandler);
			action = mReceiveHandler->MakeCreateTask();
			break;
		
		case dataDragFunc_Drop:
		case dataDragFunc_OSpecDrop:
			//	We'll never know.  Also, action = NULL should not be posted.
			break;
			
		case dataDragFunc_Drag:
			Assert_(mReceiveHandler);
			mDragSemantic = mReceiveHandler->FindDragSemantic();
			switch (mDragSemantic) {
				case dataDrag_Copy:
					action = mReceiveHandler->MakeCopyTask();
					break;
				case dataDrag_Move:
					action = mReceiveHandler->MakeMoveTask();
					break;
				case dataDrag_OSpec:
					action = mReceiveHandler->MakeOSpecTask();
					break;
				case dataDrag_Link:
					action = mReceiveHandler->MakeLinkTask();
					break;
			}
			break;
	}
	return action;
}