mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-14 03:59:32 +02:00
333 lines
8.5 KiB
ObjectPascal
333 lines
8.5 KiB
ObjectPascal
{
|
|
/***************************************************************************
|
|
ShellCtrls.pas
|
|
------------
|
|
|
|
|
|
***************************************************************************/
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
}
|
|
unit ShellCtrls;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, Forms,
|
|
ComCtrls;
|
|
|
|
type
|
|
|
|
{ TObjectTypes }
|
|
|
|
TObjectType = (otFolders, otNonFolders, otHidden);
|
|
|
|
TObjectTypes = set of TObjectType;
|
|
|
|
{ TCustomShellTreeView }
|
|
|
|
TCustomShellTreeView = class(TCustomTreeView)
|
|
private
|
|
FObjectTypes: TObjectTypes;
|
|
procedure HandleOnExpanding(Sender: TObject; Node: TTreeNode; var AllowExpansion: Boolean);
|
|
protected
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
|
|
{ Methods specific to Lazarus }
|
|
class procedure GetFilesInDir(const ABaseDir: string;
|
|
AObjectTypes: TObjectTypes; AResult: TStrings);
|
|
function PopulateTreeNodeWithFiles(ANode: TTreeNode; ANodePath: string): Boolean;
|
|
procedure PopulateTreeViewWithBaseFiles;
|
|
function GetPathFromNode(ANode: TTreeNode): string;
|
|
|
|
{ Properties }
|
|
|
|
property ObjectTypes: TObjectTypes read FObjectTypes write FObjectTypes;
|
|
end;
|
|
|
|
{ TShellTreeView }
|
|
|
|
TShellTreeView = class(TCustomShellTreeView)
|
|
published
|
|
{ TCustomTreeView properties }
|
|
property Align;
|
|
property Anchors;
|
|
property AutoExpand;
|
|
property BorderSpacing;
|
|
//property BiDiMode;
|
|
property BackgroundColor;
|
|
property BorderStyle;
|
|
property BorderWidth;
|
|
property Color;
|
|
property Ctl3D;
|
|
property Constraints;
|
|
property Enabled;
|
|
property ExpandSignType;
|
|
property Font;
|
|
//property ParentBiDiMode;
|
|
property ParentColor default False;
|
|
property ParentCtl3D;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property PopupMenu;
|
|
property ReadOnly;
|
|
property RightClickSelect;
|
|
property RowSelect;
|
|
property ScrollBars;
|
|
property SelectionColor;
|
|
property ShowButtons;
|
|
property ShowHint;
|
|
property ShowLines;
|
|
property ShowRoot;
|
|
property TabOrder;
|
|
property TabStop default True;
|
|
property Tag;
|
|
property ToolTips;
|
|
property Visible;
|
|
property OnChange;
|
|
property OnChanging;
|
|
property OnClick;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnSelectionChanged;
|
|
property OnShowHint;
|
|
property OnUTF8KeyPress;
|
|
property Options;
|
|
property TreeLineColor;
|
|
property TreeLinePenStyle;
|
|
property ExpandSignColor;
|
|
{ TCustomShellTreeView properties }
|
|
property ObjectTypes;
|
|
end;
|
|
|
|
procedure Register;
|
|
|
|
implementation
|
|
|
|
{$ifdef windows}
|
|
uses Windows;
|
|
{$endif}
|
|
|
|
{
|
|
uses ShlObj;
|
|
|
|
// $I shellctrlswin32.inc
|
|
|
|
procedure PopulateTreeViewWithShell(ATreeView: TCustomShellTreeView);
|
|
var
|
|
ShellFolder: IShellFolder = nil;
|
|
Win32ObjectTypes: Integer;
|
|
// pidl: LPITEMIDLIST;
|
|
pidlParent: LPITEMIDLIST;
|
|
begin
|
|
SHGetSpecialFolderLocation(0, CSIDL_DESKTOP, @pidl);
|
|
|
|
SHGetDesktopFolder(ShellFolder);
|
|
|
|
if ShellFolder = nil then Exit;
|
|
|
|
// Converts the control data into Windows constants
|
|
|
|
Win32ObjectTypes := 0;
|
|
|
|
if otFolders in ATreeView.ObjectTypes then
|
|
Win32ObjectTypes := Win32ObjectTypes or SHCONTF_FOLDERS;
|
|
|
|
if otNonFolders in ATreeView.ObjectTypes then
|
|
Win32ObjectTypes := Win32ObjectTypes or SHCONTF_NONFOLDERS;
|
|
|
|
if otHidden in ATreeView.ObjectTypes then
|
|
Win32ObjectTypes := Win32ObjectTypes or SHCONTF_INCLUDEHIDDEN;
|
|
|
|
// Now gets the name of the desktop folder
|
|
}
|
|
|
|
{ TCustomShellTreeView }
|
|
|
|
procedure TCustomShellTreeView.HandleOnExpanding(Sender: TObject;
|
|
Node: TTreeNode; var AllowExpansion: Boolean);
|
|
begin
|
|
Node.DeleteChildren;
|
|
AllowExpansion := PopulateTreeNodeWithFiles(Node, GetPathFromNode(Node));
|
|
end;
|
|
|
|
constructor TCustomShellTreeView.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
|
|
// Initial property values
|
|
|
|
ObjectTypes:= [otFolders];
|
|
|
|
// Necessary event handlers
|
|
|
|
OnExpanding := @HandleOnExpanding;
|
|
|
|
// Populates the base dirs
|
|
|
|
PopulateTreeViewWithBaseFiles();
|
|
end;
|
|
|
|
destructor TCustomShellTreeView.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{ Finds all files/directories directly inside a directory.
|
|
Does not recurse inside subdirectories. }
|
|
class procedure TCustomShellTreeView.GetFilesInDir(const ABaseDir: string;
|
|
AObjectTypes: TObjectTypes; AResult: TStrings);
|
|
var
|
|
DirInfo: TSearchRec;
|
|
FindResult: Integer;
|
|
IsDirectory, IsValidDirectory, IsHidden, AddFile: Boolean;
|
|
ObjectData: TObject;
|
|
begin
|
|
FindResult := FindFirst(ABaseDir + '\*.*', FaDirectory, DirInfo);
|
|
|
|
while FindResult = 0 do
|
|
begin
|
|
Application.ProcessMessages;
|
|
|
|
IsDirectory := (DirInfo.Attr and FaDirectory = FaDirectory);
|
|
|
|
IsValidDirectory := (DirInfo.Name <> '.') and (DirInfo.Name <> '..');
|
|
|
|
IsHidden := (DirInfo.Attr and faHidden = faHidden);
|
|
|
|
// First check if we show hidden files
|
|
if IsHidden then AddFile := (otHidden in AObjectTypes)
|
|
else AddFile := True;
|
|
|
|
// If it is a directory, check if it is a valid one
|
|
if IsDirectory then
|
|
AddFile := AddFile and ((otFolders in AObjectTypes) and IsValidDirectory)
|
|
else
|
|
AddFile := AddFile and (otNonFolders in AObjectTypes);
|
|
|
|
// Mark if it is a directory (ObjectData <> nil)
|
|
if IsDirectory then ObjectData := AResult
|
|
else ObjectData := nil;
|
|
|
|
// AddFile identifies if the file is valid or not
|
|
if AddFile then AResult.AddObject(DirInfo.Name, ObjectData);
|
|
|
|
FindResult := FindNext(DirInfo);
|
|
end;
|
|
|
|
SysUtils.FindClose(DirInfo);
|
|
end;
|
|
|
|
{ Returns true if at least one item was added, false otherwise }
|
|
function TCustomShellTreeView.PopulateTreeNodeWithFiles(ANode: TTreeNode;
|
|
ANodePath: string): Boolean;
|
|
var
|
|
i: Integer;
|
|
Files: TStringList;
|
|
NewNode: TTreeNode;
|
|
begin
|
|
Files := TStringList.Create;
|
|
try
|
|
GetFilesInDir(ANodePath, FObjectTypes, Files);
|
|
|
|
Result := Files.Count > 0;
|
|
|
|
for i := 0 to Files.Count - 1 do
|
|
begin
|
|
NewNode := Items.AddChildObject(ANode, Files.Strings[i], nil); //@Files.Strings[i]);
|
|
NewNode.HasChildren := Files.Objects[i] <> nil;
|
|
end;
|
|
finally
|
|
Files.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomShellTreeView.PopulateTreeViewWithBaseFiles;
|
|
{$if defined(windows) and not defined(wince)}
|
|
const
|
|
DRIVE_UNKNOWN = 0;
|
|
DRIVE_NO_ROOT_DIR = 1;
|
|
DRIVE_REMOVABLE = 2;
|
|
DRIVE_FIXED = 3;
|
|
DRIVE_REMOTE = 4;
|
|
DRIVE_CDROM = 5;
|
|
DRIVE_RAMDISK = 6;
|
|
var
|
|
r: LongWord;
|
|
Drives: array[0..128] of char;
|
|
pDrive: PChar;
|
|
NewNode: TTreeNode;
|
|
begin
|
|
r := GetLogicalDriveStrings(SizeOf(Drives), Drives);
|
|
if r = 0 then Exit;
|
|
if r > SizeOf(Drives) then Exit;
|
|
// raise Exception.Create(SysErrorMessage(ERROR_OUTOFMEMORY));
|
|
|
|
pDrive := Drives;
|
|
while pDrive^ <> #0 do
|
|
begin
|
|
// r := GetDriveType(pDrive);
|
|
|
|
NewNode := Items.AddChildObject(nil, pDrive, pDrive);
|
|
NewNode.HasChildren := True;
|
|
|
|
Inc(pDrive, 4);
|
|
end;
|
|
end;
|
|
{$endif}
|
|
{$ifdef wince}
|
|
begin
|
|
PopulateTreeNodeWithFiles(nil, '\');
|
|
end;
|
|
{$endif}
|
|
{$ifdef unix}
|
|
begin
|
|
PopulateTreeNodeWithFiles(nil, '/');
|
|
end;
|
|
{$endif}
|
|
|
|
function TCustomShellTreeView.GetPathFromNode(ANode: TTreeNode): string;
|
|
var
|
|
rootDir : String;
|
|
begin
|
|
// In the future use ANode.Data instead of ANode.Text
|
|
rootDir := PChar(ANode.Text);
|
|
while (ANode.Parent <> nil)do
|
|
begin
|
|
ANode := ANode.Parent;
|
|
if( pChar(ANode.Text) <> PathDelim)then
|
|
rootDir := PChar(ANode.Text)+PathDelim+rootDir
|
|
else
|
|
rootDir := PChar(ANode.Text)+rootDir;
|
|
end;
|
|
result:=rootDir;
|
|
end;
|
|
|
|
|
|
procedure Register;
|
|
begin
|
|
RegisterComponents('Misc',[TCustomShellTreeView]);
|
|
// RegisterNoIcon([TCustomShellTreeView]);
|
|
end;
|
|
|
|
end.
|