home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-02-09 | 12.0 KB | 371 lines | [TEXT/CWIE] |
- // ============================================================================
- // CDragAndDrop.cp ©1995 J. Rodden, DD/MF & Associates. All rights reserved
- // ============================================================================
- // CDragAndDrop picks up drag manager handling where LDragAndDrop leaves off.
- // Everything necessary for a drag and droppable pane is encapsulated in this
- // class.
- // ============================================================================
-
- #include "CDragTask.h"
- #include "CDragAndDrop.h"
-
- // ============================================================================
- // • CDragAndDrop
- // ============================================================================
-
- CDragAndDrop::CDragAndDrop(WindowPtr inMacWindow, LPane *inPane)
- : LDragAndDrop(inMacWindow, inPane)
- {
- mFlavorSize = 0L;
- mFlavorAccepted = 0L;
-
- mHighlightDrag = true;
- }
-
-
- // ============================================================================
- // • ClickIsDragEvent
- // ============================================================================
-
- Boolean
- CDragAndDrop::ClickIsDragEvent(const SMouseDownEvent &inMouseDown, Rect* inRect)
- {
- // Track item long enough to distinguish between a click to
- // select, and the beginning of a drag
-
- if ( ::WaitMouseMoved(inMouseDown.macEvent.where) ) {
- // If we leave the window, the drag manager will be changing thePort,
- // so we'll make sure thePort remains properly set.
-
- mPane->GetSuperView()->FocusDraw();
- CreateDragEvent(inMouseDown,inRect);
- mPane->GetSuperView()->OutOfFocus(nil);
-
- return true;
- }
-
- return false;
- }
-
-
- // ============================================================================
- // • CreateDragEvent
- // ============================================================================
-
- void
- CDragAndDrop::CreateDragEvent(const SMouseDownEvent &inMouseDown, Rect* inRect)
- {
- if ( DragAndDropIsPresent() ) {
-
- CDragTask theDragTask( inMouseDown.macEvent, inRect, kItemRef, this);
-
- mHighlightDrag = false; // we start a drag here, don't highlight until
- // we've gone out and returned
- theDragTask.DoDrag();
-
- // If the drag is to the trash, it should be a move, not a copy
- if ( DroppedInTrash(&theDragTask) ) RemoveDragItem(inMouseDown);
- }
- }
-
-
- // ============================================================================
- // • SetLocalFrame
- // ============================================================================
- // Setup local frame (in global coords) for reference by drawing routines
-
- void
- CDragAndDrop::SetLocalFrame (void)
- {
- mPane->CalcPortFrameRect(mLocalFrame);
-
- mPane->PortToGlobalPoint(topLeft (mLocalFrame));
- mPane->PortToGlobalPoint(botRight (mLocalFrame));
- }
-
-
- // ============================================================================
- // • ItemIsAcceptable
- // ============================================================================
-
- Boolean
- CDragAndDrop::ItemIsAcceptable(DragReference inDragRef, ItemReference inItemRef)
- {
- // ItemIsAcceptable will be called whenever the Drag Manager wants to know if
- // the item the user is currently dragging contains any information that we
- // can accept.
- //
- // In our case, the only thing we'll accept are mFlavorAccepted items.
-
- FlavorFlags theFlags;
-
- if (::GetFlavorFlags(inDragRef, inItemRef, mFlavorAccepted, &theFlags) == noErr)
- return true;
-
- return false;
- }
-
-
- // ============================================================================
- // • LeaveDropArea
- // ============================================================================
-
- void
- CDragAndDrop::LeaveDropArea (DragReference inDragRef)
- {
- LDragAndDrop::LeaveDropArea(inDragRef);
- mHighlightDrag = true; // next time we enter, highlight
- }
-
-
- // ============================================================================
- // • InsideDropArea
- // ============================================================================
-
- void
- CDragAndDrop::InsideDropArea (DragReference inDragRef)
- {
- // Let LDragAndDrop do its thing - this is not really necessary, since
- // the inherited version doesn't do anything. But it's safer this
- // way because someday it might.
-
- LDragAndDrop::InsideDropArea(inDragRef);
-
-
- // And we'll do ours - we'll just read the mouse coordinates.
-
- Point theMouseLocation;
- Point thePinnedLocation;
- ::GetDragMouse(inDragRef, &theMouseLocation, &thePinnedLocation);
-
- mPane->GlobalToPortPoint(theMouseLocation);
- mPane->PortToLocalPoint(theMouseLocation);
- mPane->GlobalToPortPoint(thePinnedLocation);
- mPane->PortToLocalPoint(thePinnedLocation);
-
- InsideDropArea( inDragRef, theMouseLocation, thePinnedLocation);
- }
-
-
- // ============================================================================
- // • InsideDropArea
- // ============================================================================
- // The mouse location is where the mouse actually is on the screen. The
- // alternative is the pinned location, which is _usually_ the same location,
- // but can be different if the cursor is being constrained by a tracking handler.
- // This is useful when you want an area within a view to be 'off-limits' to
- // the ongoing drag.
- //
- // If we did want to do something based on where the cursor currently is in
- // our area (such as indicating an insertion point or something), it would
- // usually be best to use the pinned location for that work.
- //
- // Both mouse locations are in global screen coordinates
- // ============================================================================
-
- void
- CDragAndDrop::InsideDropArea(
- DragReference inDragRef,
- Point& theMouseLocation,
- Point& thePinnedLocation)
- {
- }
-
-
- // ============================================================================
- // • ReceiveDragItem
- // ============================================================================
-
- void
- CDragAndDrop::ReceiveDragItem(
- DragReference inDragRef,
- DragAttributes inDragAttrs,
- ItemReference inItemRef,
- Rect &inItemBounds) // In Local coordinates
- {
- mHighlightDrag = true;
-
- // First, we'll figure out whether we want to copy the item(s), or only move the item(s).
- //
- // The rules for copying vs moving are spelled out in MD+DDK pp 19 through 21, and in
- // a simplified form are: copy the item unless where it's coming from and
- // where it's going to are the same window; then move it. If the option key
- // was held down when the drag began, always copy it.
- //
- // Optional behaviour is for an application to also check the option
- // key at the end of the drag. Copying then takes place if the option key was
- // held down at the beginning _OR_ at the end.
-
- Boolean optionKeyWasDown = CheckForOptionKey(inDragRef);
-
- // Check to see if this View (the destination) is the
- // same view (the source) that the object is coming from.
-
- Boolean dragIsFromThisView = CheckIfViewIsAlsoSender(inDragRef);
-
- Boolean copyData = !(dragIsFromThisView && !optionKeyWasDown);
-
-
- // Information about the drag contents we'll be needing.
-
- FlavorFlags theFlags; // We actually only use the flags to see if a flavor exists
- Size theDataSize; // How much data there is for us.
-
- // Check to make sure the drag contains a mFlavorAccepted item.
-
- if (::GetFlavorFlags(inDragRef, inItemRef, mFlavorAccepted, &theFlags) == noErr) {
- Boolean fromFinder
- = ( ::GetFlavorFlags(inDragRef, inItemRef, flavorTypeHFS, &theFlags) == noErr );
-
- ::GetFlavorDataSize(inDragRef, inItemRef, mFlavorAccepted, &theDataSize);
-
- ThrowIf_(theDataSize > sizeof(mFlavorSize)); // sanity check
-
- ReceiveDragItem( inDragRef, inItemRef, theDataSize,
- copyData, fromFinder, inItemBounds);
- }
- }
-
-
- // ============================================================================
- // • ReceiveDragItem
- // ============================================================================
- // Override this routine to pull out the dragged data.
-
- void
- CDragAndDrop::ReceiveDragItem(
- DragReference inDragRef,
- ItemReference inItemRef,
- Size inDataSize, // How much data there is
- Boolean inCopyData, // Should we copy the data?
- Boolean inFromFinder, // Data came from the Finder
- Rect& inItemBounds) // In Local coordinates
- {
- }
-
-
- // ============================================================================
- // • RemoveDragItem
- // ============================================================================
- // The drag item orriginated by inMouseDown was dropped in the trash.
-
- void
- CDragAndDrop::RemoveDragItem(const SMouseDownEvent &inMouseDown)
- {
- }
-
-
- // ============================================================================
- // • DroppedInTrash
- // ============================================================================
-
- Boolean
- CDragAndDrop::DroppedInTrash(LDragTask* inDragTask)
- {
- // An exception to the copy vs move option is if the user drags
- // the item to the trash. Then it should be _moved_, not copied.
- //
- // If we run into any error messages along the way, we'll abort
- // the test. We can't lose any data this way; only _not_ making
- // a deletion that really should be made.
-
- OSErr theErr;
- AEDesc theDropDestination;
-
- DragReference theDragRef = inDragTask->GetDragReference();
- theErr = ::GetDropLocation(theDragRef, &theDropDestination);
-
- if ((theErr) || (theDropDestination.descriptorType == typeNull)) return false;
-
- if (theDropDestination.descriptorType == typeAlias) {
-
- // The drag was to the finder. The question now is whether it
- // was to the trash.
-
- Boolean aliasWasChanged;
- FSSpec theDestinationFSSpec;
- FSSpec theTrashFSSpec;
- short theTrashVRefNum;
- long theTrashDirID;
-
- // First, build the FSSpec of the destination to which the user dragged
- // the object
-
- HLock(theDropDestination.dataHandle);
- theErr = ::ResolveAlias( nil,
- (AliasHandle) theDropDestination.dataHandle,
- &theDestinationFSSpec,
- &aliasWasChanged);
- HUnlock(theDropDestination.dataHandle);
- if (theErr) return false;
-
-
- // Next, find the FSSpec of the system's trash
-
- theErr = ::FindFolder( kOnSystemDisk, kTrashFolderType, kDontCreateFolder,
- &theTrashVRefNum, &theTrashDirID);
- if (theErr) return false;
-
- theErr = ::FSMakeFSSpec( theTrashVRefNum, theTrashDirID, nil, &theTrashFSSpec);
- if (theErr) return false;
-
-
- // Compare the two FSSpecs.
-
- if (( theDestinationFSSpec.vRefNum == theTrashFSSpec.vRefNum)
- && ( theDestinationFSSpec.parID == theTrashFSSpec.parID)
- && (EqualString(theDestinationFSSpec.name, theTrashFSSpec.name, false, true))) {
-
- // Since the FSSpec of the destination of the drag is the same as the FSSpec of
- // the trash, the drag was to the trash.
- //
- // We get to this point _after_ the clipping file has been placed in the trash
- // so to complete the 'move', we simply delete this item.
-
- return true;
- }
- }
-
- return false;
- }
-
-
- // ============================================================================
- // • CheckForOptionKey
- // ============================================================================
-
- Boolean
- CDragAndDrop::CheckForOptionKey(DragReference inDragRef)
- {
- // We'll check whether the option key was down at either the beginning _or_ the
- // end of the drag, since (a) it's the preferred behaviour and (b) its so easy to do.
-
- Int16 theModifiersNow; // The state of the modifier keys right now
- Int16 theModifiersAtMouseDown; // The state of the modifier keys when the drag began
- Int16 theModifiersAtMouseUp; // The state of the modifier keys when the drag ended
- ::GetDragModifiers(inDragRef, &theModifiersNow, &theModifiersAtMouseDown, &theModifiersAtMouseUp);
-
- return ((theModifiersAtMouseDown & optionKey) || (theModifiersAtMouseUp & optionKey));
- }
-
-
- // ============================================================================
- // • CheckIfViewIsAlsoSender
- // ============================================================================
-
- Boolean
- CDragAndDrop::CheckIfViewIsAlsoSender(DragReference inDragRef)
- {
- // Just a note: While we are using the drag attributes only at the end of the
- // drag, they are also available to you during the drag.
-
- // Drag Attributes are described in MD+DDK, page 2-31.
-
- DragAttributes theDragAttributes;
- ::GetDragAttributes(inDragRef, &theDragAttributes);
-
- return (theDragAttributes & dragInsideSenderWindow);
- }
-
-
-