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