Previous Book Contents Book Index Next

Inside Macintosh: Programmer's Guide to MacApp / Part 1 - MacApp Theory and Architecture
Chapter 9 - Drag and Drop

Working With Drag Data

MacApp supplies a number of classes and methods for efficient manipulation of drag data. The following sections provide additional detail on classes and topics introduced earlier in this chapter.


The CDragItemIterator class provides an iterator that traverses the TDragItem objects in a drag operation. A CDragItemIterator object is passed as a parameter to several TView methods during a drag session. For example, the TView::WillAcceptDrop method uses a passed iterator to determine whether the view can accept the data in the drag.

How Data Is Represented

The Macintosh Drag Manager supports dragging of data in multiple representations, or flavors. This is similar to the concept of putting Clipboard data on the desk scrap in multiple formats, such as PICT and TEXT. A drag source should supply or promise data in as many flavors as it can support, to increase the likelihood that a drop target will be able to accept the dragged data.

MacApp supplies the TDragItem class (page 267) to aid your application in supplying data to the Drag Manager, and the CFlavorFlags data structure to provide simplified access to the Drag Manager FlavorFlags data type.

When a View Should Accept a Drop

A view should examine the contents of a drag and determine whether it can accept the dragged item(s). The human interface guidelines for drag and drop suggest that a drop target should accept a drop only if all items can be accepted. This eliminates any ambiguity that might result if a drop target only accepted a subset of items being dragged.

If a view can accept only a single item and the passed CDragItemIterator object represents multiple items, the view should refuse to accept the drop. For example, a TPicture view accepts a drag if there is exactly one item and it has the PICT flavor.

Each item in a drag can contain multiple "flavors," or representations, of the item. The drop target doesn't need to accept all flavors offered by each item, but it must accept each of the items in some supplied flavor.


A view object uses objects of type TDragItem to supply data to be dragged. The data can be supplied in multiple representations, or flavors. For example, if a user clicks and drags a picture, the application might supply a single drag item object with flavors of PICT, GIF, JPEG, QuickTime, and any other graphic format it knows how to provide. This enables the drop target to request the item in whatever format it understands best.

The TDragItem class simplifies the multiflavor nature of drag items by implementing the concept of focus. A TDragItem object is always "focused" on a specific flavor. TDragItem methods for reading and writing data work on whatever flavor is currently focused. Adding a new flavor to a TDragItem object has the effect of focusing on the new flavor. An application focuses on a specific flavor by calling the FocusOnFlavor method.

Promising Data

Instead of providing a drag item with actual data, a view can promise to supply data later, using the TDragItem::PromiseFlavor method. Promising data requires little overhead and, except for very small data items, is more efficient than supplying all possible flavors up front--consider the memory requirements of supplying data in multiple large graphic formats, which may never even be used!

Fulfilling Promises

When a drop target requests data that has been promised, the drag session's DragSendDataProc method calls the DoFulfillPromise method of the drag source (normally a view object), passing a pointer to a TDragItem object that is focused on the requested flavor.

The view object can get information about the drag item by calling the GetFlavorType and GetItemReference methods. The view provides the requested flavor data by calling one or more of the following TDragItem methods that write data to the focused flavor of the drag item:

If a view requests a TDragFlavorStream, the view should free the requested stream before returning from DoFulfillPromise.

Drag Copy Versus Drag Move

A user-initiated drag operation can have the effect of either copying or moving the dragged data. The drag-and-drop human interface guidelines specify that data dragged within a single container should be moved. Data dragged between containers should be copied. However, the definition of container depends on the specific application, and the definition of within may vary depending on the user. To avoid confusion, the drag session object evaluates each drag individually and applies criteria established by the views involved to determine whether data should be copied or moved. Specifically, the DragReceiveHandler method of the drag session object calls the WillDragMove method of the source view.

Move Families

The WillDragMove method compares the values of the fDragMoveFamily fields of the source and target views to determine whether the drag qualifies as a move. Views that will support a drag move should set the fDragMoveFamily field to the same arbitrary value. It's OK if that value is the default, kNoIdentifier.

If, for example, a window contains a number of text views but a move should be generated only when dragging between two specific text views, those two views can assign the same value to fDragMoveFamily. Consequently, dragging between those two views will generate a move. Dragging between any other text view and one of the two views in the hypothetical family will cause the data to be copied.

Move Relationships

The source view of a drag uses its fDragMoveDeterminer field to specify a relationship with the target destination that must be met if data is to be moved. MacApp supplies the following values for the fDragMoveDeterminer field: kNeverMove, kMoveWithinWindow, kMoveWithinContext, kMoveWithinView, and kMoveWithinApplication.

If the fDragMoveFamily field values of the source and destination views match, the WillDragMove method looks at the value of the fDragMoveDeterminer field of the source view to determine whether the operation should be treated as a copy or a move. If the views are related in the manner described by the source view's fDragMoveDeterminer field, a move is generated. For example, if the source and target of a drag are views within the same window and the fDragMoveDeterminer field of the source view is kMoveWithinWindow, kMoveWithinContext, or kMoveWithinApplication, the drag will qualify as a move.

Forcing a Copy

MacApp implements a mechanism to circumvent the standard conventions and force a copy. To do so, a user presses the Option key before dropping the data and keeps it down while the data is dropped. The Option keypress is handled in the TDragDropSession::DragReceiveHandler method.


For MacApp to initiate a drag move operation, the source and destination views must have matching values in their fDragMoveFamily fields and the views must have the type of relationship specified by the source view's fDragMoveDeterminer field.

It's still a match if both views have their fDragMoveFamily fields set to kNoIdentifier.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996