CustomDriveView.pas 36 KB

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