Skip to content

DragOver implementation faulty #1295

@martijntonies

Description

@martijntonies

The current implementation of Drag/Drop (VCL style) seems faulty.

When an application uses a custom DragObject instead of having the drag "Source" be a pointer to the control that started the drag, the treeview hides this functionality.

A custom DragObject is used to add functionality and have the target control not test for individual controls, but use this added functionality when drag-dropping between (different) controls.

When deriving a custom DragObject from TBaseDragControlObject, the target control can access the original control too. But not with VirtualTree, see the code below: it explicitly tests for TBaseDragControlObject and then passes the control to the "DragOver" event, instead of the custom DragObject like other VCL controls do.

This means that when we want to use the custom drag object in the DragOver (or DragDrop) events of the tree view, all that information is gone, making the custom drag object usage useless...

Only when there's an "DragInternalObject" (see TControl.DoDragMsg and procedure DragInitControl in VCL.Controls), should the control be passed, as this means no custom drag object was used.

I believe that VirtualTree >tries< to check for a custom drag object in the .DoStartDrag method, but this only works when Source and Target are the same treeview instance, not when dragging from a different component or between virtual tree instances.

A user can decide to derive from BaseDragObject instead to avoid the issue with the current faulty implementation, but then looses information about the original source control.

`procedure TBaseVirtualTree.CMDrag(var Message: TCMDrag);

var
S: TObject;
ShiftState: Integer;
P: TPoint;
Formats: TFormatArray;
Effect: Integer;

begin
with Message, DragRec^ do
begin
S := Source;
Formats := nil;

// Let the ancestor handle dock operations.
if S is TDragDockObject then
  inherited
else
begin
  // We need an extra check for the control drag object as there might be other objects not derived from
  // this class (e.g. TActionDragObject).
  if not (tsUserDragObject in FStates) and (S is TBaseDragControlObject) then
    S := (S as TBaseDragControlObject).Control;

...
DragOver(S, ShiftState, TDragState(DragMessage), Pos, Effect);
...
`

Metadata

Metadata

Assignees

No one assigned

    Labels

    Pull Requests InvitedThere are no current plans to address the issue, but we would be happy if someone supplies a PR.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions