CustomDriveView.pas 38 KB

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