CustomDriveView.pas 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. unit CustomDriveView;
  2. interface
  3. uses
  4. Classes, ComCtrls, CommCtrl, Windows, Controls, Forms, ShlObj, Messages,
  5. Graphics,
  6. DragDrop, CustomDirView, IEDriveInfo, DragDropFilesEx, PasTools;
  7. type
  8. {Types uses by the function IterateSubTree:}
  9. {TRecursiveScan: determines, wich nodes are scanned by the function IterateSubTree:
  10. rsNoRecursive: Scan startnode only.
  11. rsRecursiveExisting: Scan all subnodes of the startnode but not new created subnodes.}
  12. TRecursiveScan = (rsNoRecursive, rsRecursiveExisting);
  13. {TScanStartnode: determines, wether the startnode should also be scanned:}
  14. TScanStartNode = (coNoScanStartNode, coScanStartNode);
  15. TCallBackFunc = function(var Node: TTreeNode; Data: Pointer): Boolean of object;
  16. type
  17. TCustomDriveView = class(TCustomTreeView)
  18. protected
  19. FParentForm: TCustomForm;
  20. FDragFileList: TStringList;
  21. FDragDropFilesEx: TCustomizableDragDropFilesEx;
  22. FDragImageList: TDragImageList;
  23. FDragDrive: string;
  24. FExeDrag: Boolean;
  25. FDDLinkOnExeDrag: Boolean;
  26. FDragNode: TTreeNode;
  27. FDragStartTime: FILETIME;
  28. FDragPos: TPoint;
  29. FStartPos: TPoint;
  30. FContextMenu: Boolean;
  31. FCanChange: Boolean;
  32. FUseSystemContextMenu: Boolean;
  33. FDimmHiddenDirs: Boolean;
  34. FShowHiddenDirs: Boolean;
  35. FNaturalOrderNumericalSorting: Boolean;
  36. FDarkMode: Boolean;
  37. FContinue: Boolean;
  38. FImageList: TImageList;
  39. FScrollOnDragOver: TTreeViewScrollOnDragOver;
  40. FRecreatingHandle: Boolean;
  41. FOnDDDragEnter: TDDOnDragEnter;
  42. FOnDDDragLeave: TDDOnDragLeave;
  43. FOnDDDragOver: TDDOnDragOver;
  44. FOnDDDrop: TDDOnDrop;
  45. FOnDDQueryContinueDrag: TDDOnQueryContinueDrag;
  46. FOnDDChooseEffect: TDDOnChooseEffect;
  47. FOnDDGiveFeedback: TDDOnGiveFeedback;
  48. FOnDDDragDetect: TDDOnDragDetect;
  49. FOnDDProcessDropped: TOnProcessDropped;
  50. FOnDDError: TDDErrorEvent;
  51. FOnDDExecuted: TDDExecutedEvent;
  52. FOnDDFileOperation: TDDFileOperationEvent;
  53. FOnDDFileOperationExecuted: TDDFileOperationExecutedEvent;
  54. FOnDDCreateDragFileList: TDDOnCreateDragFileList;
  55. FOnDDEnd: TNotifyEvent;
  56. FOnDDCreateDataObject: TDDOnCreateDataObject;
  57. FLastDDResult: TDragResult;
  58. FOnBusy: TDirViewBusy;
  59. function GetTargetPopupMenu: Boolean;
  60. procedure SetTargetPopUpMenu(Value: Boolean);
  61. procedure SetDimmHiddenDirs(Value: Boolean);
  62. procedure SetShowHiddenDirs(Value: Boolean);
  63. procedure SetNaturalOrderNumericalSorting(Value: Boolean);
  64. procedure SetDarkMode(Value: Boolean);
  65. function GetDirectory: string; virtual;
  66. procedure SetDirectory(Value: string); virtual;
  67. function GetCustomDirView: TCustomDirView; virtual; abstract;
  68. procedure SetCustomDirView(Value: TCustomDirView); virtual; abstract;
  69. procedure CreateWnd; override;
  70. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  71. function GetNodeFromHItem(Item: TTVItem): TTreeNode;
  72. function IsCustomDrawn(Target: TCustomDrawTarget; Stage: TCustomDrawStage): Boolean; override;
  73. function CustomDrawItem(Node: TTreeNode; State: TCustomDrawState;
  74. Stage: TCustomDrawStage; var PaintImages: Boolean): Boolean; override;
  75. procedure NeedImageLists(Recreate: Boolean);
  76. procedure DoCompare(Sender: TObject; Node1, Node2: TTreeNode; Data: Integer; var Compare: Integer);
  77. function DoCompareText(Text1, Text2: string): Integer;
  78. procedure CNNotify(var Msg: TWMNotify); message CN_NOTIFY;
  79. procedure CMColorChanged(var Msg: TMessage); message CM_COLORCHANGED;
  80. procedure CMRecreateWnd(var Msg: TMessage); message CM_RECREATEWND;
  81. procedure WMLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN;
  82. procedure WMLButtonUp(var Msg: TWMLButtonDown); message WM_LBUTTONUP;
  83. procedure WMRButtonDown(var Msg: TWMRButtonDown); message WM_RBUTTONDOWN;
  84. procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
  85. procedure WMContextMenu(var Msg: TWMContextMenu); message WM_CONTEXTMENU;
  86. procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
  87. procedure CMDPIChanged(var Message: TMessage); message CM_DPICHANGED;
  88. procedure Delete(Node: TTreeNode); override;
  89. procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  90. procedure KeyPress(var Key: Char); override;
  91. procedure KeyUp(var Key: Word; Shift: TShiftState); override;
  92. procedure InternalOnDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
  93. State: TCustomDrawState; var DefaultDraw: Boolean);
  94. procedure DDDragEnter(DataObj: IDataObject; KeyState: Longint;
  95. Point: TPoint; var Effect: Longint; var Accept: Boolean);
  96. procedure DDDragLeave;
  97. procedure DDDragOver(KeyState: Longint; Point: TPoint; var Effect: Longint; PreferredEffect: LongInt);
  98. procedure DDDrop(DataObj: IDataObject; KeyState: Longint; Point: TPoint;
  99. var Effect: Longint);
  100. procedure DDQueryContinueDrag(EscapePressed: BOOL; KeyState: Longint;
  101. var Result: HResult);
  102. procedure DDDropHandlerSucceeded(Sender: TObject; KeyState: Longint;
  103. Point: TPoint; Effect: Longint);
  104. procedure DDGiveFeedback(Effect: Longint; var Result: HResult);
  105. procedure DDProcessDropped(Sender: TObject; KeyState: Longint;
  106. Point: TPoint; Effect: Longint);
  107. procedure DDError(Error: TDDError); virtual;
  108. procedure DDSpecifyDropTarget(Sender: TObject; DragDropHandler: Boolean;
  109. Point: TPoint; var PIDL: PItemIDList; var Filename: string);
  110. procedure DDDragDetect(KeyState: Longint; DetectStart, Point: TPoint;
  111. DragStatus: TDragDetectStatus); virtual;
  112. procedure PerformDragDropFileOperation(Node: TTreeNode; Effect: Integer); virtual; abstract;
  113. procedure DDChooseEffect(KeyState: Integer; var Effect: Integer; PreferredEffect: Integer); virtual;
  114. function DragCompleteFileList: Boolean; virtual; abstract;
  115. function DDExecute: TDragResult; virtual;
  116. function DDSourceEffects: TDropEffectSet; virtual; abstract;
  117. function NodePath(Node: TTreeNode): string; virtual; abstract;
  118. function NodeIsRecycleBin(Node: TTreeNode): Boolean; virtual;
  119. function NodePathExists(Node: TTreeNode): Boolean; virtual;
  120. function NodeColor(Node: TTreeNode): TColor; virtual; abstract;
  121. function NodeCanDrag(Node: TTreeNode): Boolean; virtual;
  122. function NodeOverlayIndexes(Node: TTreeNode): Word; virtual;
  123. function FindPathNode(Path: string): TTreeNode; virtual; abstract;
  124. procedure ClearDragFileList(FileList: TFileList); virtual;
  125. procedure AddToDragFileList(FileList: TFileList; Node: TTreeNode); virtual;
  126. procedure ValidateDirectoryEx(Node: TTreeNode; Recurse: TRecursiveScan;
  127. NewDirs: Boolean); virtual; abstract;
  128. procedure RebuildTree; virtual; abstract;
  129. procedure DisplayContextMenu(Node: TTreeNode; ScreenPos: TPoint); virtual; abstract;
  130. procedure DisplayPropertiesMenu(Node: TTreeNode); virtual; abstract;
  131. procedure ScrollOnDragOverBeforeUpdate(ObjectToValidate: TObject);
  132. procedure ScrollOnDragOverAfterUpdate;
  133. function DoBusy(Busy: Integer): Boolean;
  134. function StartBusy: Boolean;
  135. procedure EndBusy;
  136. function IsBusy: Boolean;
  137. property ImageList: TImageList read FImageList;
  138. public
  139. constructor Create(AOwner: TComponent); override;
  140. destructor Destroy; override;
  141. procedure ValidateDirectory(Node: TTreeNode);
  142. procedure CenterNode(Node: TTreeNode); virtual;
  143. function SortChildren(ParentNode: TTreeNode; Recurse: Boolean): Boolean;
  144. function IterateSubTree(var StartNode : TTreeNode;
  145. CallBackFunc: TCallBackFunc; Recurse: TRecursiveScan;
  146. ScanStartNode: TScanStartNode; Data: Pointer): Boolean;
  147. function NodePathName(Node: TTreeNode): string; virtual; abstract;
  148. property DragDropFilesEx: TCustomizableDragDropFilesEx read FDragDropFilesEx;
  149. property UseSystemContextMenu: Boolean read FUseSystemContextMenu
  150. write FUseSystemContextMenu default True;
  151. property DimmHiddenDirs: Boolean read FDimmHiddenDirs
  152. write SetDimmHiddenDirs default False;
  153. property ShowHiddenDirs: Boolean read FShowHiddenDirs
  154. write SetShowHiddenDirs default False;
  155. property NaturalOrderNumericalSorting: Boolean read FNaturalOrderNumericalSorting write SetNaturalOrderNumericalSorting;
  156. property DarkMode: Boolean read FDarkMode write SetDarkMode;
  157. property DDLinkOnExeDrag: Boolean read FDDLinkOnExeDrag write FDDLinkOnExeDrag default True;
  158. {The mouse has entered the component window as a target of a drag&drop operation:}
  159. property OnDDDragEnter: TDDOnDragEnter read FOnDDDragEnter write FOnDDDragEnter;
  160. {The mouse has leaved the component window as a target of a drag&drop operation:}
  161. property OnDDDragLeave: TDDOnDragLeave read FOnDDDragLeave write FOnDDDragLeave;
  162. {The mouse is dragging in the component window as a target of a drag&drop operation:}
  163. property OnDDDragOver: TDDOnDragOver read FOnDDDragOver write FOnDDDragOver;
  164. {The Drag&drop operation is about to be executed:}
  165. property OnDDDrop: TDDOnDrop read FOnDDDrop write FOnDDDrop;
  166. property OnDDQueryContinueDrag: TDDOnQueryContinueDrag read FOnDDQueryContinueDrag write FOnDDQueryContinueDrag;
  167. property OnDDChooseEffect: TDDOnChooseEffect read FOnDDChooseEffect write FOnDDChooseEffect;
  168. property OnDDGiveFeedback: TDDOnGiveFeedback read FOnDDGiveFeedback write FOnDDGiveFeedback;
  169. {A drag&drop operation is about to be initiated whith the components window as the source:}
  170. property OnDDDragDetect: TDDOnDragDetect read FOnDDDragDetect write FOnDDDragDetect;
  171. {The component window is the target of a drag&drop operation:}
  172. property OnDDProcessDropped: TOnProcessDropped read FOnDDProcessDropped write FOnDDProcessDropped;
  173. {An error has occurred during a drag&drop operation:}
  174. property OnDDError: TDDErrorEvent read FOnDDError write FOnDDError;
  175. {The drag&drop operation has been executed:}
  176. property OnDDExecuted: TDDExecutedEvent read FOnDDExecuted write FOnDDExecuted;
  177. {Event is fired just before executing the fileoperation. This event is also fired when
  178. files are pasted from the clipboard:}
  179. property OnDDFileOperation: TDDFileOperationEvent read FOnDDFileOperation write FOnDDFileOperation;
  180. {Event is fired after executing the fileoperation. This event is also fired when
  181. files are pasted from the clipboard:}
  182. property OnDDFileOperationExecuted: TDDFileOperationExecutedEvent read FOnDDFileOperationExecuted write FOnDDFileOperationExecuted;
  183. property OnDDCreateDragFileList: TDDOnCreateDragFileList
  184. read FOnDDCreateDragFileList write FOnDDCreateDragFileList;
  185. property OnDDEnd: TNotifyEvent
  186. read FOnDDEnd write FOnDDEnd;
  187. property OnDDCreateDataObject: TDDOnCreateDataObject
  188. read FOnDDCreateDataObject write FOnDDCreateDataObject;
  189. property OnBusy: TDirViewBusy read FOnBusy write FOnBusy;
  190. { Show popupmenu when dropping a file with the right mouse button }
  191. property TargetPopUpMenu: Boolean read GetTargetPopUpMenu write SetTargetPopUpMenu default True;
  192. {Current selected directory:}
  193. property Directory: string read GetDirectory write SetDirectory;
  194. property DragNode: TTreeNode read FDragNode;
  195. property Continue: Boolean read FContinue write FContinue;
  196. property LastDDResult: TDragResult read FLastDDResult;
  197. end;
  198. implementation
  199. uses
  200. SysUtils, ShellApi, ImgList, ActiveX,
  201. IEListView, BaseUtils;
  202. constructor TCustomDriveView.Create(AOwner: TComponent);
  203. begin
  204. inherited;
  205. DragMode := dmAutomatic;
  206. FDragFileList := TStringList.Create;
  207. FDragDrive := '';
  208. FExeDrag := False;
  209. FDDLinkOnExeDrag := True;
  210. FContextMenu := False;
  211. FCanChange := True;
  212. FUseSystemContextMenu := True;
  213. FContinue := True;
  214. FNaturalOrderNumericalSorting := True;
  215. FDarkMode := False;
  216. FRecreatingHandle := False;
  217. OnCompare := DoCompare;
  218. FDragDropFilesEx := TCustomizableDragDropFilesEx.Create(Self);
  219. with FDragDropFilesEx do
  220. begin
  221. AcceptOwnDnd := True;
  222. {MP}
  223. AutoDetectDnD := False;
  224. {/MP}
  225. BringToFront := True;
  226. CompleteFileList := True;
  227. NeedValid := [nvFileName];
  228. RenderDataOn := rdoEnterAndDropSync;
  229. TargetPopUpMenu := True;
  230. OnDragEnter := DDDragEnter;
  231. OnDragLeave := DDDragLeave;
  232. OnDragOver := DDDragOver;
  233. OnDrop := DDDrop;
  234. OnQueryContinueDrag := DDQueryContinueDrag;
  235. OnSpecifyDropTarget := DDSpecifyDropTarget;
  236. OnDropHandlerSucceeded := DDDropHandlerSucceeded;
  237. OnGiveFeedback := DDGiveFeedback;
  238. OnProcessDropped := DDProcessDropped;
  239. OnDragDetect := DDDragDetect;
  240. end;
  241. OnCustomDrawItem := InternalOnDrawItem;
  242. FScrollOnDragOver := TTreeViewScrollOnDragOver.Create(Self, False);
  243. FScrollOnDragOver.OnBeforeUpdate := ScrollOnDragOverBeforeUpdate;
  244. FScrollOnDragOver.OnAfterUpdate := ScrollOnDragOverAfterUpdate;
  245. end;
  246. destructor TCustomDriveView.Destroy;
  247. begin
  248. FreeAndNil(FScrollOnDragOver);
  249. FreeAndNil(FImageList);
  250. if Assigned(Images) then
  251. Images.Free;
  252. if Assigned(FDragImageList) then
  253. begin
  254. if GlobalDragImageList = FDragImageList then
  255. GlobalDragImageList := nil;
  256. FDragImageList.Free;
  257. end;
  258. FDragFileList.Destroy;
  259. if Assigned(FDragDropFilesEx) then
  260. FDragDropFilesEx.Free;
  261. inherited Destroy;
  262. end;
  263. procedure TCustomDriveView.NeedImageLists(Recreate: Boolean);
  264. var
  265. MinHeight: Integer;
  266. AImages: TImageList;
  267. begin
  268. if not Assigned(Images) then
  269. begin
  270. Images := TImageList.Create(Self);
  271. Images.BkColor := Color;
  272. end;
  273. AImages := ShellImageListForControl(Self, ilsSmall);
  274. if Images.Handle <> AImages.Handle then
  275. begin
  276. Images.Handle := AImages.Handle;
  277. end;
  278. if (not Assigned(FImageList)) or Recreate then
  279. begin
  280. if Assigned(FImageList) then
  281. FImageList.Free;
  282. FImageList := OverlayImageList(Images.Width);
  283. end;
  284. MinHeight := ScaleByTextHeight(Self, 18);
  285. if TreeView_GetItemHeight(Handle) < MinHeight then
  286. TreeView_SetItemHeight(Handle, MinHeight);
  287. end;
  288. procedure TCustomDriveView.CMDPIChanged(var Message: TMessage);
  289. begin
  290. inherited;
  291. NeedImageLists(True);
  292. end;
  293. procedure TCustomDriveView.CreateWnd;
  294. begin
  295. inherited;
  296. if DarkMode then AllowDarkModeForWindow(Self, DarkMode);
  297. NeedImageLists(False);
  298. if not (csDesigning in ComponentState) then
  299. FDragImageList := TDragImageList.Create(Self);
  300. if not Assigned(GlobalDragImageList) then
  301. GlobalDragImageList := FDragImageList;
  302. FDragDropFilesEx.DragDropControl := Self;
  303. FParentForm := GetParentForm(Self);
  304. end;
  305. procedure TCustomDriveView.Notification(AComponent: TComponent; Operation: TOperation);
  306. begin
  307. inherited;
  308. if Operation = opRemove then
  309. begin
  310. if AComponent = GetCustomDirView then SetCustomDirView(nil);
  311. end;
  312. end;
  313. procedure TCustomDriveView.InternalOnDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
  314. State: TCustomDrawState; var DefaultDraw: Boolean);
  315. var
  316. FItemColor: TColor;
  317. begin
  318. if Assigned(Node) and Assigned(Node.Data) and (Node <> DropTarget) then
  319. begin
  320. if not Node.Selected then
  321. begin
  322. FItemColor := NodeColor(Node);
  323. if (FItemColor <> clDefaultItemColor) and
  324. (Canvas.Font.Color <> FItemColor) then
  325. Canvas.Font.Color := FItemColor;
  326. end
  327. else
  328. if (not Self.Focused) and HideSelection then
  329. begin
  330. Canvas.Brush.Color := clBtnFace;
  331. Canvas.Font.Color := clBtnText;
  332. end
  333. else
  334. if Node.Selected and (not Self.Focused) and DarkMode then
  335. begin
  336. Canvas.Font.Color := Font.Color;
  337. end;
  338. end;
  339. end; {InternalOnDrawItem}
  340. procedure TCustomDriveView.ScrollOnDragOverBeforeUpdate(ObjectToValidate: TObject);
  341. var
  342. NodeToValidate: TTreeNode;
  343. begin
  344. GlobalDragImageList.HideDragImage;
  345. if Assigned(ObjectToValidate) then
  346. begin
  347. NodeToValidate := (ObjectToValidate as TTreeNode);
  348. if not NodeToValidate.HasChildren then
  349. ValidateDirectory(NodeToValidate);
  350. end;
  351. end;
  352. procedure TCustomDriveView.ScrollOnDragOverAfterUpdate;
  353. begin
  354. GlobalDragImageList.ShowDragImage;
  355. end;
  356. procedure TCustomDriveView.DDDragEnter(DataObj: IDataObject; KeyState: Longint;
  357. Point: TPoint; var Effect: Longint; var Accept: Boolean);
  358. var
  359. Index: Integer;
  360. begin
  361. if (FDragDropFilesEx.FileList.Count > 0) and
  362. (Length(TFDDListItem(FDragDropFilesEx.FileList[0]^).Name) > 0) Then
  363. begin
  364. try
  365. FDragDrive := DriveInfo.GetDriveKey(TFDDListItem(FDragDropFilesEx.FileList[0]^).Name);
  366. except
  367. // WinRAR gives us only filename on "enter", we get a full path only on "drop".
  368. FDragDrive := '';
  369. end;
  370. FExeDrag := FDDLinkOnExeDrag and
  371. (deLink in DragDropFilesEx.TargetEffects) and
  372. ((DragDropFilesEx.AvailableDropEffects and DROPEFFECT_LINK) <> 0);
  373. if FExeDrag then
  374. begin
  375. for Index := 0 to FDragDropFilesEx.FileList.Count - 1 do
  376. if not IsExecutable(TFDDListItem(FDragDropFilesEx.FileList[Index]^).Name) then
  377. begin
  378. FExeDrag := False;
  379. Break;
  380. end;
  381. end;
  382. end
  383. else
  384. begin
  385. FDragDrive := '';
  386. end;
  387. FScrollOnDragOver.StartDrag;
  388. if Assigned(FOnDDDragEnter) then
  389. FOnDDDragEnter(Self, DataObj, KeyState, Point, Effect, Accept);
  390. end; {DDDragEnter}
  391. procedure TCustomDriveView.DDDragLeave;
  392. begin
  393. if Assigned(DropTarget) then
  394. begin
  395. if GlobalDragImageList.Dragging then
  396. GlobalDragImageList.HideDragImage;
  397. DropTarget := nil;
  398. Update;
  399. end;
  400. if Assigned(FOnDDDragLeave) then
  401. FOnDDDragLeave(Self);
  402. end; {DragLeave}
  403. procedure TCustomDriveView.DDDragOver(KeyState: Longint; Point: TPoint; var Effect: Longint; PreferredEffect: Longint);
  404. var
  405. Node: TTreeNode;
  406. Rect1: TRect;
  407. UpdateImage: Boolean;
  408. LastDragNode: TTreeNode;
  409. begin
  410. if Effect <> DROPEFFECT_NONE then
  411. begin
  412. Node := GetNodeAt(Point.X, Point.Y);
  413. if Assigned(Node) then
  414. begin
  415. LastDragNode := DropTarget;
  416. UpdateImage := False;
  417. if GlobalDragImageList.Dragging and (LastDragNode <> Node) then
  418. begin
  419. if Assigned(LastDragNode) then
  420. begin
  421. Rect1 := LastDragNode.DisplayRect(True);
  422. if Rect1.Right >= Point.x - GlobalDragImageList.GetHotSpot.X then
  423. begin
  424. GlobalDragImageList.HideDragImage;
  425. UpdateImage := True;
  426. end
  427. else
  428. begin
  429. Rect1 := Node.DisplayRect(True);
  430. if Rect1.Right >= Point.x - GlobalDragImageList.GetHotSpot.X then
  431. begin
  432. GlobalDragImageList.HideDragImage;
  433. UpdateImage := True;
  434. end
  435. end;
  436. end
  437. else
  438. begin
  439. {LastDragNode not assigned:}
  440. GlobalDragImageList.HideDragImage;
  441. UpdateImage := True;
  442. end;
  443. end;
  444. DropTarget := Node;
  445. if UpdateImage then
  446. GlobalDragImageList.ShowDragImage;
  447. {Drop-operation allowed at this location?}
  448. if Assigned(FDragNode) and
  449. (Effect <> DROPEFFECT_LINK) and
  450. ((Node = FDragNode) or Node.HasAsParent(FDragNode) or (FDragNode.Parent = Node)) then
  451. Effect := DROPEFFECT_NONE;
  452. FScrollOnDragOver.DragOver(Point);
  453. end {Assigned(Node)}
  454. else
  455. begin
  456. DropTarget := nil;
  457. end;
  458. end;
  459. DDChooseEffect(KeyState, Effect, PreferredEffect);
  460. if Assigned(FOnDDDragOver) then
  461. FOnDDDragOver(Self, KeyState, Point, Effect);
  462. if not Assigned(DropTarget) then Effect := DROPEFFECT_NONE
  463. else
  464. if NodeIsRecycleBin(DropTarget) then
  465. begin
  466. if FDragDropFilesEx.FileNamesAreMapped then Effect := DROPEFFECT_NONE
  467. else Effect := DROPEFFECT_MOVE;
  468. end;
  469. end; {DDDragOver}
  470. procedure TCustomDriveView.DDDrop(DataObj: IDataObject; KeyState: Longint;
  471. Point: TPoint; var Effect: Longint);
  472. begin
  473. if GlobalDragImageList.Dragging then
  474. GlobalDragImageList.HideDragImage;
  475. if Effect = DROPEFFECT_NONE then
  476. DropTarget := nil;
  477. if Assigned(FOnDDDrop) then
  478. FOnDDDrop(Self, DataObj, KeyState, Point, Effect);
  479. end; {DDDrop}
  480. procedure TCustomDriveView.DDQueryContinueDrag(EscapePressed: BOOL; KeyState: Longint;
  481. var Result: HResult);
  482. var
  483. Point: TPoint;
  484. ClientPoint: TPoint;
  485. KnowTime: FILETIME;
  486. begin
  487. if Result = DRAGDROP_S_DROP then
  488. begin
  489. GetSystemTimeAsFileTime(KnowTime);
  490. if ((Int64(KnowTime) - Int64(FDragStartTime)) <= DDDragStartDelay) then
  491. Result := DRAGDROP_S_CANCEL;
  492. end;
  493. if Assigned(FOnDDQueryContinueDrag) then
  494. FOnDDQueryContinueDrag(Self, EscapePressed, KeyState, Result);
  495. if EscapePressed then
  496. begin
  497. if GlobalDragImageList.Dragging then
  498. GlobalDragImageList.HideDragImage;
  499. DropTarget := nil;
  500. end
  501. else
  502. begin
  503. if GlobalDragImageList.Dragging then
  504. begin
  505. GetCursorPos(Point);
  506. {Convert screen coordinates to the parentforms coordinates:}
  507. ClientPoint := FParentForm.ScreenToClient(Point);
  508. {Move the drag image to the new position and show it:}
  509. if not CompareMem(@ClientPoint, @FDragPos, SizeOf(TPoint)) then
  510. begin
  511. FDragPos := ClientPoint;
  512. if PtInRect(FParentForm.BoundsRect, Point) then
  513. begin
  514. GlobalDragImageList.DragMove(ClientPoint.X, ClientPoint.Y);
  515. GlobalDragImageList.ShowDragImage;
  516. end
  517. else GlobalDragImageList.HideDragImage;
  518. end;
  519. end;
  520. end;
  521. end; {DDQueryContinueDrag}
  522. procedure TCustomDriveView.DDDropHandlerSucceeded(Sender: TObject;
  523. KeyState: Integer; Point: TPoint; Effect: Integer);
  524. begin
  525. DropTarget := nil;
  526. end;
  527. procedure TCustomDriveView.DDChooseEffect(KeyState: Integer; var Effect: Integer; PreferredEffect: Integer);
  528. begin
  529. if Assigned(FOnDDChooseEffect) then
  530. FOnDDChooseEffect(Self, KeyState, Effect);
  531. end;
  532. procedure TCustomDriveView.DDGiveFeedback(Effect: Longint; var Result: HResult);
  533. begin
  534. if Assigned(FOnDDGiveFeedback) then
  535. FOnDDGiveFeedback(Self, Effect, Result);
  536. end; {DDGiveFeedback}
  537. procedure TCustomDriveView.DDProcessDropped(Sender: TObject; KeyState: Longint;
  538. Point: TPoint; Effect: Longint);
  539. begin
  540. try
  541. if Assigned(DropTarget) then
  542. try
  543. if NodePathExists(DropTarget) then
  544. begin
  545. if Assigned(FOnDDProcessDropped) then
  546. FOnDDProcessDropped(Self, KeyState, Point, Effect);
  547. if Effect <> DROPEFFECT_NONE then
  548. begin
  549. PerformDragDropFileOperation(DropTarget, Effect);
  550. if Assigned(FOnDDExecuted) then
  551. FOnDDExecuted(Self, Effect);
  552. end;
  553. end
  554. else
  555. begin
  556. ValidateDirectory(DropTarget);
  557. DDError(DDPathNotFoundError);
  558. end;
  559. finally
  560. DropTarget := nil;
  561. ClearDragFileList(FDragDropFilesEx.FileList);
  562. end;
  563. except
  564. Application.HandleException(Self);
  565. end;
  566. end; {ProcessDropped}
  567. procedure TCustomDriveView.DDError(Error: TDDError);
  568. begin
  569. if Assigned(FOnDDError) then FOnDDError(Self, Error)
  570. else raise Exception.CreateFmt(SDragDropError, [Ord(Error)]);
  571. end; {DDError}
  572. procedure TCustomDriveView.DDSpecifyDropTarget(Sender: TObject;
  573. DragDropHandler: Boolean; Point: TPoint; var PIDL: PItemIDList; var Filename: string);
  574. begin
  575. PIDL := nil;
  576. if DragDropHandler and Assigned(DropTarget) then FileName := NodePathName(DropTarget)
  577. else FileName := EmptyStr;
  578. end; {DDSpecifyDropTarget}
  579. procedure TCustomDriveView.DDDragDetect(KeyState: Longint; DetectStart, Point: TPoint;
  580. DragStatus: TDragDetectStatus);
  581. var
  582. P: TPoint;
  583. ImageList: HImageList;
  584. NodeRect: TRect;
  585. FileListCreated: Boolean;
  586. AvoidDragImage: Boolean;
  587. begin
  588. if (DragStatus = ddsDrag) and (not Assigned(FDragNode)) then
  589. begin
  590. P := ScreenToClient(FStartPos);
  591. FDragNode := GetNodeAt(P.X, P.Y);
  592. end;
  593. if Assigned(FOnDDDragDetect) then
  594. FOnDDDragDetect(Self, KeyState, DetectStart, Point, DragStatus);
  595. if (DragStatus = ddsDrag) and Assigned(FDragNode) then
  596. begin
  597. NodeRect := FDragNode.DisplayRect(True);
  598. Dec(NodeRect.Left, 16);
  599. {Check, wether the mouse cursor was within the nodes display rectangle:}
  600. if (NodeRect.Left > P.X) or (NodeRect.Right < P.X) or
  601. (not NodeCanDrag(FDragNode)) then
  602. begin
  603. FDragNode := nil;
  604. Exit;
  605. end;
  606. FDragDrive := '';
  607. ClearDragFileList(FDragDropFilesEx.FileList);
  608. FDragDropFilesEx.CompleteFileList := DragCompleteFileList;
  609. FileListCreated := False;
  610. AvoidDragImage := False;
  611. if Assigned(OnDDCreateDragFileList) then
  612. begin
  613. OnDDCreateDragFileList(Self, FDragDropFilesEx.FileList, FileListCreated);
  614. if FileListCreated then
  615. AvoidDragImage := True;
  616. end;
  617. if not FileListCreated then
  618. begin
  619. AddToDragFileList(FDragDropFilesEx.FileList, FDragNode);
  620. end;
  621. FDragDropFilesEx.SourceEffects := DDSourceEffects;
  622. if FDragDropFilesEx.FileList.Count > 0 then
  623. try
  624. {Create the dragimage:}
  625. GlobalDragImageList := FDragImageList;
  626. if not AvoidDragImage then
  627. begin
  628. {Hide the selection mark to get a proper dragimage:}
  629. if Selected = FDragNode then
  630. Selected := nil;
  631. ImageList := TreeView_CreateDragImage(Handle, FDragNode.ItemID);
  632. {Show the selection mark if it was hidden:}
  633. if not Assigned(Selected) then
  634. Selected := FDragNode;
  635. if ImageList <> Invalid_Handle_Value then
  636. begin
  637. GlobalDragImageList.Handle := ImageList;
  638. GlobalDragImageList.SetDragImage(0, P.X - NodeRect.TopLeft.X, P.Y - NodeRect.TopLeft.Y);
  639. P := FParentForm.ScreenToClient(Point);
  640. GlobalDragImageList.BeginDrag(FParentForm.Handle, P.X, P.Y);
  641. GlobalDragImageList.HideDragImage;
  642. ShowCursor(True);
  643. end;
  644. end;
  645. DropSourceControl := Self;
  646. GetSystemTimeAsFileTime(FDragStartTime);
  647. {Supress the context menu:}
  648. FContextMenu := False;
  649. {Execute the drag&drop-Operation:}
  650. FLastDDResult := DDExecute;
  651. {the drag&drop operation is finished, so clean up the used drag image:}
  652. GlobalDragImageList.EndDrag;
  653. GlobalDragImageList.Clear;
  654. Application.ProcessMessages;
  655. finally
  656. ClearDragFileList(FDragDropFilesEx.FileList);
  657. FDragDrive := '';
  658. DropTarget := nil;
  659. try
  660. if Assigned(OnDDEnd) then
  661. OnDDEnd(Self);
  662. finally
  663. DropSourceControl := nil;
  664. FDragNode := nil;
  665. end;
  666. end;
  667. end;
  668. end; {(DDDragDetect}
  669. function TCustomDriveView.DDExecute: TDragResult;
  670. var
  671. DataObject: TDataObject;
  672. begin
  673. DataObject := nil;
  674. if Assigned(OnDDCreateDataObject) then
  675. OnDDCreateDataObject(Self, DataObject);
  676. Result := FDragDropFilesEx.Execute(DataObject);
  677. end;
  678. function TCustomDriveView.GetNodeFromHItem(Item: TTVItem): TTreeNode;
  679. begin
  680. Result := nil;
  681. if Items <> nil then
  682. with Item do
  683. if (state and TVIF_PARAM) <> 0 then
  684. Result := Pointer(lParam)
  685. else
  686. Result := Items.GetNode(hItem);
  687. end; {GetNodeFromItem}
  688. function TCustomDriveView.IsCustomDrawn(Target: TCustomDrawTarget;
  689. Stage: TCustomDrawStage): Boolean;
  690. begin
  691. Result := inherited IsCustomDrawn(Target, Stage) or
  692. ((Target = dtItem) and (Stage = cdPostPaint));
  693. end;
  694. function TCustomDriveView.CustomDrawItem(Node: TTreeNode; State: TCustomDrawState;
  695. Stage: TCustomDrawStage; var PaintImages: Boolean): Boolean;
  696. var
  697. Point: TPoint;
  698. Index: Integer;
  699. OverlayIndexes: Word;
  700. OverlayIndex: Word;
  701. Image: Word;
  702. begin
  703. Result := inherited CustomDrawItem(Node, State, Stage, PaintImages);
  704. if Result and (Stage = cdPostPaint) then
  705. begin
  706. Assert(Assigned(Node));
  707. OverlayIndexes := NodeOverlayIndexes(Node);
  708. OverlayIndex := 1;
  709. while OverlayIndexes > 0 do
  710. begin
  711. if (OverlayIndex and OverlayIndexes) <> 0 then
  712. begin
  713. Index := 0;
  714. Image := OverlayIndex;
  715. while Image > 1 do
  716. begin
  717. Inc(Index);
  718. Image := Image shr 1;
  719. end;
  720. Point := Node.DisplayRect(True).TopLeft;
  721. Dec(Point.X, Indent);
  722. ImageList_Draw(ImageList.Handle, Index, Self.Canvas.Handle,
  723. Point.X, Point.Y, ILD_TRANSPARENT);
  724. Dec(OverlayIndexes, OverlayIndex);
  725. end;
  726. OverlayIndex := OverlayIndex shl 1;
  727. end;
  728. end;
  729. end;
  730. procedure TCustomDriveView.CNNotify(var Msg: TWMNotify);
  731. begin
  732. case Msg.NMHdr.code of
  733. TVN_BEGINDRAG: DDDragDetect(MK_LBUTTON, FStartPos, Mouse.CursorPos, ddsDrag);
  734. TVN_BEGINRDRAG: DDDragDetect(MK_RBUTTON, FStartPos, Mouse.CursorPos, ddsDrag);
  735. else
  736. inherited;
  737. end;
  738. end; {CNNotify}
  739. procedure TCustomDriveView.CMColorChanged(var Msg: TMessage);
  740. begin
  741. inherited;
  742. if Assigned(Images) then
  743. Images.BkColor := Color;
  744. ForceColorChange(Self);
  745. end;
  746. procedure TCustomDriveView.WMLButtonDown(var Msg: TWMLButtonDown);
  747. begin
  748. if not IsBusy then
  749. begin
  750. FCanChange := False;
  751. GetCursorPos(FStartPos);
  752. inherited;
  753. end;
  754. end; {WMLButtonDown}
  755. procedure TCustomDriveView.WMLButtonUp(var Msg: TWMLButtonDown);
  756. begin
  757. FCanChange := True;
  758. if Assigned(DropTarget) and Assigned(DropTarget.Data) then
  759. Selected := DropTarget;
  760. DropTarget := nil;
  761. inherited;
  762. end; {WMLButtonUp}
  763. procedure TCustomDriveView.WMRButtonDown(var Msg: TWMRButtonDown);
  764. begin
  765. if not IsBusy then
  766. begin
  767. GetCursorPos(FStartPos);
  768. if FDragDropFilesEx.DragDetectStatus <> ddsDrag then
  769. FContextMenu := True;
  770. inherited;
  771. end;
  772. end; {WMRButtonDown}
  773. procedure TCustomDriveView.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  774. begin
  775. if not IsBusy then
  776. begin
  777. inherited;
  778. end;
  779. end;
  780. procedure TCustomDriveView.WMContextMenu(var Msg: TWMContextMenu);
  781. var
  782. Node: TTreeNode;
  783. Point: TPoint;
  784. PrevAutoPopup: Boolean;
  785. begin
  786. PrevAutoPopup := False;
  787. try
  788. if Assigned(PopupMenu) then
  789. begin
  790. PrevAutoPopup := PopupMenu.AutoPopup;
  791. PopupMenu.AutoPopup := False;
  792. end;
  793. inherited;
  794. finally
  795. if Assigned(PopupMenu) then
  796. PopupMenu.AutoPopup := PrevAutoPopup;
  797. end;
  798. FStartPos.X := -1;
  799. FStartPos.Y := -1;
  800. try
  801. if FContextMenu then
  802. begin
  803. Point.X := Msg.XPos;
  804. Point.Y := Msg.YPos;
  805. Point := ScreenToClient(Point);
  806. Node := GetNodeAt(Point.X, Point.Y);
  807. if FUseSystemContextMenu and Assigned(Node) then
  808. begin
  809. if Assigned(OnMouseDown) then
  810. OnMouseDown(Self, mbRight, [], Msg.XPos, Msg.YPos);
  811. DisplayContextMenu(Node, Mouse.CursorPos);
  812. end
  813. else
  814. begin
  815. if Assigned(PopupMenu) then
  816. PopupMenu.Popup(Msg.XPos, Msg.YPos);
  817. end;
  818. end;
  819. FContextMenu := False;
  820. finally
  821. DropTarget := nil;
  822. end;
  823. end; {WMContextMenu}
  824. procedure TCustomDriveView.CMRecreateWnd(var Msg: TMessage);
  825. var
  826. HadHandle: Boolean;
  827. begin
  828. HadHandle := HandleAllocated;
  829. inherited;
  830. // If the control is not showing (e.g. because the machine is locked), the handle is not recreated.
  831. // If contents is reloaded (LoadPath) without handle allocated, it crashes
  832. // (as the handle is implicitly created somewhere in the middle of the reload and chaos ensures).
  833. if HadHandle then
  834. begin
  835. Assert(not FRecreatingHandle);
  836. FRecreatingHandle := True;
  837. try
  838. HandleNeeded;
  839. finally
  840. FRecreatingHandle := False;
  841. end;
  842. end;
  843. end;
  844. procedure TCustomDriveView.Delete(Node: TTreeNode);
  845. begin
  846. if Node = FDragNode then
  847. FDragNode := nil;
  848. if Node = DropTarget then
  849. begin
  850. DropTarget := nil;
  851. Update;
  852. end;
  853. inherited;
  854. end; {OnDelete}
  855. procedure TCustomDriveView.WMKeyDown(var Message: TWMKeyDown);
  856. begin
  857. if not IsBusy then
  858. begin
  859. inherited;
  860. end;
  861. end;
  862. procedure TCustomDriveView.KeyDown(var Key: Word; Shift: TShiftState);
  863. begin
  864. if (Key = VK_RETURN) and (ssAlt in Shift) and (not IsEditing) and
  865. Assigned(Selected) then
  866. begin
  867. DisplayPropertiesMenu(Selected);
  868. Key := 0;
  869. end;
  870. inherited;
  871. end; {KeyDown}
  872. procedure TCustomDriveView.KeyPress(var Key : Char);
  873. begin
  874. if Assigned(Selected) then
  875. begin
  876. if not IsEditing then
  877. begin
  878. case Key of
  879. #13, ' ':
  880. begin
  881. Selected.Expanded := not Selected.Expanded;
  882. Key := #0;
  883. end;
  884. '/':
  885. begin
  886. Selected.Collapse(True);
  887. Selected.MakeVisible;
  888. Key := #0;
  889. end;
  890. '*':
  891. Selected.MakeVisible;
  892. end {Case}
  893. end
  894. end;
  895. inherited;
  896. end; {KeyPress}
  897. procedure TCustomDriveView.KeyUp(var Key: Word; Shift: TShiftState);
  898. var
  899. Point: TPoint;
  900. begin
  901. inherited;
  902. if (Key = VK_APPS) and Assigned(Selected) then
  903. begin
  904. Point := ClientToScreen(Selected.DisplayRect(True).TopLeft);
  905. Inc(Point.Y, 20);
  906. DisplayContextMenu(Selected, Point);
  907. end;
  908. end; {KeyUp}
  909. procedure TCustomDriveView.ValidateDirectory(Node: TTreeNode);
  910. begin
  911. ValidateDirectoryEx(Node, rsRecursiveExisting, False);
  912. end; {ValidateDirectory}
  913. procedure TCustomDriveView.CenterNode(Node: TTreeNode);
  914. var
  915. NodePos: TRect;
  916. ScrollInfo: TScrollInfo;
  917. begin
  918. if Assigned(Node) and (Items.Count > 0) then
  919. begin
  920. Node.MakeVisible;
  921. NodePos := Node.DisplayRect(False);
  922. with ScrollInfo do
  923. begin
  924. cbSize := SizeOf(ScrollInfo);
  925. fMask := SIF_ALL;
  926. nMin := 0;
  927. nMax := 0;
  928. nPage := 0;
  929. end;
  930. GetScrollInfo(Handle, SB_VERT, ScrollInfo);
  931. if ScrollInfo.nMin <> ScrollInfo.nMax then
  932. begin
  933. {Scroll tree up:}
  934. if (NodePos.Top < Height div 4) and (ScrollInfo.nPos > 0) then
  935. begin
  936. ScrollInfo.fMask := SIF_POS;
  937. while (ScrollInfo.nPos > 0) and (NodePos.Top < (Height div 4)) do
  938. begin
  939. Perform(WM_VSCROLL, SB_LINEUP, 0);
  940. GetScrollInfo(Handle, SB_VERT, ScrollInfo);
  941. NodePos := Node.DisplayRect(False);
  942. end;
  943. end
  944. else
  945. if (NodePos.Top > ((Height * 3) div 4)) then
  946. begin
  947. {Scroll tree down:}
  948. ScrollInfo.fMask := SIF_POS;
  949. while (ScrollInfo.nPos + ABS(ScrollInfo.nPage) < ScrollInfo.nMax) and
  950. (NodePos.Top > ((Height * 3) div 4)) and
  951. (ScrollInfo.nPage > 0) do
  952. begin
  953. Perform(WM_VSCROLL, SB_LINEDOWN, 0);
  954. GetScrollInfo(Handle, SB_VERT, ScrollInfo);
  955. NodePos := Node.DisplayRect(False);
  956. end;
  957. end;
  958. NodePos := Node.DisplayRect(True);
  959. end;
  960. if NodePos.Left < 50 then
  961. Perform(WM_HSCROLL, SB_PAGELEFT, 0);
  962. end;
  963. end; {CenterNode}
  964. function TCustomDriveView.DoCompareText(Text1, Text2: string): Integer;
  965. begin
  966. Result := CompareLogicalTextPas(Text1, Text2, NaturalOrderNumericalSorting);
  967. end;
  968. procedure TCustomDriveView.DoCompare(Sender: TObject; Node1, Node2: TTreeNode; Data: Integer; var Compare: Integer);
  969. begin
  970. Compare := DoCompareText(Node1.Text, Node2.Text);
  971. end;
  972. function TCustomDriveView.SortChildren(ParentNode: TTreeNode; Recurse: Boolean): Boolean;
  973. begin
  974. Result := Assigned(ParentNode) and ParentNode.AlphaSort(Recurse);
  975. end; {SortChildren}
  976. function TCustomDriveView.IterateSubTree(var StartNode : TTreeNode;
  977. CallBackFunc: TCallBackFunc; Recurse: TRecursiveScan;
  978. ScanStartNode: TScanStartNode; Data: Pointer): Boolean;
  979. function ScanSubTree(var StartNode: TTreeNode): Boolean;
  980. var
  981. Node: TTreeNode;
  982. NextNode: TTreeNode;
  983. NodeHasChilds: Boolean;
  984. begin
  985. Result := False;
  986. if not Assigned(StartNode) then Exit;
  987. Node := StartNode.GetFirstChild;
  988. while Assigned(Node) and FContinue do
  989. begin
  990. NextNode := StartNode.GetNextChild(Node);
  991. NodeHasChilds := Node.HasChildren;
  992. if (not FContinue) or (not CallBackFunc(Node, Data)) then Exit;
  993. if Assigned(Node) and
  994. (Recurse = rsRecursiveExisting) and NodeHasChilds then
  995. begin
  996. if (not ScanSubTree(Node)) or (not FContinue) then Exit;
  997. end;
  998. Node := NextNode;
  999. end;
  1000. Result := True;
  1001. end; {ScanSubTree}
  1002. begin {IterateSubTree}
  1003. Result := False;
  1004. FContinue := True;
  1005. if Assigned(CallBackFunc) then
  1006. begin
  1007. if ScanStartNode = coScanStartNode then
  1008. begin
  1009. CallBackFunc(StartNode, Data);
  1010. end;
  1011. if (not Assigned(StartNode)) or
  1012. FContinue and ScanSubTree(StartNode) then
  1013. begin
  1014. Result := True;
  1015. end;
  1016. end;
  1017. end; {IterateSubTree}
  1018. procedure TCustomDriveView.ClearDragFileList(FileList: TFileList);
  1019. begin
  1020. FileList.Clear;
  1021. end;
  1022. procedure TCustomDriveView.AddToDragFileList(FileList: TFileList; Node: TTreeNode);
  1023. begin
  1024. FileList.AddItem(nil, NodePathName(Node));
  1025. end;
  1026. function TCustomDriveView.NodeCanDrag(Node: TTreeNode): Boolean;
  1027. begin
  1028. Result := True;
  1029. end;
  1030. function TCustomDriveView.NodeOverlayIndexes(Node: TTreeNode): Word;
  1031. begin
  1032. Result := oiNoOverlay;
  1033. end;
  1034. function TCustomDriveView.NodeIsRecycleBin(Node: TTreeNode): Boolean;
  1035. begin
  1036. Result := False;
  1037. end;
  1038. function TCustomDriveView.NodePathExists(Node: TTreeNode): Boolean;
  1039. begin
  1040. Result := True;
  1041. end;
  1042. procedure TCustomDriveView.SetDimmHiddenDirs(Value: Boolean);
  1043. begin
  1044. if Value <> FDimmHiddenDirs then
  1045. begin
  1046. FDimmHiddenDirs := Value;
  1047. Self.Invalidate;
  1048. end;
  1049. end; {SetDimmHiddenDirs}
  1050. procedure TCustomDriveView.SetShowHiddenDirs(Value: Boolean);
  1051. begin
  1052. if Value <> FShowHiddenDirs then
  1053. begin
  1054. FShowHiddenDirs := Value;
  1055. RebuildTree;
  1056. end;
  1057. end; {SetDimmHiddenDirs}
  1058. procedure TCustomDriveView.SetNaturalOrderNumericalSorting(Value: Boolean);
  1059. begin
  1060. if NaturalOrderNumericalSorting <> Value then
  1061. begin
  1062. FNaturalOrderNumericalSorting := Value;
  1063. AlphaSort;
  1064. end;
  1065. end;
  1066. procedure TCustomDriveView.SetDarkMode(Value: Boolean);
  1067. begin
  1068. if DarkMode <> Value then
  1069. begin
  1070. FDarkMode := Value;
  1071. // See TCustomDirView.SetDarkMode
  1072. if HandleAllocated then AllowDarkModeForWindow(Self, DarkMode);
  1073. end;
  1074. end;
  1075. function TCustomDriveView.GetTargetPopupMenu: Boolean;
  1076. begin
  1077. if Assigned(FDragDropFilesEx) then Result := FDragDropFilesEx.TargetPopupMenu
  1078. else Result := True;
  1079. end;
  1080. procedure TCustomDriveView.SetTargetPopUpMenu(Value: Boolean);
  1081. begin
  1082. if Assigned(FDragDropFilesEx) then
  1083. FDragDropFilesEx.TargetPopupMenu := Value;
  1084. end; {SetTargetPopUpMenu}
  1085. function TCustomDriveView.GetDirectory: string;
  1086. begin
  1087. if Assigned(Selected) then Result := NodePathName(Selected)
  1088. else Result := '';
  1089. end; {GetDirectory}
  1090. procedure TCustomDriveView.SetDirectory(Value: string);
  1091. var
  1092. NewSelected: TTreeNode;
  1093. Rect: TRect;
  1094. begin
  1095. NewSelected := FindPathNode(Value);
  1096. if Assigned(NewSelected) and (NewSelected <> Selected) then
  1097. begin
  1098. FCanChange := True;
  1099. NewSelected.MakeVisible;
  1100. Rect := NewSelected.DisplayRect(False);
  1101. Selected := NewSelected;
  1102. end
  1103. else
  1104. if csDesigning in ComponentState then
  1105. Selected := nil;
  1106. end; {SetDirectory}
  1107. function TCustomDriveView.DoBusy(Busy: Integer): Boolean;
  1108. begin
  1109. Result := True;
  1110. if Assigned(OnBusy) then
  1111. begin
  1112. OnBusy(Self, Busy, Result);
  1113. end;
  1114. end;
  1115. function TCustomDriveView.StartBusy: Boolean;
  1116. begin
  1117. Result := DoBusy(1);
  1118. end;
  1119. function TCustomDriveView.IsBusy: Boolean;
  1120. begin
  1121. Result := DoBusy(0);
  1122. end;
  1123. procedure TCustomDriveView.EndBusy;
  1124. begin
  1125. DoBusy(-1);
  1126. end;
  1127. end.