home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / PowerPlant / CDragAndDrop / CDragAndDrop.cp next >
Encoding:
Text File  |  1995-02-09  |  12.0 KB  |  371 lines  |  [TEXT/CWIE]

  1. // ============================================================================
  2. //    CDragAndDrop.cp       ©1995 J. Rodden, DD/MF & Associates. All rights reserved
  3. // ============================================================================
  4. // CDragAndDrop picks up drag manager handling where LDragAndDrop leaves off.
  5. // Everything necessary for a drag and droppable pane is encapsulated in this
  6. // class. 
  7. // ============================================================================
  8.  
  9. #include "CDragTask.h"
  10. #include "CDragAndDrop.h"
  11.  
  12. // ============================================================================
  13. //        • CDragAndDrop
  14. // ============================================================================
  15.  
  16. CDragAndDrop::CDragAndDrop(WindowPtr inMacWindow, LPane *inPane)
  17.         : LDragAndDrop(inMacWindow, inPane)
  18. {
  19.     mFlavorSize        = 0L;
  20.     mFlavorAccepted    = 0L;
  21.     
  22.     mHighlightDrag    = true;
  23. }
  24.  
  25.  
  26. // ============================================================================
  27. //        • ClickIsDragEvent
  28. // ============================================================================
  29.  
  30. Boolean
  31. CDragAndDrop::ClickIsDragEvent(const SMouseDownEvent &inMouseDown, Rect* inRect)
  32. {
  33.     // Track item long enough to distinguish between a click to
  34.     // select, and the beginning of a drag
  35.     
  36.     if ( ::WaitMouseMoved(inMouseDown.macEvent.where) ) {
  37.         // If we leave the window, the drag manager will be changing thePort,
  38.         // so we'll make sure thePort remains properly set.
  39.         
  40.         mPane->GetSuperView()->FocusDraw();
  41.         CreateDragEvent(inMouseDown,inRect);
  42.         mPane->GetSuperView()->OutOfFocus(nil);
  43.         
  44.         return true;
  45.     }
  46.     
  47.     return false;
  48. }
  49.  
  50.  
  51. // ============================================================================
  52. //        • CreateDragEvent
  53. // ============================================================================
  54.  
  55. void
  56. CDragAndDrop::CreateDragEvent(const SMouseDownEvent &inMouseDown, Rect* inRect)
  57. {
  58.     if ( DragAndDropIsPresent() ) {
  59.         
  60.         CDragTask theDragTask( inMouseDown.macEvent, inRect, kItemRef, this);
  61.     
  62.         mHighlightDrag = false;        // we start a drag here, don't highlight until
  63.                                     // we've gone out and returned
  64.         theDragTask.DoDrag();
  65.     
  66.         // If the drag is to the trash, it should be a move, not a copy
  67.         if ( DroppedInTrash(&theDragTask) ) RemoveDragItem(inMouseDown);
  68.     }
  69. }
  70.  
  71.  
  72. // ============================================================================
  73. //        • SetLocalFrame
  74. // ============================================================================
  75. // Setup local frame (in global coords) for reference by drawing routines
  76.  
  77. void
  78. CDragAndDrop::SetLocalFrame (void)
  79. {
  80.     mPane->CalcPortFrameRect(mLocalFrame);
  81.  
  82.     mPane->PortToGlobalPoint(topLeft (mLocalFrame));
  83.     mPane->PortToGlobalPoint(botRight (mLocalFrame));
  84. }
  85.  
  86.  
  87. // ============================================================================
  88. //        • ItemIsAcceptable
  89. // ============================================================================
  90.  
  91. Boolean
  92. CDragAndDrop::ItemIsAcceptable(DragReference inDragRef, ItemReference inItemRef)
  93. {
  94.     //    ItemIsAcceptable will be called whenever the Drag Manager wants to know if
  95.     //    the item the user is currently dragging contains any information that we
  96.     //    can accept.
  97.     //
  98.     //    In our case, the only thing we'll accept are mFlavorAccepted items.
  99.  
  100.     FlavorFlags    theFlags;
  101.     
  102.     if (::GetFlavorFlags(inDragRef, inItemRef, mFlavorAccepted, &theFlags) == noErr)
  103.         return true;
  104.     
  105.     return false;
  106. }
  107.  
  108.  
  109. // ============================================================================
  110. //        • LeaveDropArea
  111. // ============================================================================
  112.  
  113. void
  114. CDragAndDrop::LeaveDropArea (DragReference inDragRef)
  115. {
  116.     LDragAndDrop::LeaveDropArea(inDragRef);
  117.     mHighlightDrag = true;        // next time we enter, highlight
  118. }
  119.  
  120.  
  121. // ============================================================================
  122. //        • InsideDropArea
  123. // ============================================================================
  124.  
  125. void
  126. CDragAndDrop::InsideDropArea (DragReference inDragRef)
  127. {
  128.     // Let LDragAndDrop do its thing - this is not really necessary, since
  129.     //        the inherited version doesn't do anything. But it's safer this
  130.     //        way because someday it might.
  131.  
  132.     LDragAndDrop::InsideDropArea(inDragRef);
  133.     
  134.  
  135.     // And we'll do ours - we'll just read the mouse coordinates.
  136.  
  137.     Point    theMouseLocation;
  138.     Point    thePinnedLocation;
  139.     ::GetDragMouse(inDragRef, &theMouseLocation, &thePinnedLocation);
  140.     
  141.     mPane->GlobalToPortPoint(theMouseLocation);
  142.     mPane->PortToLocalPoint(theMouseLocation);
  143.     mPane->GlobalToPortPoint(thePinnedLocation);
  144.     mPane->PortToLocalPoint(thePinnedLocation);
  145.     
  146.     InsideDropArea( inDragRef, theMouseLocation, thePinnedLocation);
  147. }
  148.  
  149.  
  150. // ============================================================================
  151. //        • InsideDropArea
  152. // ============================================================================
  153. // The mouse location is where the mouse actually is on the screen. The
  154. // alternative is the pinned location, which is _usually_ the same location,
  155. // but can be different if the cursor is being constrained by a tracking handler.
  156. // This is useful when you want an area within a view to be 'off-limits' to
  157. // the ongoing drag.
  158. //
  159. // If we did want to do something based on where the cursor currently is in
  160. // our area (such as indicating an insertion point or something), it would
  161. // usually be best to use the pinned location for that work.
  162. //
  163. // Both mouse locations are in global screen coordinates
  164. // ============================================================================
  165.  
  166. void
  167. CDragAndDrop::InsideDropArea(
  168.     DragReference    inDragRef,
  169.     Point&            theMouseLocation,
  170.     Point&            thePinnedLocation)
  171. {
  172. }
  173.  
  174.  
  175. // ============================================================================
  176. //        • ReceiveDragItem
  177. // ============================================================================
  178.  
  179. void
  180. CDragAndDrop::ReceiveDragItem(
  181.     DragReference    inDragRef,
  182.     DragAttributes    inDragAttrs,
  183.     ItemReference    inItemRef,
  184.     Rect            &inItemBounds)    // In Local coordinates
  185. {
  186.     mHighlightDrag = true;
  187.     
  188.     // First, we'll figure out whether we want to copy the item(s), or only move the item(s).
  189.     //
  190.     // The rules for copying vs moving are spelled out in MD+DDK pp 19 through 21, and in
  191.     // a simplified form are: copy the item unless where it's coming from and
  192.     // where it's going to are the same window; then move it. If the option key
  193.     // was held down when the drag began, always copy it.
  194.     //
  195.     // Optional behaviour is for an application to also check the option
  196.     // key at the end of the drag. Copying then takes place if the option key was
  197.     // held down at the beginning _OR_ at the end.
  198.     
  199.     Boolean optionKeyWasDown = CheckForOptionKey(inDragRef);
  200.  
  201.     // Check to see if this View (the destination) is the
  202.     // same view (the source) that the object is coming from.
  203.     
  204.     Boolean dragIsFromThisView = CheckIfViewIsAlsoSender(inDragRef);
  205.     
  206.     Boolean copyData = !(dragIsFromThisView && !optionKeyWasDown);
  207.     
  208.     
  209.     // Information about the drag contents we'll be needing.
  210.     
  211.     FlavorFlags    theFlags;        // We actually only use the flags to see if a flavor exists
  212.     Size        theDataSize;    // How much data there is for us.
  213.     
  214.     // Check to make sure the drag contains a mFlavorAccepted item.
  215.     
  216.     if (::GetFlavorFlags(inDragRef, inItemRef, mFlavorAccepted, &theFlags) == noErr) {
  217.         Boolean fromFinder
  218.                 = ( ::GetFlavorFlags(inDragRef, inItemRef, flavorTypeHFS, &theFlags) == noErr );
  219.  
  220.       ::GetFlavorDataSize(inDragRef, inItemRef, mFlavorAccepted, &theDataSize);
  221.         
  222.         ThrowIf_(theDataSize > sizeof(mFlavorSize));    // sanity check
  223.         
  224.         ReceiveDragItem( inDragRef, inItemRef, theDataSize, 
  225.                             copyData, fromFinder, inItemBounds);
  226.     }
  227. }
  228.  
  229.  
  230. // ============================================================================
  231. //        • ReceiveDragItem
  232. // ============================================================================
  233. // Override this routine to pull out the dragged data.
  234.  
  235. void
  236. CDragAndDrop::ReceiveDragItem(
  237.     DragReference    inDragRef,
  238.     ItemReference    inItemRef,
  239.     Size            inDataSize,        // How much data there is
  240.     Boolean            inCopyData,      // Should we copy the data?
  241.     Boolean            inFromFinder,    // Data came from the Finder
  242.     Rect&            inItemBounds)    // In Local coordinates
  243. {
  244. }
  245.  
  246.  
  247. // ============================================================================
  248. //        • RemoveDragItem
  249. // ============================================================================
  250. // The drag item orriginated by inMouseDown was dropped in the trash.
  251.  
  252. void
  253. CDragAndDrop::RemoveDragItem(const SMouseDownEvent &inMouseDown)
  254. {
  255. }
  256.  
  257.  
  258. // ============================================================================
  259. //        • DroppedInTrash
  260. // ============================================================================
  261.  
  262. Boolean
  263. CDragAndDrop::DroppedInTrash(LDragTask* inDragTask)
  264. {
  265.     // An exception to the copy vs move option is if the user drags
  266.     // the item to the trash. Then it should be _moved_, not copied.
  267.     //
  268.     // If we run into any error messages along the way, we'll abort
  269.     // the test. We can't lose any data this way; only _not_ making
  270.     // a deletion that really should be made.
  271.  
  272.     OSErr    theErr;
  273.     AEDesc    theDropDestination;
  274.     
  275.     DragReference theDragRef = inDragTask->GetDragReference();
  276.     theErr = ::GetDropLocation(theDragRef, &theDropDestination);
  277.     
  278.     if ((theErr) || (theDropDestination.descriptorType == typeNull)) return false;
  279.     
  280.     if (theDropDestination.descriptorType == typeAlias) {
  281.  
  282.         // The drag was to the finder. The question now is whether it
  283.         // was to the trash.
  284.  
  285.         Boolean    aliasWasChanged;
  286.         FSSpec    theDestinationFSSpec;
  287.         FSSpec    theTrashFSSpec;
  288.         short    theTrashVRefNum;
  289.         long    theTrashDirID;
  290.  
  291.         // First, build the FSSpec of the destination to which the user dragged
  292.         // the object
  293.  
  294.         HLock(theDropDestination.dataHandle);
  295.         theErr = ::ResolveAlias(    nil,
  296.                                     (AliasHandle) theDropDestination.dataHandle,
  297.                                     &theDestinationFSSpec,
  298.                                     &aliasWasChanged);
  299.         HUnlock(theDropDestination.dataHandle);
  300.         if (theErr) return false;
  301.         
  302.  
  303.         // Next, find the FSSpec of the system's trash
  304.  
  305.         theErr = ::FindFolder(    kOnSystemDisk, kTrashFolderType, kDontCreateFolder,
  306.                                 &theTrashVRefNum, &theTrashDirID);
  307.         if (theErr) return false;
  308.         
  309.         theErr = ::FSMakeFSSpec( theTrashVRefNum, theTrashDirID, nil, &theTrashFSSpec);
  310.         if (theErr) return false;
  311.         
  312.  
  313.         // Compare the two FSSpecs.
  314.  
  315.         if ((            theDestinationFSSpec.vRefNum ==    theTrashFSSpec.vRefNum)
  316.         && (            theDestinationFSSpec.parID     ==    theTrashFSSpec.parID)
  317.         && (EqualString(theDestinationFSSpec.name,        theTrashFSSpec.name, false, true))) {
  318.  
  319.             // Since the FSSpec of the destination of the drag is the same as the FSSpec of
  320.             // the trash, the drag was to the trash.
  321.             //
  322.             // We get to this point _after_ the clipping file has been placed in the trash
  323.             // so to complete the 'move', we simply delete this item.
  324.  
  325.             return true;
  326.         }
  327.     }
  328.     
  329.     return false;
  330. }
  331.  
  332.  
  333. // ============================================================================
  334. //        • CheckForOptionKey
  335. // ============================================================================
  336.  
  337. Boolean
  338. CDragAndDrop::CheckForOptionKey(DragReference inDragRef)
  339. {
  340.     // We'll check whether the option key was down at either the beginning _or_ the
  341.     // end of the drag, since (a) it's the preferred behaviour and (b) its so easy to do.
  342.  
  343.     Int16 theModifiersNow;            // The state of the modifier keys right now
  344.     Int16 theModifiersAtMouseDown;    // The state of the modifier keys when the drag began
  345.     Int16 theModifiersAtMouseUp;    // The state of the modifier keys when the drag ended
  346.     ::GetDragModifiers(inDragRef, &theModifiersNow, &theModifiersAtMouseDown, &theModifiersAtMouseUp);
  347.     
  348.     return ((theModifiersAtMouseDown & optionKey) || (theModifiersAtMouseUp & optionKey));
  349. }
  350.  
  351.  
  352. // ============================================================================
  353. //        • CheckIfViewIsAlsoSender
  354. // ============================================================================
  355.  
  356. Boolean
  357. CDragAndDrop::CheckIfViewIsAlsoSender(DragReference inDragRef)
  358. {
  359.     // Just a note: While we are using the drag attributes only at the end of the
  360.     // drag, they are also available to you during the drag.
  361.  
  362.     // Drag Attributes are described in MD+DDK, page 2-31.
  363.  
  364.     DragAttributes theDragAttributes;
  365.     ::GetDragAttributes(inDragRef, &theDragAttributes);
  366.     
  367.     return (theDragAttributes & dragInsideSenderWindow);
  368. }
  369.  
  370.  
  371.