lazarus/dirsel.pas

277 lines
8.1 KiB
ObjectPascal

{
/***************************************************************************
DirSel.pas
----------
Component Library
***************************************************************************/
*****************************************************************************
* *
* 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 DirSel;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Buttons,
StdCtrls, ComCtrls, ExtCtrls;
type
{ TDirSelDlg }
TDirSelDlg = class(TForm)
btnOK: TButton;
btnCancel: TButton;
lblDirectory: TLabel;
Panel1: TPanel;
DirectoryPanel: TPanel;
TV: TTreeview;
procedure FormShow(Sender: TObject);
procedure TVExpanded(Sender: TObject; Node: TTreeNode);
private
FRootDir: string;
FDir: string;
FShowHidden: Boolean;
//TheImageList: TImageList;
procedure AddDirectories(Node: TTreeNode; Dir: string);
function GetAbsolutePath(Node: TTreeNode): string;
procedure SetDir(const Value: string);
procedure SetRootDir(const Value: string);
procedure SetupCaptions;
public
function SelectedDir: string;
property Directory: string read FDir write SetDir;
property RootDirectory: string read FRootDir write SetRootDir;
property ShowHidden: Boolean read FShowHidden write FShowHidden;
end;
var
DirSelDlg: TDirSelDlg;
implementation
uses
FileUtil, LCLStrConsts;
{function HasSubDirs returns True if the directory passed has subdirectories}
function HasSubDirs(const Dir: string; AShowHidden: boolean): Boolean;
var
FileInfo: TSearchRec;
FCurrentDir: string;
begin
//Assume No
Result := False;
if Dir <> '' then
begin
FCurrentDir := AppendPathDelim(Dir);
FCurrentDir := FCurrentDir + GetAllFilesMask;
// debugln('FCurrentDir=' + FCurrentDir);
try
if SysUtils.FindFirstUTF8(FCurrentDir, faAnyFile, FileInfo)=0 then
begin
repeat
if FileInfo.Name = '' then
Continue;
// check if special file
if ((FileInfo.Name='.') or (FileInfo.Name='..')) or
// unix dot directories (aka hidden directories)
((FileInfo.Name[1] in ['.']) and AShowHidden) or
// check Hidden attribute
(((faHidden and FileInfo.Attr)>0) and AShowHidden) then
Continue;
Result := ((faDirectory and FileInfo.Attr)>0);
//We found at least one non special dir, that's all we need.
if Result then
break;
until SysUtils.FindNextUTF8(FileInfo)<>0;
end;//if
finally
SysUtils.FindCloseUTF8(FileInfo);
end;//Try-Finally
end;//if
end;//HasSubDirs
{procedure AddDirectories Adds Subdirectories to a passed node if they exist}
procedure TDirSelDlg.AddDirectories(Node: TTreeNode; Dir: string);
var
FileInfo: TSearchRec;
NewNode: TTreeNode;
i: integer;
FCurrentDir: string;
//used to sort the directories.
SortList: TStringList;
begin
if Dir <> '' then
begin
FCurrentDir:= Dir;
AppendPathDelim(FCurrentDir);
i:= length(FCurrentDir);
FCurrentDir:= Dir + GetAllFilesMask;
try
if SysUtils.FindFirstUTF8(FCurrentDir, faAnyFile,FileInfo)=0 then
begin
Try
SortList:= TStringList.Create;
SortList.Sorted:= True;
repeat
// check if special file
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='') then
Continue;
// if hidden files or directories must be filtered, we test for
// dot files, considered hidden under unix type OS's.
if not FShowHidden then
if (FileInfo.Name[1] in ['.']) then
Continue;
// if this is a directory then add it to the tree.
if ((faDirectory and FileInfo.Attr)>0) then
begin
//if this is a hidden file and we have not been requested to show
//hidden files then do not add it to the list.
if ((faHidden and FileInfo.Attr)>0) and not FShowHidden then
continue;
SortList.Add(FileInfo.Name);
end;//if
until SysUtils.FindNextUTF8(FileInfo)<>0;
for i:= 0 to SortList.Count - 1 do
begin
NewNode:= TV.Items.AddChild(Node,SortList[i]);
//if subdirectories then indicate so.
NewNode.HasChildren := HasSubDirs(AppendPathDelim(Dir) + NewNode.Text, FShowHidden);
end;//for
finally
SortList.free;
end;//Try-Finally
end;//if
finally
SysUtils.FindCloseUTF8(FileInfo);
end;//Try-Finally
end;//if
if Node.Level = 0 then Node.Text := Dir;
end;//AddDirectories
{procedure SetRootNode Clear the TreeView and Add the root with it's
subdirectories}
procedure TDirSelDlg.SetRootDir(const Value: string);
var
RootNode: TTreeNode;
begin
//Clear the list
TV.Items.Clear;
FRootDir:= Value;
//Remove the path delimiter unless this is root.
if FRootDir = '' then FRootDir := PathDelim;
if (FRootDir <> PathDelim) and (FRootDir[length(FRootDir)] = PathDelim) then
FRootDir:= copy(FRootDir,1,length(FRootDir) - 1);
//Create the root node and add it to the Tree View.
RootNode:= TV.Items.Add(nil,FRootDir);
//Add the Subdirectories to Root.
AddDirectories(RootNode,FRootDir);
//Set the root node as the selected node.
TV.Selected:= RootNode;
end;//SetRootDir
procedure TDirSelDlg.SetupCaptions;
begin
Caption := rsfdSelectDirectory;
btnOK.Caption := rsMbOK;
btnCancel.Caption := rsMbCancel;
lblDirectory.Caption := rsDirectory;
end;
{Returns the absolute path to a node.}
function TDirSelDlg.GetAbsolutePath(Node: TTreeNode): string;
begin
Result:= '';
While Node<>nil do
begin
if Node.Text = PathDelim then
Result:= Node.Text + Result
else
Result:= Node.Text + PathDelim + Result;
Node:= Node.Parent;
end;//while
end;//GetAbsolutePath
procedure TDirSelDlg.FormShow(Sender: TObject);
begin
SetupCaptions;
if TV.Selected <> nil then
TV.Selected.Expand(false);
end;//FormShow
procedure TDirSelDlg.TVExpanded(Sender: TObject; Node: TTreeNode);
begin
if Node.Count = 0 then
AddDirectories(Node, GetAbsolutePath(Node));
end;//TVExpanded
procedure TDirSelDlg.SetDir(const Value: string);
var
StartDir: string;
Node: TTreeNode;
i,p: integer;
SubDir: PChar;
begin
FDir:= Value;
StartDir:= Value;
if TV.Items.Count = 0 then exit;
p:= AnsiPos(FRootDir, StartDir);
if p = 1 then
Delete(StartDir,P,Length(FRootDir));
for i:= 1 to Length(StartDir) do
if (StartDir[i] = PathDelim) then StartDir[i] := #0;
SubDir:= PChar(StartDir);
if SubDir[0] = #0 then
SubDir:= @SubDir[1];
Node:= TV.Items.GetFirstNode;
While SubDir[0] <> #0 do
begin
Node:= Node.GetFirstChild;
while (Node <> nil) and (AnsiCompareStr(Node.Text, SubDir) <> 0) do
Node:= Node.GetNextSibling;
if Node = nil then break
else
begin
Node.Expand(False);
end;//else
SubDir:= SubDir + StrLen(SubDir) + 1
end;//While
TV.Selected.MakeVisible;
end;//SetDir
function TDirSelDlg.SelectedDir: string;
begin
Result:= '';
if TV.Selected <> nil then
Result:= GetAbsolutePath(TV.Selected);
end;//SelectedDir
initialization
{$I dirsel.lrs}
end.