The OpenDoc drag and drop facility allows users to apply direct manipulation to move or copy data. Users can drag items from one location in a part or document (or the desktop) to another location in the same or different part or document (or to the desktop).
Drag and drop provides a direct-manipulation alternative to the clipboard. The fundamental user-level operations, copying and moving, are are similar in drag and drop and in clipboard transfer and are similar across all platforms.
The user typically initiates a drag by positioning the mouse pointer over some selected (or single-click-selectable) content, pressing and holding down the mouse button, and then moving the pointer. The user can hold down a modifier key while pressing the mouse button or while releasing the mouse button to force a drag to be a copy (called a drag-copy) or a move (called a drag-move).
As the user moves the mouse pointer, an outline of the selected item (provided by the source part, drawn by OpenDoc) is dragged to the new location. When the user releases the mouse button, the item is placed (dropped) at the pointer location. The part beneath the pointer is notified that something has been dropped on it. At this point, the destination part behaves essentially as it does when pasting from the clipboard; it makes the same decisions regarding embedding versus incorporating data and handling links. The source part may have to delete the items if it was a move operation or do nothing if it was a copy.
Parts can restrict the dropped content they will accept to specific part kinds. To indicate that it can accept a drop, a part provides appropriate feedback to the user once the mouse pointer enters its facet.
For frames and icons that are being dragged, OpenDoc provides specific behavior and appearance for the item being dragged. For intrinsic content that is being dragged, your part editor is responsible for defining behavior and providing user feedback.
The user can move an active frame by dragging its border. By moving the pointer to the active frame border and pressing the mouse button, the user selects the frame and can start dragging immediately.
The user can move a selected frame by moving the pointer anywhere within it and pressing the button to start a drag. Also, if a frame is bundled, the user can drag it by pressing the mouse button while the pointer is anywhere in the interior of the frame, whether or not the frame is already active or selected.
When the user releases the mouse button, the frame and its part are dropped at the new location. After a frame is dropped, it becomes selected. The destination may adjust the drop location of a frame based on constraints such as gridding (in a graphics part) or text position (in a text part).
OpenDoc follows these conventions for drag and drop:
OpenDoc supports a mechanism for you to allow the user to force a copy or move operation by pressing modifier keys.
Dragging stationery
Stationery parts may be copied exactly like any other part. However, if you drag-move stationery into a part whose preferred view type for embedded parts is frame view, a copy is "torn off" the stationery pad and displayed in a frame. The stationery part remains in its original location, unchanged.
Each frame has a SetDroppable method, through which the part displayed in the frame controls whether or not the frame can (in general) accept dropped data. When a display frame is added or reconnected to your part, you can call SetDroppable and pass either kODTrue or kODFalse to allow or prohibit dropping. (When initially created, frames are not droppable.) You can call SetDroppable again at any time to change the state of the frame.
OpenDoc calls the IsDroppable method of the frame before making any of the drag-related method calls DragEnter, DragWithin, DragLeave, or Drop to your part. If your display frame is not droppable, your part does not receive any of these calls.
Your part's display frame does not have to be droppable for you to initiate a drag from it.
If your part supports dragging and dropping data, it must also support undoing that operation. Data transfer between parts is undoable only if both parts have undo support. Undo support in general is described in "Undo".
For drag and drop, undo involves a multistage action. The part initiating the drag begins the action, the part receiving the drop adds a single action, and the initiating part completes the action when the drop completes. See "Adding Multistage Actions" for more details. If drag and drop involves embedded frames, be sure to set the dragged frames' in-limbo flags appropriately when initiating a drag, when dropping, and when the drag completes. See Table 5 for details.
In response to a mouse-down event at the appropriate location, the part receiving the mouse event (the source part) has the choice of initiating a drag. You should follow the procedures listed under "Mouse Events, Activation, and Dragging" in deciding whether to initiate a drag operation.
To initiate a drag, you (the source part) should follow these steps:
There is no drag-and-drop focus or lock to be acquired. Only one part at a time can initiate and complete a drag.
The StartDrag method completes when the drop occurs; see "Completion of StartDrag".
As long as the mouse button remains pressed, the drag is in progress. Potential destination parts need to perform certain actions during dragging when the mouse pointer is within their facets.
Any facet the mouse pointer passes over during a drag represents a potential drop destination, if the facet's frame is droppable. OpenDoc calls a part's DragEnter method when the pointer enters one of its droppable frames' facets during a drag:
ODDragResult DragEnter (in ODDragItemIterator dragInfo, in ODFacet facet, in ODPoint where); |
On receiving a call to its DragEnter method, your part (the potential destination part) should take these steps:
Note:
(For the OS/2 platform). As for the clipboard object, the OS/2 implementation of the ODDragAndDrop object provides two extra methods to help parts in determining whether or not they can accept the dragged data; they are called CanEmbed and CanIncorporate.CanEmbed queries the registration manager for a part editor capable of handling the content of the drag item. If a match is found, the corresponding rendering mechanism and format pair will be saved in the drag item storage unit (under the the kODSelectedRMF value of the kODPropContents property) to be used later for rendering in the event a drop ocurrs in this facet. This method should be used by container parts.
CanIncorporate determines if the drag item content matches a specific kind. Parts should call this method for the kinds they support. As for CanEmbed, if a match is found, the corresponding rendering mechanism and format pair will be saved in the drag item storage unit.
If your part cannot accept all the dragged items, you should not accept a drop at all.
When the user initiates a drag from within your frame, you should not display destination feedback as long as the mouse pointer has not yet left your frame, although you should provide feedback if the mouse pointer returns to your frame after having left it.
You can draw the drag feedback on your own, or with the help of platform-specific services.
If you return kODFalse from this method, OpenDoc assumes you cannot accept a drop and will not subsequently call your DragWithin, DragLeave, or Drop methods as long as the mouse pointer remains in this facet.
OpenDoc calls the potential destination part's DragWithin method continuously while the mouse pointer remains inside the facet:
ODDragResult DragWithin (in ODDragItemIterator dragInfo, in ODFacet facet, in ODPoint where); |
In response, the part can do any desired processing inside of its display. For example, if a part allows objects to be dropped only in individual hot spots, it may change its feedback based on mouse-pointer location.
Calls to a part's DragWithin method also give the part an additional chance to examine the state of the user's system. For example, the part may want to find out whether the user has pressed a modifier key during the drag operation.
If you return kODFalse from this method, OpenDoc assumes you no longer wish to accept a drop in this facet. It will not make additional calls to your DragWithin method, and will not call your DragLeave or Drop method, as long as the mouse pointer remains in this facet.
OpenDoc calls the DragLeave method of a potential destination part when the mouse pointer leaves a droppable facet:
void DragLeave (in ODFacet facet, in ODPoint where); |
In response, the part might remove the adornment on its frame.
If the user releases the mouse button while the pointer is within a facet, OpenDoc calls the Drop method of the facet's part. This is the interface to the Drop method:
ODDropResult Drop (in ODDragItemIterator dropInfo, in ODFacet facet, in ODPoint where); |
The potential destination part then decides whether it can receive the dragged data. If it accepts the data, it either incorporates it or embeds it. This section describes how to design your drop method, how to accept a drop of non-OpenDoc data, and what the source part (the part that initiated the drag) should do after the drop occurs.
The destination part can inspect the drag attributes (by calling the GetDragAttributes method of the drag and drop object) to determine how to handle the drop. Drag attributes are bit flags, and more than one can be set at a time.
These are the possible drag attributes for a drop:
Constant | Description |
kODDragIsInSourceFrame | The item being dragged has not yet left the source frame of the drag. |
kODDragIsInSourcePart | The item being dragged is in the source part of the drag. |
kODDropIsInSourceFrame | The drop is occurring in the source frame of the drag. |
kODDropIsInSourcePart | The drop is occurring in the part displayed in the source frame of the drag (though not necessarily in the source frame itself). |
kODDropIsMove | This drag and drop operation is a move. |
kODDropIsCopy | This drag and drop operation is a copy. |
kODDropIsLink | This drag and drop operation is a link. |
kODDropIsPasteAs | The destination part should display the Paste As dialog box. |
Your Drop method might follow steps similar to these:
In all of these cases, you initially read the data from the drag and drop object, and you specify the following kinds of clone transactions:
Note:
The destination part can override a drag that is a move and force it to be a copy. It cannot, however, override a copy and force it to be a move.
If the drop involves an embedded frame, follow the instructions listed in Table 5. Save the current value of the frame's in-limbo flag and then set the flag to false.
When it completes, your Drop method should return an appropriate result (of type ODDropResult), such as kODDropCopy, kODDropMove, or kODDropFail. OpenDoc in turn passes that information on to the source part; see "Completion of StartDrag".
When your part's Drop method is called, it is passed a drag-item iterator (class ODDragItemIterator), so that you can access all drag items in the drag and drop object. If OpenDoc data has been dragged, there is only one drag item in the object, but if the data comes from outside of OpenDoc, there may be more than one item. It is the responsibility of the destination part to iterate through all the drag items to find out whether it can accept the drop.
You can examine the contents property of the storage unit of each dragged item to determine the kind of data it consists of. If you can read data of that type, you can incorporate it into your part. Otherwise, you may be able to embed it as a separate part.
If your part is the source part of this drag, your call to the drag and drop object's StartDrag method completes after the destination's Drop method completes. You can now, based on the return value of StartDrag, confirm whether the operation was a move or a copy or whether it failed. Take these steps:
If the completed drag was initiated as a drag-move but ended up being a drag-copy, and if it involved an embedded frame, follow the instructions listed in Table 5 (reset the frames's in-limbo flag to false).
Asynchronous drag and drop
On the AIX platform, OpenDoc provides the ODPart method DropCompleted. This method is called to notify the source part of the completion of a drag that it initiated. The method provides the same drop results that StartDrag returns for a synchronous drag.