| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264 | unit CustomDriveView;interfaceuses  Classes, ComCtrls, CommCtrl, Windows, Controls, Forms, ShlObj, Messages,    Graphics,  DragDrop, CustomDirView, IEDriveInfo, DragDropFilesEx, PasTools;type  {Types uses by the function IterateSubTree:}  {TRecursiveScan: determines, wich nodes are scanned by the function IterateSubTree:  rsNoRecursive:       Scan startnode only.  rsRecursiveExisting: Scan all subnodes of the startnode but not new created subnodes.}  TRecursiveScan = (rsNoRecursive, rsRecursiveExisting);  {TScanStartnode: determines, wether the startnode should also be scanned:}  TScanStartNode = (coNoScanStartNode, coScanStartNode);  TCallBackFunc = function(var Node: TTreeNode; Data: Pointer): Boolean of object;type  TCustomDriveView = class(TCustomTreeView)  protected    FParentForm: TCustomForm;    FDragFileList: TStringList;    FDragDropFilesEx: TCustomizableDragDropFilesEx;    FDragImageList: TDragImageList;    FDragDrive: string;    FExeDrag: Boolean;    FDDLinkOnExeDrag: Boolean;    FDragNode: TTreeNode;    FDragStartTime: FILETIME;    FDragPos: TPoint;    FStartPos: TPoint;    FContextMenu: Boolean;    FCanChange: Boolean;    FUseSystemContextMenu: Boolean;    FDimmHiddenDirs: Boolean;    FShowHiddenDirs: Boolean;    FNaturalOrderNumericalSorting: Boolean;    FDarkMode: Boolean;    FImageList: TImageList;    FScrollOnDragOver: TTreeViewScrollOnDragOver;    FRecreatingHandle: Boolean;    FOnDDDragEnter: TDDOnDragEnter;    FOnDDDragLeave: TDDOnDragLeave;    FOnDDDragOver: TDDOnDragOver;    FOnDDDrop: TDDOnDrop;    FOnDDQueryContinueDrag: TDDOnQueryContinueDrag;    FOnDDChooseEffect: TDDOnChooseEffect;    FOnDDGiveFeedback: TDDOnGiveFeedback;    FOnDDDragDetect: TDDOnDragDetect;    FOnDDProcessDropped: TOnProcessDropped;    FOnDDError: TDDErrorEvent;    FOnDDExecuted: TDDExecutedEvent;    FOnDDFileOperation: TDDFileOperationEvent;    FOnDDFileOperationExecuted: TDDFileOperationExecutedEvent;    FOnDDCreateDragFileList: TDDOnCreateDragFileList;    FOnDDEnd: TNotifyEvent;    FOnDDCreateDataObject: TDDOnCreateDataObject;    FLastDDResult: TDragResult;    FOnBusy: TDirViewBusy;    function GetTargetPopupMenu: Boolean;    procedure SetTargetPopUpMenu(Value: Boolean);    procedure SetDimmHiddenDirs(Value: Boolean);    procedure SetShowHiddenDirs(Value: Boolean);    procedure SetNaturalOrderNumericalSorting(Value: Boolean);    procedure SetDarkMode(Value: Boolean);    function GetDirectory: string; virtual;    procedure SetDirectory(Value: string); virtual;    function GetCustomDirView: TCustomDirView; virtual; abstract;    procedure SetCustomDirView(Value: TCustomDirView); virtual; abstract;    procedure CreateWnd; override;    procedure Notification(AComponent: TComponent; Operation: TOperation); override;    function GetNodeFromHItem(Item: TTVItem): TTreeNode;    function IsCustomDrawn(Target: TCustomDrawTarget; Stage: TCustomDrawStage): Boolean; override;    function CustomDrawItem(Node: TTreeNode; State: TCustomDrawState;      Stage: TCustomDrawStage; var PaintImages: Boolean): Boolean; override;    procedure NeedImageLists(Recreate: Boolean);    procedure DoCompare(Sender: TObject; Node1, Node2: TTreeNode; Data: Integer; var Compare: Integer);    function DoCompareText(Text1, Text2: string): Integer;    procedure UpdateItemHeight;    procedure CNNotify(var Msg: TWMNotify); message CN_NOTIFY;    procedure CMColorChanged(var Msg: TMessage); message CM_COLORCHANGED;    procedure CMRecreateWnd(var Msg: TMessage); message CM_RECREATEWND;    procedure WMLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN;    procedure WMLButtonUp(var Msg: TWMLButtonDown); message WM_LBUTTONUP;    procedure WMRButtonDown(var Msg: TWMRButtonDown); message WM_RBUTTONDOWN;    procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;    procedure WMContextMenu(var Msg: TWMContextMenu); message WM_CONTEXTMENU;    procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;    procedure CMDPIChanged(var Message: TMessage); message CM_DPICHANGED;    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;    procedure Delete(Node: TTreeNode); override;    procedure KeyDown(var Key: Word; Shift: TShiftState); override;    procedure KeyPress(var Key: Char); override;    procedure KeyUp(var Key: Word; Shift: TShiftState); override;    procedure InternalOnDrawItem(Sender: TCustomTreeView; Node: TTreeNode;      State: TCustomDrawState; var DefaultDraw: Boolean);    procedure DDDragEnter(DataObj: IDataObject; KeyState: Longint;      Point: TPoint; var Effect: Longint; var Accept: Boolean);    procedure DDDragLeave(Dummy: Integer);    procedure DDDragOver(KeyState: Longint; Point: TPoint; var Effect: Longint; PreferredEffect: LongInt);    procedure DDDrop(DataObj: IDataObject; KeyState: Longint; Point: TPoint;      var Effect: Longint);    procedure DDQueryContinueDrag(EscapePressed: BOOL; KeyState: Longint;      var Result: HResult);    procedure DDDropHandlerSucceeded(Sender: TObject; KeyState: Longint;      Point: TPoint; Effect: Longint);    procedure DDGiveFeedback(Effect: Longint; var Result: HResult);    procedure DDProcessDropped(Sender: TObject; KeyState: Longint;      Point: TPoint; Effect: Longint);    procedure DDError(Error: TDDError); virtual;    procedure DDSpecifyDropTarget(Sender: TObject; DragDropHandler: Boolean;      Point: TPoint; var PIDL: PItemIDList; var Filename: string);    procedure DDDragDetect(KeyState: Longint; DetectStart, Point: TPoint;      DragStatus: TDragDetectStatus); virtual;    procedure PerformDragDropFileOperation(Node: TTreeNode; Effect: Integer); virtual; abstract;    procedure DDChooseEffect(KeyState: Integer; var Effect: Integer; PreferredEffect: Integer); virtual;    function DragCompleteFileList: Boolean; virtual; abstract;    function DDExecute: TDragResult; virtual;    function DDSourceEffects: TDropEffectSet; virtual; abstract;    function NodePath(Node: TTreeNode): string; virtual; abstract;    function NodeIsRecycleBin(Node: TTreeNode): Boolean; virtual;    function NodePathExists(Node: TTreeNode): Boolean; virtual;    function NodeColor(Node: TTreeNode): TColor; virtual; abstract;    function NodeCanDrag(Node: TTreeNode): Boolean; virtual;    function NodeOverlayIndexes(Node: TTreeNode): Word; virtual;    function FindPathNode(Path: string): TTreeNode; virtual; abstract;    procedure ClearDragFileList(FileList: TFileList); virtual;    procedure AddToDragFileList(FileList: TFileList; Node: TTreeNode); virtual;    procedure ValidateDirectoryEx(Node: TTreeNode; Recurse: TRecursiveScan;      NewDirs: Boolean); virtual; abstract;    procedure RebuildTree; virtual; abstract;    procedure DisplayContextMenu(Node: TTreeNode; ScreenPos: TPoint); virtual; abstract;    procedure DisplayPropertiesMenu(Node: TTreeNode); virtual; abstract;    procedure ScrollOnDragOverBeforeUpdate(ObjectToValidate: TObject);    procedure ScrollOnDragOverAfterUpdate;    function DoBusy(Busy: Integer): Boolean;    function StartBusy: Boolean;    procedure EndBusy;    function IsBusy: Boolean;    property ImageList: TImageList read FImageList;  public    constructor Create(AOwner: TComponent); override;    destructor Destroy; override;    procedure ValidateDirectory(Node: TTreeNode);    function SortChildren(ParentNode: TTreeNode; Recurse: Boolean): Boolean;    function IterateSubTree(var StartNode : TTreeNode;      CallBackFunc: TCallBackFunc; Recurse: TRecursiveScan;      ScanStartNode: TScanStartNode; Data: Pointer): Boolean;    function NodePathName(Node: TTreeNode): string; virtual; abstract;    property DragDropFilesEx: TCustomizableDragDropFilesEx read FDragDropFilesEx;    property UseSystemContextMenu: Boolean read FUseSystemContextMenu      write FUseSystemContextMenu default True;    property DimmHiddenDirs: Boolean read FDimmHiddenDirs      write SetDimmHiddenDirs default False;    property ShowHiddenDirs: Boolean read FShowHiddenDirs      write SetShowHiddenDirs default False;    property NaturalOrderNumericalSorting: Boolean read FNaturalOrderNumericalSorting write SetNaturalOrderNumericalSorting;    property DarkMode: Boolean read FDarkMode write SetDarkMode;    property DDLinkOnExeDrag: Boolean read FDDLinkOnExeDrag write FDDLinkOnExeDrag default True;    {The mouse has entered the component window as a target of a drag&drop operation:}    property OnDDDragEnter: TDDOnDragEnter read FOnDDDragEnter write FOnDDDragEnter;    {The mouse has leaved the component window as a target of a drag&drop operation:}    property OnDDDragLeave: TDDOnDragLeave read FOnDDDragLeave write FOnDDDragLeave;    {The mouse is dragging in the component window as a target of a drag&drop operation:}    property OnDDDragOver: TDDOnDragOver read FOnDDDragOver write FOnDDDragOver;    {The Drag&drop operation is about to be executed:}    property OnDDDrop: TDDOnDrop read FOnDDDrop write FOnDDDrop;    property OnDDQueryContinueDrag: TDDOnQueryContinueDrag read FOnDDQueryContinueDrag write FOnDDQueryContinueDrag;    property OnDDChooseEffect: TDDOnChooseEffect read FOnDDChooseEffect write FOnDDChooseEffect;    property OnDDGiveFeedback: TDDOnGiveFeedback read FOnDDGiveFeedback write FOnDDGiveFeedback;    {A drag&drop operation is about to be initiated whith the components window as the source:}    property OnDDDragDetect: TDDOnDragDetect read FOnDDDragDetect write FOnDDDragDetect;    {The component window is the target of a drag&drop operation:}    property OnDDProcessDropped: TOnProcessDropped read FOnDDProcessDropped write FOnDDProcessDropped;    {An error has occurred during a drag&drop operation:}    property OnDDError: TDDErrorEvent read FOnDDError write FOnDDError;    {The drag&drop operation has been executed:}    property OnDDExecuted: TDDExecutedEvent read FOnDDExecuted write FOnDDExecuted;    {Event is fired just before executing the fileoperation. This event is also fired when     files are pasted from the clipboard:}    property OnDDFileOperation: TDDFileOperationEvent read FOnDDFileOperation write FOnDDFileOperation;    {Event is fired after executing the fileoperation. This event is also fired when     files are pasted from the clipboard:}    property OnDDFileOperationExecuted: TDDFileOperationExecutedEvent read FOnDDFileOperationExecuted write FOnDDFileOperationExecuted;    property OnDDCreateDragFileList: TDDOnCreateDragFileList      read FOnDDCreateDragFileList write FOnDDCreateDragFileList;    property OnDDEnd: TNotifyEvent      read FOnDDEnd write FOnDDEnd;    property OnDDCreateDataObject: TDDOnCreateDataObject      read FOnDDCreateDataObject write FOnDDCreateDataObject;    property OnBusy: TDirViewBusy read FOnBusy write FOnBusy;    { Show popupmenu when dropping a file with the right mouse button }    property TargetPopUpMenu: Boolean read GetTargetPopUpMenu write SetTargetPopUpMenu default True;    {Current selected directory:}    property Directory: string read GetDirectory write SetDirectory;    property DragNode: TTreeNode read FDragNode;    property LastDDResult: TDragResult read FLastDDResult;  end;implementationuses  SysUtils, ShellApi, ImgList, ActiveX, Math,  IEListView, BaseUtils;constructor TCustomDriveView.Create(AOwner: TComponent);begin  inherited;  DragMode := dmAutomatic;  FDragFileList := TStringList.Create;  FDragDrive := '';  FExeDrag := False;  FDDLinkOnExeDrag := True;  FContextMenu := False;  FCanChange := True;  FUseSystemContextMenu := True;  FNaturalOrderNumericalSorting := True;  FDarkMode := False;  FRecreatingHandle := False;  OnCompare := DoCompare;  FDragDropFilesEx := TCustomizableDragDropFilesEx.Create(Self);  with FDragDropFilesEx do  begin    AcceptOwnDnd := True;    {MP}    AutoDetectDnD := False;    {/MP}    BringToFront := True;    CompleteFileList := True;    NeedValid := [nvFileName];    RenderDataOn := rdoEnterAndDropSync;    TargetPopUpMenu := True;    OnDragEnter := DDDragEnter;    OnDragLeave := DDDragLeave;    OnDragOver := DDDragOver;    OnDrop := DDDrop;    OnQueryContinueDrag := DDQueryContinueDrag;    OnSpecifyDropTarget := DDSpecifyDropTarget;    OnDropHandlerSucceeded := DDDropHandlerSucceeded;    OnGiveFeedback := DDGiveFeedback;    OnProcessDropped := DDProcessDropped;    OnDragDetect := DDDragDetect;  end;  OnCustomDrawItem := InternalOnDrawItem;  FScrollOnDragOver := TTreeViewScrollOnDragOver.Create(Self, False);  FScrollOnDragOver.OnBeforeUpdate := ScrollOnDragOverBeforeUpdate;  FScrollOnDragOver.OnAfterUpdate := ScrollOnDragOverAfterUpdate;end;destructor TCustomDriveView.Destroy;begin  FreeAndNil(FScrollOnDragOver);  FreeAndNil(FImageList);  if Assigned(Images) then    Images.Free;  if Assigned(FDragImageList) then  begin    if GlobalDragImageList = FDragImageList then      GlobalDragImageList := nil;    FDragImageList.Free;  end;  FDragFileList.Destroy;  if Assigned(FDragDropFilesEx) then    FDragDropFilesEx.Free;  inherited Destroy;end;procedure TCustomDriveView.UpdateItemHeight;var  ImageHeight: Integer;  TextHeight: Integer;begin  // Particularly when called from CMFontChanged because we are changing (reverting)  // the default form font, the Images might not be set up yet  if Assigned(Images) then    ImageHeight := (Images.Width * 9) div 8  else    ImageHeight := 0;  // 16 seems to be the system default tree view item height  TextHeight := ScaleByControlTextHeightRunTime(Canvas, 16);  TreeView_SetItemHeight(Handle, Max(ImageHeight, TextHeight));end;procedure TCustomDriveView.CMFontChanged(var Message: TMessage);begin  inherited;  UpdateItemHeight;end;procedure TCustomDriveView.NeedImageLists(Recreate: Boolean);var  AImages: TImageList;begin  if not Assigned(Images) then  begin    Images := TImageList.Create(Self);    Images.BkColor := Color;  end;  AImages := ShellImageListForControl(Self, ilsSmall);  if Images.Handle <> AImages.Handle then  begin    Images.Handle := AImages.Handle;  end;  if (not Assigned(FImageList)) or Recreate then  begin    if Assigned(FImageList) then      FImageList.Free;    FImageList := OverlayImageList(Images.Width);  end;  UpdateItemHeight;end;procedure TCustomDriveView.CMDPIChanged(var Message: TMessage);begin  inherited;  NeedImageLists(True);end;procedure TCustomDriveView.CreateWnd;begin  inherited;  if DarkMode then AllowDarkModeForWindow(Self, DarkMode);  NeedImageLists(False);  if not (csDesigning in ComponentState) then    FDragImageList := TDragImageList.Create(Self);  if not Assigned(GlobalDragImageList) then    GlobalDragImageList := FDragImageList;  FDragDropFilesEx.DragDropControl := Self;  FParentForm := GetParentForm(Self);end;procedure TCustomDriveView.Notification(AComponent: TComponent; Operation: TOperation);begin  inherited;  if Operation = opRemove then  begin    if AComponent = GetCustomDirView then SetCustomDirView(nil);  end;end;procedure TCustomDriveView.InternalOnDrawItem(Sender: TCustomTreeView; Node: TTreeNode;  State: TCustomDrawState; var DefaultDraw: Boolean);var  FItemColor: TColor;begin  if Assigned(Node) and Assigned(Node.Data) and (Node <> DropTarget) then  begin    if not Node.Selected then    begin      FItemColor := NodeColor(Node);      if (FItemColor <> clDefaultItemColor) and         (Canvas.Font.Color <> FItemColor) then           Canvas.Font.Color := FItemColor;    end      else    if (not Self.Focused) and HideSelection then    begin      Canvas.Brush.Color := clBtnFace;      Canvas.Font.Color := clBtnText;    end      else    if Node.Selected and (not Self.Focused) and DarkMode then    begin      Canvas.Font.Color := Font.Color;    end;  end;end; {InternalOnDrawItem}procedure TCustomDriveView.ScrollOnDragOverBeforeUpdate(ObjectToValidate: TObject);var  NodeToValidate: TTreeNode;begin  GlobalDragImageList.HideDragImage;  if Assigned(ObjectToValidate) then  begin    NodeToValidate := (ObjectToValidate as TTreeNode);    if not NodeToValidate.HasChildren then      ValidateDirectory(NodeToValidate);  end;end;procedure TCustomDriveView.ScrollOnDragOverAfterUpdate;begin  GlobalDragImageList.ShowDragImage;end;procedure TCustomDriveView.DDDragEnter(DataObj: IDataObject; KeyState: Longint;  Point: TPoint; var Effect: Longint; var Accept: Boolean);var  Index: Integer;begin  if (FDragDropFilesEx.FileList.Count > 0) and     (Length(TFDDListItem(FDragDropFilesEx.FileList[0]^).Name) > 0) Then  begin    try      FDragDrive := DriveInfo.GetDriveKey(TFDDListItem(FDragDropFilesEx.FileList[0]^).Name);    except      // WinRAR gives us only filename on "enter", we get a full path only on "drop".      FDragDrive := '';    end;    FExeDrag := FDDLinkOnExeDrag and      (deLink in DragDropFilesEx.TargetEffects) and      ((DragDropFilesEx.AvailableDropEffects and DROPEFFECT_LINK) <> 0);    if FExeDrag then    begin      for Index := 0 to FDragDropFilesEx.FileList.Count - 1 do        if not IsExecutable(TFDDListItem(FDragDropFilesEx.FileList[Index]^).Name) then        begin          FExeDrag := False;          Break;        end;    end;  end    else  begin    FDragDrive := '';  end;  FScrollOnDragOver.StartDrag;  if Assigned(FOnDDDragEnter) then    FOnDDDragEnter(Self, DataObj, KeyState, Point, Effect, Accept);end; {DDDragEnter}procedure TCustomDriveView.DDDragLeave(Dummy: Integer);begin  if Assigned(DropTarget) then  begin    if GlobalDragImageList.Dragging then      GlobalDragImageList.HideDragImage;    DropTarget := nil;    Update;  end;  if Assigned(FOnDDDragLeave) then    FOnDDDragLeave(Self);end; {DragLeave}procedure TCustomDriveView.DDDragOver(KeyState: Longint; Point: TPoint; var Effect: Longint; PreferredEffect: Longint);var  Node: TTreeNode;  Rect1: TRect;  UpdateImage: Boolean;  LastDragNode: TTreeNode;begin  if Effect <> DROPEFFECT_NONE then  begin    Node := GetNodeAt(Point.X, Point.Y);    if Assigned(Node) then    begin      LastDragNode := DropTarget;      UpdateImage := False;      if GlobalDragImageList.Dragging and (LastDragNode <> Node) then      begin        if Assigned(LastDragNode) then        begin          Rect1 := LastDragNode.DisplayRect(True);          if Rect1.Right >= Point.x - GlobalDragImageList.GetHotSpot.X then          begin            GlobalDragImageList.HideDragImage;            UpdateImage := True;          end            else          begin            Rect1 := Node.DisplayRect(True);            if Rect1.Right >= Point.x - GlobalDragImageList.GetHotSpot.X then            begin              GlobalDragImageList.HideDragImage;              UpdateImage := True;            end          end;        end          else        begin          {LastDragNode not assigned:}          GlobalDragImageList.HideDragImage;          UpdateImage := True;        end;      end;      DropTarget := Node;      if UpdateImage then        GlobalDragImageList.ShowDragImage;      {Drop-operation allowed at this location?}      if Assigned(FDragNode) and         (Effect <> DROPEFFECT_LINK) and         ((Node = FDragNode) or Node.HasAsParent(FDragNode) or (FDragNode.Parent = Node)) then         Effect := DROPEFFECT_NONE;      FScrollOnDragOver.DragOver(Point);    end {Assigned(Node)}      else    begin      DropTarget := nil;    end;  end;  DDChooseEffect(KeyState, Effect, PreferredEffect);  if Assigned(FOnDDDragOver) then    FOnDDDragOver(Self, KeyState, Point, Effect);  if not Assigned(DropTarget) then Effect := DROPEFFECT_NONE    else  if NodeIsRecycleBin(DropTarget) then  begin    if FDragDropFilesEx.FileNamesAreMapped then Effect := DROPEFFECT_NONE      else Effect := DROPEFFECT_MOVE;  end;end; {DDDragOver}procedure TCustomDriveView.DDDrop(DataObj: IDataObject; KeyState: Longint;  Point: TPoint; var Effect: Longint);begin  if GlobalDragImageList.Dragging then    GlobalDragImageList.HideDragImage;  if Effect = DROPEFFECT_NONE then    DropTarget := nil;  if Assigned(FOnDDDrop) then    FOnDDDrop(Self, DataObj, KeyState, Point, Effect);end; {DDDrop}procedure TCustomDriveView.DDQueryContinueDrag(EscapePressed: BOOL; KeyState: Longint;  var Result: HResult);var  Point: TPoint;  ClientPoint: TPoint;  KnowTime: FILETIME;begin  if Result = DRAGDROP_S_DROP then  begin    GetSystemTimeAsFileTime(KnowTime);    if ((Int64(KnowTime) - Int64(FDragStartTime)) <= DDDragStartDelay) then      Result := DRAGDROP_S_CANCEL;  end;  if Assigned(FOnDDQueryContinueDrag) then    FOnDDQueryContinueDrag(Self, EscapePressed, KeyState, Result);  if EscapePressed then  begin    if GlobalDragImageList.Dragging then      GlobalDragImageList.HideDragImage;    DropTarget := nil;  end    else  begin    if GlobalDragImageList.Dragging then    begin      GetCursorPos(Point);      {Convert screen coordinates to the parentforms coordinates:}      ClientPoint := FParentForm.ScreenToClient(Point);      {Move the drag image to the new position and show it:}      if not CompareMem(@ClientPoint, @FDragPos, SizeOf(TPoint)) then      begin        FDragPos := ClientPoint;        if PtInRect(FParentForm.BoundsRect, Point) then        begin          GlobalDragImageList.DragMove(ClientPoint.X, ClientPoint.Y);          GlobalDragImageList.ShowDragImage;        end          else GlobalDragImageList.HideDragImage;      end;    end;  end;end; {DDQueryContinueDrag}procedure TCustomDriveView.DDDropHandlerSucceeded(Sender: TObject;  KeyState: Integer; Point: TPoint; Effect: Integer);begin  DropTarget := nil;end;procedure TCustomDriveView.DDChooseEffect(KeyState: Integer; var Effect: Integer; PreferredEffect: Integer);begin  if Assigned(FOnDDChooseEffect) then    FOnDDChooseEffect(Self, KeyState, Effect);end;procedure TCustomDriveView.DDGiveFeedback(Effect: Longint; var Result: HResult);begin  if Assigned(FOnDDGiveFeedback) then    FOnDDGiveFeedback(Self, Effect, Result);end; {DDGiveFeedback}procedure TCustomDriveView.DDProcessDropped(Sender: TObject; KeyState: Longint;  Point: TPoint; Effect: Longint);begin  try    if Assigned(DropTarget) then    try      if NodePathExists(DropTarget) then      begin        if Assigned(FOnDDProcessDropped) then          FOnDDProcessDropped(Self, KeyState, Point, Effect);        if Effect <> DROPEFFECT_NONE then        begin          PerformDragDropFileOperation(DropTarget, Effect);          if Assigned(FOnDDExecuted) then            FOnDDExecuted(Self, Effect);        end;      end        else      begin        ValidateDirectory(DropTarget);        DDError(DDPathNotFoundError);      end;    finally      DropTarget := nil;      ClearDragFileList(FDragDropFilesEx.FileList);    end;  except    Application.HandleException(Self);  end;end; {ProcessDropped}procedure TCustomDriveView.DDError(Error: TDDError);begin  if Assigned(FOnDDError) then FOnDDError(Self, Error)    else raise Exception.CreateFmt(SDragDropError, [Ord(Error)]);end; {DDError}procedure TCustomDriveView.DDSpecifyDropTarget(Sender: TObject;  DragDropHandler: Boolean; Point: TPoint; var PIDL: PItemIDList; var Filename: string);begin  PIDL := nil;  if DragDropHandler and Assigned(DropTarget) then FileName := NodePathName(DropTarget)    else FileName := EmptyStr;end; {DDSpecifyDropTarget}procedure TCustomDriveView.DDDragDetect(KeyState: Longint; DetectStart, Point: TPoint;  DragStatus: TDragDetectStatus);var  P: TPoint;  ImageList: HImageList;  NodeRect: TRect;  FileListCreated: Boolean;  AvoidDragImage: Boolean;begin  if (DragStatus = ddsDrag) and (not Assigned(FDragNode)) then  begin    P := ScreenToClient(FStartPos);    FDragNode := GetNodeAt(P.X, P.Y);  end;  if Assigned(FOnDDDragDetect) then    FOnDDDragDetect(Self, KeyState, DetectStart, Point, DragStatus);  if (DragStatus = ddsDrag) and Assigned(FDragNode) then  begin    NodeRect := FDragNode.DisplayRect(True);    Dec(NodeRect.Left, 16);    {Check, wether the mouse cursor was within the nodes display rectangle:}    if (NodeRect.Left > P.X) or (NodeRect.Right < P.X) or       (not NodeCanDrag(FDragNode)) then    begin      FDragNode := nil;      Exit;    end;    FDragDrive := '';    ClearDragFileList(FDragDropFilesEx.FileList);    FDragDropFilesEx.CompleteFileList := DragCompleteFileList;    FileListCreated := False;    AvoidDragImage := False;    if Assigned(OnDDCreateDragFileList) then    begin      OnDDCreateDragFileList(Self, FDragDropFilesEx.FileList, FileListCreated);      if FileListCreated then        AvoidDragImage := True;    end;    if not FileListCreated then    begin      AddToDragFileList(FDragDropFilesEx.FileList, FDragNode);    end;    FDragDropFilesEx.SourceEffects := DDSourceEffects;    if FDragDropFilesEx.FileList.Count > 0 then    try      {Create the dragimage:}      GlobalDragImageList := FDragImageList;      if not AvoidDragImage then      begin        {Hide the selection mark to get a proper dragimage:}        if Selected = FDragNode then          Selected := nil;        ImageList := TreeView_CreateDragImage(Handle, FDragNode.ItemID);        {Show the selection mark if it was hidden:}        if not Assigned(Selected) then          Selected := FDragNode;        if ImageList <> Invalid_Handle_Value then        begin          GlobalDragImageList.Handle := ImageList;          GlobalDragImageList.SetDragImage(0, P.X - NodeRect.TopLeft.X, P.Y - NodeRect.TopLeft.Y);          P := FParentForm.ScreenToClient(Point);          GlobalDragImageList.BeginDrag(FParentForm.Handle, P.X, P.Y);          GlobalDragImageList.HideDragImage;          ShowCursor(True);        end;      end;      DropSourceControl := Self;      GetSystemTimeAsFileTime(FDragStartTime);      {Supress the context menu:}      FContextMenu := False;      {Execute the drag&drop-Operation:}      FLastDDResult := DDExecute;      {the drag&drop operation is finished, so clean up the used drag image:}      GlobalDragImageList.EndDrag;      GlobalDragImageList.Clear;      Application.ProcessMessages;    finally      ClearDragFileList(FDragDropFilesEx.FileList);      FDragDrive := '';      DropTarget := nil;      try        if Assigned(OnDDEnd) then          OnDDEnd(Self);      finally        DropSourceControl := nil;        FDragNode := nil;      end;    end;  end;end; {(DDDragDetect}function TCustomDriveView.DDExecute: TDragResult;var  DataObject: TDataObject;begin  DataObject := nil;  if Assigned(OnDDCreateDataObject) then    OnDDCreateDataObject(Self, DataObject);  Result := FDragDropFilesEx.Execute(DataObject);end;function TCustomDriveView.GetNodeFromHItem(Item: TTVItem): TTreeNode;begin  Result := nil;  if Items <> nil then    with Item do      if (state and TVIF_PARAM) <> 0 then        Result := Pointer(lParam)      else        Result := Items.GetNode(hItem);end; {GetNodeFromItem}function TCustomDriveView.IsCustomDrawn(Target: TCustomDrawTarget;  Stage: TCustomDrawStage): Boolean;begin  Result := inherited IsCustomDrawn(Target, Stage) or    ((Target = dtItem) and (Stage = cdPostPaint));end;function TCustomDriveView.CustomDrawItem(Node: TTreeNode; State: TCustomDrawState;  Stage: TCustomDrawStage; var PaintImages: Boolean): Boolean;var  Point: TPoint;  Index: Integer;  OverlayIndexes: Word;  OverlayIndex: Word;  Image: Word;begin  Result := inherited CustomDrawItem(Node, State, Stage, PaintImages);  if Result and (Stage = cdPostPaint) then  begin    Assert(Assigned(Node));    OverlayIndexes := NodeOverlayIndexes(Node);    OverlayIndex := 1;    while OverlayIndexes > 0 do    begin      if (OverlayIndex and OverlayIndexes) <> 0 then      begin        Index := 0;        Image := OverlayIndex;        while Image > 1 do        begin          Inc(Index);          Image := Image shr 1;        end;        Point := Node.DisplayRect(True).TopLeft;        Dec(Point.X, Indent);        ImageList_Draw(ImageList.Handle, Index, Self.Canvas.Handle,          Point.X, Point.Y, ILD_TRANSPARENT);        Dec(OverlayIndexes, OverlayIndex);      end;      OverlayIndex := OverlayIndex shl 1;    end;  end;end;procedure TCustomDriveView.CNNotify(var Msg: TWMNotify);begin  case Msg.NMHdr.code of    TVN_BEGINDRAG:  DDDragDetect(MK_LBUTTON, FStartPos, Mouse.CursorPos, ddsDrag);    TVN_BEGINRDRAG: DDDragDetect(MK_RBUTTON, FStartPos, Mouse.CursorPos, ddsDrag);  else    inherited;  end;end; {CNNotify}procedure TCustomDriveView.CMColorChanged(var Msg: TMessage);begin  inherited;  if Assigned(Images) then    Images.BkColor := Color;  ForceColorChange(Self);end;procedure TCustomDriveView.WMLButtonDown(var Msg: TWMLButtonDown);begin  if not IsBusy then  begin    FCanChange := False;    GetCursorPos(FStartPos);    inherited;  end;end; {WMLButtonDown}procedure TCustomDriveView.WMLButtonUp(var Msg: TWMLButtonDown);begin  FCanChange := True;  if Assigned(DropTarget) and Assigned(DropTarget.Data) then    Selected := DropTarget;  DropTarget := nil;  inherited;end; {WMLButtonUp}procedure TCustomDriveView.WMRButtonDown(var Msg: TWMRButtonDown);begin  if not IsBusy then  begin    GetCursorPos(FStartPos);    if FDragDropFilesEx.DragDetectStatus <> ddsDrag then      FContextMenu := True;    inherited;  end;end; {WMRButtonDown}procedure TCustomDriveView.WMLButtonDblClk(var Message: TWMLButtonDblClk);begin  if not IsBusy then  begin    inherited;  end;end;procedure TCustomDriveView.WMContextMenu(var Msg: TWMContextMenu);var  Node: TTreeNode;  Point: TPoint;  PrevAutoPopup: Boolean;begin  PrevAutoPopup := False;  try    if Assigned(PopupMenu) then    begin      PrevAutoPopup := PopupMenu.AutoPopup;      PopupMenu.AutoPopup := False;    end;    inherited;  finally    if Assigned(PopupMenu) then      PopupMenu.AutoPopup := PrevAutoPopup;  end;  FStartPos.X := -1;  FStartPos.Y := -1;  try    if FContextMenu then    begin      Point.X := Msg.XPos;      Point.Y := Msg.YPos;      Point := ScreenToClient(Point);      Node := GetNodeAt(Point.X, Point.Y);      if FUseSystemContextMenu and Assigned(Node) then      begin        if Assigned(OnMouseDown) then          OnMouseDown(Self, mbRight, [], Msg.XPos, Msg.YPos);        DisplayContextMenu(Node, Mouse.CursorPos);      end        else      begin        if Assigned(PopupMenu) then          PopupMenu.Popup(Msg.XPos, Msg.YPos);      end;    end;    FContextMenu := False;  finally    DropTarget := nil;  end;end; {WMContextMenu}procedure TCustomDriveView.CMRecreateWnd(var Msg: TMessage);var  HadHandle: Boolean;begin  HadHandle := HandleAllocated;  inherited;  // If the control is not showing (e.g. because the machine is locked), the handle is not recreated.  // If contents is reloaded (LoadPath) without handle allocated, it crashes  // (as the handle is implicitly created somewhere in the middle of the reload and chaos ensures).  if HadHandle then  begin    Assert(not FRecreatingHandle);    FRecreatingHandle := True;    try      HandleNeeded;    finally      FRecreatingHandle := False;    end;  end;end;procedure TCustomDriveView.Delete(Node: TTreeNode);begin  if Node = FDragNode then    FDragNode := nil;  if Node = DropTarget then  begin    DropTarget := nil;    Update;  end;  inherited;end; {OnDelete}procedure TCustomDriveView.WMKeyDown(var Message: TWMKeyDown);begin  if not IsBusy then  begin    inherited;  end;end;procedure TCustomDriveView.KeyDown(var Key: Word; Shift: TShiftState);begin  if (Key = VK_RETURN) and (ssAlt in Shift) and (not IsEditing) and     Assigned(Selected) then  begin    DisplayPropertiesMenu(Selected);    Key := 0;  end;  inherited;end; {KeyDown}procedure TCustomDriveView.KeyPress(var Key : Char);begin  if Assigned(Selected) then  begin    if not IsEditing then    begin      case Key of        #13, ' ':          begin            Selected.Expanded := not Selected.Expanded;            Key := #0;          end;        '/':          begin            Selected.Collapse(True);            Selected.MakeVisible;            Key := #0;          end;        '*':          Selected.MakeVisible;      end {Case}    end  end;  inherited;end; {KeyPress}procedure TCustomDriveView.KeyUp(var Key: Word; Shift: TShiftState);var  Point: TPoint;begin  inherited;  if (Key = VK_APPS) and Assigned(Selected) then  begin    Point := ClientToScreen(Selected.DisplayRect(True).TopLeft);    Inc(Point.Y, 20);    DisplayContextMenu(Selected, Point);  end;end; {KeyUp}procedure TCustomDriveView.ValidateDirectory(Node: TTreeNode);begin  ValidateDirectoryEx(Node, rsRecursiveExisting, False);end;  {ValidateDirectory}function TCustomDriveView.DoCompareText(Text1, Text2: string): Integer;begin  Result := CompareLogicalTextPas(Text1, Text2, NaturalOrderNumericalSorting);end;procedure TCustomDriveView.DoCompare(Sender: TObject; Node1, Node2: TTreeNode; Data: Integer; var Compare: Integer);begin  Compare := DoCompareText(Node1.Text, Node2.Text);end;function TCustomDriveView.SortChildren(ParentNode: TTreeNode; Recurse: Boolean): Boolean;begin  Result := Assigned(ParentNode) and ParentNode.AlphaSort(Recurse);end; {SortChildren}function TCustomDriveView.IterateSubTree(var StartNode : TTreeNode;  CallBackFunc: TCallBackFunc; Recurse: TRecursiveScan;  ScanStartNode: TScanStartNode; Data: Pointer): Boolean;  function ScanSubTree(var StartNode: TTreeNode): Boolean;  var    Node: TTreeNode;    NextNode: TTreeNode;    NodeHasChilds: Boolean;  begin    Result := False;    if not Assigned(StartNode) then Exit;    Node := StartNode.GetFirstChild;    while Assigned(Node) do    begin      NextNode := StartNode.GetNextChild(Node);      NodeHasChilds := Node.HasChildren;      if not CallBackFunc(Node, Data) then Exit;      if Assigned(Node) and         (Recurse = rsRecursiveExisting) and NodeHasChilds then      begin        if not ScanSubTree(Node) then Exit;      end;      Node := NextNode;    end;    Result := True;  end; {ScanSubTree}begin {IterateSubTree}  Result := False;  if Assigned(CallBackFunc) then  begin    if ScanStartNode = coScanStartNode then    begin      CallBackFunc(StartNode, Data);    end;    if (not Assigned(StartNode)) or       ScanSubTree(StartNode) then    begin      Result := True;    end;  end;end; {IterateSubTree}procedure TCustomDriveView.ClearDragFileList(FileList: TFileList);begin  FileList.Clear;end;procedure TCustomDriveView.AddToDragFileList(FileList: TFileList; Node: TTreeNode);begin  FileList.AddItem(nil, NodePathName(Node));end;function TCustomDriveView.NodeCanDrag(Node: TTreeNode): Boolean;begin  Result := True;end;function TCustomDriveView.NodeOverlayIndexes(Node: TTreeNode): Word;begin  Result := oiNoOverlay;end;function TCustomDriveView.NodeIsRecycleBin(Node: TTreeNode): Boolean;begin  Result := False;end;function TCustomDriveView.NodePathExists(Node: TTreeNode): Boolean;begin  Result := True;end;procedure TCustomDriveView.SetDimmHiddenDirs(Value: Boolean);begin  if Value <> FDimmHiddenDirs then  begin    FDimmHiddenDirs := Value;    Self.Invalidate;  end;end; {SetDimmHiddenDirs}procedure TCustomDriveView.SetShowHiddenDirs(Value: Boolean);begin  if Value <> FShowHiddenDirs then  begin    FShowHiddenDirs := Value;    RebuildTree;  end;end; {SetDimmHiddenDirs}procedure TCustomDriveView.SetNaturalOrderNumericalSorting(Value: Boolean);begin  if NaturalOrderNumericalSorting <> Value then  begin    FNaturalOrderNumericalSorting := Value;    AlphaSort;  end;end;procedure TCustomDriveView.SetDarkMode(Value: Boolean);begin  if DarkMode <> Value then  begin    FDarkMode := Value;    // See TCustomDirView.SetDarkMode    if HandleAllocated then AllowDarkModeForWindow(Self, DarkMode);  end;end;function TCustomDriveView.GetTargetPopupMenu: Boolean;begin  if Assigned(FDragDropFilesEx) then Result := FDragDropFilesEx.TargetPopupMenu    else Result := True;end;procedure TCustomDriveView.SetTargetPopUpMenu(Value: Boolean);begin  if Assigned(FDragDropFilesEx) then    FDragDropFilesEx.TargetPopupMenu := Value;end; {SetTargetPopUpMenu}function TCustomDriveView.GetDirectory: string;begin  if Assigned(Selected) then Result := NodePathName(Selected)    else Result := '';end; {GetDirectory}procedure TCustomDriveView.SetDirectory(Value: string);var  NewSelected: TTreeNode;begin  NewSelected := FindPathNode(Value);  if Assigned(NewSelected) and (NewSelected <> Selected) then  begin    FCanChange := True;    NewSelected.MakeVisible;    Selected := NewSelected;  end    else  if csDesigning in ComponentState then    Selected := nil;end; {SetDirectory}function TCustomDriveView.DoBusy(Busy: Integer): Boolean;begin  Result := True;  if Assigned(OnBusy) then  begin    OnBusy(Self, Busy, Result);  end;end;function TCustomDriveView.StartBusy: Boolean;begin  Result := DoBusy(1);end;function TCustomDriveView.IsBusy: Boolean;begin  Result := DoBusy(0);end;procedure TCustomDriveView.EndBusy;begin  DoBusy(-1);end;end.
 |