CustomDriveView.pas 38 KB

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