mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-09 12:56:14 +02:00
Improve TreeFilterEdit. Support many filtered branches and prepare for filtering the whole tree.
git-svn-id: trunk@34251 -
This commit is contained in:
parent
eb5c673298
commit
bb9e426743
@ -5,14 +5,45 @@ unit TreeFilterEdit;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, Forms, LResources, LCLType, Graphics,
|
Classes, SysUtils, Forms, LResources, Graphics,
|
||||||
Controls, ComCtrls, EditBtn, FileUtil, AvgLvlTree;
|
Controls, ComCtrls, EditBtn, FileUtil, AvgLvlTree, fgl;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
TImageIndexEvent = function (Str: String; Data: TObject;
|
TImageIndexEvent = function (Str: String; Data: TObject;
|
||||||
var AIsEnabled: Boolean): Integer of object;
|
var AIsEnabled: Boolean): Integer of object;
|
||||||
|
|
||||||
|
TTreeFilterEdit = class;
|
||||||
|
TTreeNodeList = specialize TFPGList<TTreeNode>;
|
||||||
|
|
||||||
|
{ TBranch }
|
||||||
|
|
||||||
|
// A branch in the tree which can be sorted
|
||||||
|
TBranch = class
|
||||||
|
private
|
||||||
|
fOwner: TTreeFilterEdit;
|
||||||
|
fRootNode: TTreeNode;
|
||||||
|
fOriginalData: TStringList; // Data supplied by caller.
|
||||||
|
fSortedData: TStringList; // Data sorted for viewing.
|
||||||
|
fImgIndex: Integer;
|
||||||
|
// Full filename in node data is needed when showing the directory hierarchy.
|
||||||
|
// It is stored automatically if AFullFilename is passed to contructor.
|
||||||
|
fFilenameMap: TStringToStringTree;
|
||||||
|
fTVNodeStack: TTreeNodeList;
|
||||||
|
function CompareFNs(AFilename1,AFilename2: string): integer;
|
||||||
|
procedure SortAndFilter;
|
||||||
|
procedure ApplyFilter;
|
||||||
|
procedure FreeTVNodeData(Node: TTreeNode);
|
||||||
|
procedure TVDeleteUnneededNodes(p: integer);
|
||||||
|
procedure TVClearUnneededAndCreateHierachy(Filename: string);
|
||||||
|
public
|
||||||
|
constructor Create(AOwner: TTreeFilterEdit; ARootNode: TTreeNode);
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure AddNodeData(ANodeText: string; AData: TObject; AFullFilename: string = '');
|
||||||
|
end;
|
||||||
|
|
||||||
|
TBranchList = specialize TFPGObjectList<TBranch>;
|
||||||
|
|
||||||
{ TTreeFilterEdit }
|
{ TTreeFilterEdit }
|
||||||
|
|
||||||
TTreeFilterEdit = class(TCustomControlFilterEdit)
|
TTreeFilterEdit = class(TCustomControlFilterEdit)
|
||||||
@ -21,23 +52,10 @@ type
|
|||||||
fImageIndexDirectory: integer; // Needed if directory structure is shown.
|
fImageIndexDirectory: integer; // Needed if directory structure is shown.
|
||||||
fSelectionList: TStringList; // Store/restore the old selections here.
|
fSelectionList: TStringList; // Store/restore the old selections here.
|
||||||
fShowDirHierarchy: Boolean; // Show direcories / files as a tree structure.
|
fShowDirHierarchy: Boolean; // Show direcories / files as a tree structure.
|
||||||
// Full filename in node data is needed when showing the directory hierarchy.
|
fBranches: TBranchList; // Items are under these nodes can be sorted.
|
||||||
// It is stored automatically if the map is populated by MapShortToFullFilename.
|
|
||||||
fFilenameMap: TStringToStringTree;
|
|
||||||
// Data supplied by caller through Data property.
|
|
||||||
fOriginalData: TStringList;
|
|
||||||
// Data sorted for viewing.
|
|
||||||
fSortedData: TStringList;
|
|
||||||
fRootNode: TTreeNode; // The filtered items are under this node.
|
|
||||||
fOnGetImageIndex: TImageIndexEvent;
|
fOnGetImageIndex: TImageIndexEvent;
|
||||||
fImgIndex: Integer;
|
|
||||||
fTVNodeStack: TFPList;
|
|
||||||
function CompareFNs(AFilename1,AFilename2: string): integer;
|
|
||||||
procedure SetFilteredTreeview(const AValue: TTreeview);
|
procedure SetFilteredTreeview(const AValue: TTreeview);
|
||||||
procedure SetShowDirHierarchy(const AValue: Boolean);
|
procedure SetShowDirHierarchy(const AValue: Boolean);
|
||||||
procedure FreeTVNodeData(Node: TTreeNode);
|
|
||||||
procedure TVDeleteUnneededNodes(p: integer);
|
|
||||||
procedure TVClearUnneededAndCreateHierachy(Filename: string);
|
|
||||||
protected
|
protected
|
||||||
procedure MoveNext; override;
|
procedure MoveNext; override;
|
||||||
procedure MovePrev; override;
|
procedure MovePrev; override;
|
||||||
@ -49,16 +67,16 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
procedure StoreSelection; override;
|
procedure StoreSelection; override;
|
||||||
procedure RestoreSelection; override;
|
procedure RestoreSelection; override;
|
||||||
procedure MapShortToFullFilename(ShortFilename, FullFilename: string);
|
function GetBranch(ARootNode: TTreeNode): TBranch;
|
||||||
public
|
public
|
||||||
property ImageIndexDirectory: integer read fImageIndexDirectory write fImageIndexDirectory;
|
property ImageIndexDirectory: integer read fImageIndexDirectory write fImageIndexDirectory;
|
||||||
property SelectionList: TStringList read fSelectionList;
|
property SelectionList: TStringList read fSelectionList;
|
||||||
property ShowDirHierarchy: Boolean read fShowDirHierarchy write SetShowDirHierarchy;
|
property ShowDirHierarchy: Boolean read fShowDirHierarchy write SetShowDirHierarchy;
|
||||||
property Data: TStringList read fOriginalData;
|
property Branches: TBranchList read fBranches write fBranches;
|
||||||
property RootNode: TTreeNode read fRootNode write fRootNode;
|
|
||||||
published
|
published
|
||||||
property FilteredTreeview: TTreeview read fFilteredTreeview write SetFilteredTreeview;
|
property FilteredTreeview: TTreeview read fFilteredTreeview write SetFilteredTreeview;
|
||||||
property OnGetImageIndex: TImageIndexEvent read fOnGetImageIndex write fOnGetImageIndex; deprecated 'use OnDrawItem handler in FilteredListbox';
|
property OnGetImageIndex: TImageIndexEvent read fOnGetImageIndex write fOnGetImageIndex;
|
||||||
|
// deprecated 'use OnGetImageIndex handler in FilteredTreeview';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TFileNameItem }
|
{ TFileNameItem }
|
||||||
@ -82,6 +100,199 @@ begin
|
|||||||
RegisterComponents('LazControls',[TTreeFilterEdit]);
|
RegisterComponents('LazControls',[TTreeFilterEdit]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TBranch }
|
||||||
|
|
||||||
|
constructor TBranch.Create(AOwner: TTreeFilterEdit; ARootNode: TTreeNode);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
fOwner:=AOwner;
|
||||||
|
fRootNode:=ARootNode; // RootNode can also be Nil. Then all items are at top level.
|
||||||
|
fOriginalData:=TStringList.Create;
|
||||||
|
fSortedData:=TStringList.Create;
|
||||||
|
fFilenameMap:=TStringToStringTree.Create(True);
|
||||||
|
fImgIndex:=-1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TBranch.Destroy;
|
||||||
|
begin
|
||||||
|
fFilenameMap.Free;
|
||||||
|
fSortedData.Free;
|
||||||
|
fOriginalData.Free;
|
||||||
|
FreeTVNodeData(fRootNode);
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBranch.AddNodeData(ANodeText: string; AData: TObject; AFullFilename: string);
|
||||||
|
begin
|
||||||
|
fOriginalData.AddObject(ANodeText, AData);
|
||||||
|
if AFullFilename <> '' then
|
||||||
|
fFilenameMap[ANodeText]:=AFullFilename;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TBranch.CompareFNs(AFilename1,AFilename2: string): integer;
|
||||||
|
begin
|
||||||
|
if fOwner.SortData then
|
||||||
|
Result:=CompareFilenames(AFilename1, AFilename2)
|
||||||
|
else if fOwner.fShowDirHierarchy then
|
||||||
|
Result:=CompareFilenames(ExtractFilePath(AFilename1), ExtractFilePath(AFilename2))
|
||||||
|
else
|
||||||
|
Result:=0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBranch.SortAndFilter;
|
||||||
|
// Copy data from fOriginalData to fSortedData in sorted order
|
||||||
|
var
|
||||||
|
Origi, i: Integer;
|
||||||
|
FileN: string;
|
||||||
|
begin
|
||||||
|
fSortedData.Clear;
|
||||||
|
for Origi:=0 to fOriginalData.Count-1 do begin
|
||||||
|
FileN:=fOriginalData[Origi];
|
||||||
|
if (fOwner.Filter='') or (Pos(fOwner.Filter,lowercase(FileN))>0) then begin
|
||||||
|
i:=fSortedData.Count-1;
|
||||||
|
while i>=0 do begin
|
||||||
|
if CompareFNs(FileN,fSortedData[i])>=0 then break;
|
||||||
|
dec(i);
|
||||||
|
end;
|
||||||
|
fSortedData.InsertObject(i+1,FileN, fOriginalData.Objects[Origi]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBranch.ApplyFilter;
|
||||||
|
var
|
||||||
|
TVNode: TTreeNode;
|
||||||
|
i: Integer;
|
||||||
|
FileN, s: string;
|
||||||
|
ena: Boolean;
|
||||||
|
begin
|
||||||
|
if fFilenameMap.Count > 0 then
|
||||||
|
FreeTVNodeData(fRootNode); // Free node data now, it will be filled later.
|
||||||
|
if Assigned(fRootNode) then
|
||||||
|
fRootNode.DeleteChildren // Delete old tree nodes.
|
||||||
|
else
|
||||||
|
fOwner.FilteredTreeview.Items.Clear;
|
||||||
|
if fOwner.ShowDirHierarchy then
|
||||||
|
fTVNodeStack:=TTreeNodeList.Create;
|
||||||
|
for i:=0 to fSortedData.Count-1 do begin
|
||||||
|
FileN:=fSortedData[i];
|
||||||
|
if fOwner.ShowDirHierarchy then begin
|
||||||
|
TVClearUnneededAndCreateHierachy(FileN);
|
||||||
|
TVNode:=fTVNodeStack[fTVNodeStack.Count-1];
|
||||||
|
end
|
||||||
|
else
|
||||||
|
TVNode:=fOwner.FilteredTreeview.Items.AddChild(fRootNode,FileN);
|
||||||
|
// else TVNode:=fFilteredTreeview.Items.Add(Nil,FileN);
|
||||||
|
if fFilenameMap.Count > 0 then begin
|
||||||
|
s:=FileN;
|
||||||
|
if fFilenameMap.Contains(FileN) then
|
||||||
|
s:=fFilenameMap[FileN]; // Full file name.
|
||||||
|
TVNode.Data:=TFileNameItem.Create(s);
|
||||||
|
end;
|
||||||
|
ena := True;
|
||||||
|
if Assigned(fOwner.OnGetImageIndex) then
|
||||||
|
fImgIndex:=fOwner.OnGetImageIndex(FileN, fSortedData.Objects[i], ena);
|
||||||
|
TVNode.ImageIndex:=fImgIndex;
|
||||||
|
TVNode.SelectedIndex:=fImgIndex;
|
||||||
|
// if Assigned(fSelectedPart) then
|
||||||
|
// TVNode.Selected:=fSelectedPart=fSortedData.Objects[i];
|
||||||
|
end;
|
||||||
|
if fOwner.ShowDirHierarchy then // TVDeleteUnneededNodes(0); ?
|
||||||
|
fTVNodeStack.Free;
|
||||||
|
if Assigned(fRootNode) then
|
||||||
|
fRootNode.Expanded:=True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBranch.FreeTVNodeData(Node: TTreeNode);
|
||||||
|
var
|
||||||
|
Child: TTreeNode;
|
||||||
|
begin
|
||||||
|
if Node=nil then exit;
|
||||||
|
if (Node.Data<>nil) then begin
|
||||||
|
TObject(Node.Data).Free;
|
||||||
|
Node.Data:=nil;
|
||||||
|
end;
|
||||||
|
Child:=Node.GetFirstChild;
|
||||||
|
while Child<>nil do
|
||||||
|
begin
|
||||||
|
FreeTVNodeData(Child); // Recursive call.
|
||||||
|
Child:=Child.GetNextSibling;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBranch.TVDeleteUnneededNodes(p: integer);
|
||||||
|
// delete all nodes behind the nodes in the stack, and depth>=p
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
Node: TTreeNode;
|
||||||
|
begin
|
||||||
|
for i:=fTVNodeStack.Count-1 downto p do begin
|
||||||
|
Node:=fTVNodeStack[i];
|
||||||
|
while Node.GetNextSibling<>nil do
|
||||||
|
Node.GetNextSibling.Free;
|
||||||
|
end;
|
||||||
|
fTVNodeStack.Count:=p;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TBranch.TVClearUnneededAndCreateHierachy(Filename: string);
|
||||||
|
// TVNodeStack contains a path of TTreeNode for the last filename
|
||||||
|
var
|
||||||
|
DelimPos: Integer;
|
||||||
|
FilePart: String;
|
||||||
|
Node: TTreeNode;
|
||||||
|
p: Integer;
|
||||||
|
begin
|
||||||
|
p:=0;
|
||||||
|
while Filename<>'' do begin
|
||||||
|
// get the next file name part
|
||||||
|
DelimPos:=System.Pos(PathDelim,Filename);
|
||||||
|
if DelimPos>0 then begin
|
||||||
|
FilePart:=copy(Filename,1,DelimPos-1);
|
||||||
|
Filename:=copy(Filename,DelimPos+1,length(Filename));
|
||||||
|
end else begin
|
||||||
|
FilePart:=Filename;
|
||||||
|
Filename:='';
|
||||||
|
end;
|
||||||
|
//debugln(['ClearUnneededAndCreateHierachy FilePart=',FilePart,' Filename=',Filename,' p=',p]);
|
||||||
|
if p < fTVNodeStack.Count then begin
|
||||||
|
Node:=fTVNodeStack[p];
|
||||||
|
if (FilePart=Node.Text) and (Node.Data=nil) then begin
|
||||||
|
// same sub directory
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
// change directory => last directory is complete
|
||||||
|
// => delete unneeded nodes after last path
|
||||||
|
TVDeleteUnneededNodes(p+1);
|
||||||
|
if Node.GetNextSibling<>nil then begin
|
||||||
|
Node:=Node.GetNextSibling;
|
||||||
|
Node.Text:=FilePart;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Node:=fOwner.FilteredTreeview.Items.Add(Node,FilePart);
|
||||||
|
fTVNodeStack[p]:=Node;
|
||||||
|
end;
|
||||||
|
end else begin
|
||||||
|
// new sub node
|
||||||
|
if p>0 then
|
||||||
|
Node:=fTVNodeStack[p-1]
|
||||||
|
else
|
||||||
|
Node:=fRootNode;
|
||||||
|
if Node.GetFirstChild<>nil then begin
|
||||||
|
Node:=Node.GetFirstChild;
|
||||||
|
Node.Text:=FilePart;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Node:=fOwner.FilteredTreeview.Items.AddChild(Node,FilePart);
|
||||||
|
fTVNodeStack.Add(Node);
|
||||||
|
end;
|
||||||
|
if (Filename<>'') then begin
|
||||||
|
Node.ImageIndex:=fOwner.ImageIndexDirectory;
|
||||||
|
Node.SelectedIndex:=Node.ImageIndex;
|
||||||
|
end;
|
||||||
|
inc(p);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TFileNameItem }
|
{ TFileNameItem }
|
||||||
|
|
||||||
constructor TFileNameItem.Create(AFilename: string);
|
constructor TFileNameItem.Create(AFilename: string);
|
||||||
@ -94,21 +305,14 @@ end;
|
|||||||
constructor TTreeFilterEdit.Create(AOwner: TComponent);
|
constructor TTreeFilterEdit.Create(AOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
inherited Create(AOwner);
|
inherited Create(AOwner);
|
||||||
fOriginalData:=TStringList.Create;
|
|
||||||
fSelectionList:=TStringList.Create;
|
fSelectionList:=TStringList.Create;
|
||||||
fFilenameMap:=TStringToStringTree.Create(True);
|
|
||||||
fSortedData:=TStringList.Create;
|
|
||||||
fImageIndexDirectory := -1;
|
fImageIndexDirectory := -1;
|
||||||
fImgIndex:=-1;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TTreeFilterEdit.Destroy;
|
destructor TTreeFilterEdit.Destroy;
|
||||||
begin
|
begin
|
||||||
fSortedData.Free;
|
fBranches.Free;
|
||||||
fFilenameMap.Free;
|
|
||||||
fSelectionList.Free;
|
fSelectionList.Free;
|
||||||
fOriginalData.Free;
|
|
||||||
FreeTVNodeData(fRootNode);
|
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -132,11 +336,6 @@ begin
|
|||||||
fShowDirHierarchy:=AValue;
|
fShowDirHierarchy:=AValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TTreeFilterEdit.MapShortToFullFilename(ShortFilename, FullFilename: string);
|
|
||||||
begin
|
|
||||||
fFilenameMap[ShortFilename]:=FullFilename;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TTreeFilterEdit.ApplyFilterCore;
|
procedure TTreeFilterEdit.ApplyFilterCore;
|
||||||
var
|
var
|
||||||
TVNode: TTreeNode;
|
TVNode: TTreeNode;
|
||||||
@ -144,73 +343,30 @@ var
|
|||||||
FileN, s: string;
|
FileN, s: string;
|
||||||
ena: Boolean;
|
ena: Boolean;
|
||||||
begin
|
begin
|
||||||
if fFilenameMap.Count > 0 then
|
|
||||||
FreeTVNodeData(fRootNode); // Free node data now, it will be filled later.
|
|
||||||
if Assigned(fRootNode) then // Delete old tree nodes.
|
|
||||||
fRootNode.DeleteChildren
|
|
||||||
else
|
|
||||||
fFilteredTreeview.Items.Clear;
|
|
||||||
if fShowDirHierarchy then
|
|
||||||
fTVNodeStack:=TFPList.Create;
|
|
||||||
fFilteredTreeview.BeginUpdate;
|
fFilteredTreeview.BeginUpdate;
|
||||||
for i:=0 to fSortedData.Count-1 do begin
|
if Assigned(fBranches) then begin // Filter the brances
|
||||||
FileN:=fSortedData[i];
|
for i:=0 to fBranches.Count-1 do
|
||||||
if fShowDirHierarchy then begin
|
fBranches[i].ApplyFilter;
|
||||||
TVClearUnneededAndCreateHierachy(FileN);
|
|
||||||
TVNode:=TTreeNode(fTVNodeStack[fTVNodeStack.Count-1]);
|
|
||||||
end
|
end
|
||||||
else if Assigned(fRootNode) then
|
else begin // Filter the whole tree.
|
||||||
TVNode:=fFilteredTreeview.Items.AddChild(fRootNode,FileN)
|
fFilteredTreeview.Items.Clear;
|
||||||
else
|
// ToDo ...
|
||||||
TVNode:=fFilteredTreeview.Items.Add(Nil,FileN);
|
|
||||||
if fFilenameMap.Count > 0 then begin
|
|
||||||
s:=FileN;
|
|
||||||
if fFilenameMap.Contains(FileN) then
|
|
||||||
s:=fFilenameMap[FileN]; // Full file name.
|
|
||||||
TVNode.Data:=TFileNameItem.Create(s);
|
|
||||||
end;
|
end;
|
||||||
ena := True;
|
|
||||||
if Assigned(OnGetImageIndex) then
|
|
||||||
fImgIndex:=OnGetImageIndex(FileN, fSortedData.Objects[i], ena);
|
|
||||||
TVNode.ImageIndex:=fImgIndex;
|
|
||||||
TVNode.SelectedIndex:=fImgIndex;
|
|
||||||
if Assigned(fSelectedPart) then
|
|
||||||
TVNode.Selected:=fSelectedPart=fSortedData.Objects[i];
|
|
||||||
end;
|
|
||||||
if fShowDirHierarchy then // TVDeleteUnneededNodes(0); ?
|
|
||||||
fTVNodeStack.Free;
|
|
||||||
if Assigned(fRootNode) then
|
|
||||||
fRootNode.Expanded:=True;
|
|
||||||
fFilteredTreeview.EndUpdate;
|
fFilteredTreeview.EndUpdate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TTreeFilterEdit.CompareFNs(AFilename1,AFilename2: string): integer;
|
|
||||||
begin
|
|
||||||
if SortData then
|
|
||||||
Result:=CompareFilenames(AFilename1, AFilename2)
|
|
||||||
else if fShowDirHierarchy then
|
|
||||||
Result:=CompareFilenames(ExtractFilePath(AFilename1), ExtractFilePath(AFilename2))
|
|
||||||
else
|
|
||||||
Result:=0;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TTreeFilterEdit.SortAndFilter;
|
procedure TTreeFilterEdit.SortAndFilter;
|
||||||
// Copy data from fOriginalData to fSortedData in sorted order
|
// Copy data from fOriginalData to fSortedData in sorted order
|
||||||
var
|
var
|
||||||
Origi, i: Integer;
|
Origi, i: Integer;
|
||||||
FileN: string;
|
FileN: string;
|
||||||
begin
|
begin
|
||||||
fSortedData.Clear;
|
if Assigned(fBranches) then begin // Filter the brances
|
||||||
for Origi:=0 to fOriginalData.Count-1 do begin
|
for i:=0 to fBranches.Count-1 do
|
||||||
FileN:=fOriginalData[Origi];
|
fBranches[i].SortAndFilter;
|
||||||
if (Filter='') or (Pos(Filter,lowercase(FileN))>0) then begin
|
end
|
||||||
i:=fSortedData.Count-1;
|
else begin // Filter the whole tree.
|
||||||
while i>=0 do begin
|
// ToDo ...
|
||||||
if CompareFNs(FileN,fSortedData[i])>=0 then break;
|
|
||||||
dec(i);
|
|
||||||
end;
|
|
||||||
fSortedData.InsertObject(i+1,FileN, fOriginalData.Objects[Origi]);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -247,8 +403,31 @@ begin
|
|||||||
fFilteredTreeview.Selected:=ANode;
|
fFilteredTreeview.Selected:=ANode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TTreeFilterEdit.GetBranch(ARootNode: TTreeNode): TBranch;
|
||||||
|
// Get a new or existing branch for a node.
|
||||||
|
var
|
||||||
|
branch: TBranch;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if not Assigned(fBranches) then
|
||||||
|
fBranches := TBranchList.Create;
|
||||||
|
branch := Nil;
|
||||||
|
for i := 0 to fBranches.Count-1 do
|
||||||
|
if fBranches[i].fRootNode = ARootNode then begin
|
||||||
|
branch := fBranches[i];
|
||||||
|
branch.fOriginalData.Clear;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
if branch = Nil then begin
|
||||||
|
branch := TBranch.Create(Self, ARootNode);
|
||||||
|
fBranches.Add(branch);
|
||||||
|
end;
|
||||||
|
Result := branch;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTreeFilterEdit.MoveNext;
|
procedure TTreeFilterEdit.MoveNext;
|
||||||
var tn: TTreeNode;
|
var
|
||||||
|
tn: TTreeNode;
|
||||||
begin
|
begin
|
||||||
tn := fFilteredTreeview.Selected;
|
tn := fFilteredTreeview.Selected;
|
||||||
if not Assigned(tn) then
|
if not Assigned(tn) then
|
||||||
@ -264,7 +443,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TTreeFilterEdit.MovePrev;
|
procedure TTreeFilterEdit.MovePrev;
|
||||||
var tn: TTreeNode;
|
var
|
||||||
|
tn: TTreeNode;
|
||||||
begin
|
begin
|
||||||
tn := fFilteredTreeview.Selected;
|
tn := fFilteredTreeview.Selected;
|
||||||
if not Assigned(tn) then Exit;
|
if not Assigned(tn) then Exit;
|
||||||
@ -273,95 +453,5 @@ begin
|
|||||||
fFilteredTreeview.Selected := tn;
|
fFilteredTreeview.Selected := tn;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TTreeFilterEdit.FreeTVNodeData(Node: TTreeNode);
|
|
||||||
var
|
|
||||||
Child: TTreeNode;
|
|
||||||
begin
|
|
||||||
if Node=nil then exit;
|
|
||||||
if (Node.Data<>nil) then begin
|
|
||||||
TObject(Node.Data).Free;
|
|
||||||
Node.Data:=nil;
|
|
||||||
end;
|
|
||||||
Child:=Node.GetFirstChild;
|
|
||||||
while Child<>nil do
|
|
||||||
begin
|
|
||||||
FreeTVNodeData(Child);
|
|
||||||
Child:=Child.GetNextSibling;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TTreeFilterEdit.TVDeleteUnneededNodes(p: integer);
|
|
||||||
// delete all nodes behind the nodes in the stack, and depth>=p
|
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
Node: TTreeNode;
|
|
||||||
begin
|
|
||||||
for i:=fTVNodeStack.Count-1 downto p do begin
|
|
||||||
Node:=TTreeNode(fTVNodeStack[i]);
|
|
||||||
while Node.GetNextSibling<>nil do
|
|
||||||
Node.GetNextSibling.Free;
|
|
||||||
end;
|
|
||||||
fTVNodeStack.Count:=p;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TTreeFilterEdit.TVClearUnneededAndCreateHierachy(Filename: string);
|
|
||||||
// TVNodeStack contains a path of TTreeNode for the last filename
|
|
||||||
var
|
|
||||||
DelimPos: Integer;
|
|
||||||
FilePart: String;
|
|
||||||
Node: TTreeNode;
|
|
||||||
p: Integer;
|
|
||||||
begin
|
|
||||||
p:=0;
|
|
||||||
while Filename<>'' do begin
|
|
||||||
// get the next file name part
|
|
||||||
DelimPos:=System.Pos(PathDelim,Filename);
|
|
||||||
if DelimPos>0 then begin
|
|
||||||
FilePart:=copy(Filename,1,DelimPos-1);
|
|
||||||
Filename:=copy(Filename,DelimPos+1,length(Filename));
|
|
||||||
end else begin
|
|
||||||
FilePart:=Filename;
|
|
||||||
Filename:='';
|
|
||||||
end;
|
|
||||||
//debugln(['ClearUnneededAndCreateHierachy FilePart=',FilePart,' Filename=',Filename,' p=',p]);
|
|
||||||
if p < fTVNodeStack.Count then begin
|
|
||||||
Node:=TTreeNode(fTVNodeStack[p]);
|
|
||||||
if (FilePart=Node.Text) and (Node.Data=nil) then begin
|
|
||||||
// same sub directory
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
// change directory => last directory is complete
|
|
||||||
// => delete unneeded nodes after last path
|
|
||||||
TVDeleteUnneededNodes(p+1);
|
|
||||||
if Node.GetNextSibling<>nil then begin
|
|
||||||
Node:=Node.GetNextSibling;
|
|
||||||
Node.Text:=FilePart;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Node:=fFilteredTreeview.Items.Add(Node,FilePart);
|
|
||||||
fTVNodeStack[p]:=Node;
|
|
||||||
end;
|
|
||||||
end else begin
|
|
||||||
// new sub node
|
|
||||||
if p>0 then
|
|
||||||
Node:=TTreeNode(fTVNodeStack[p-1])
|
|
||||||
else
|
|
||||||
Node:=fRootNode;
|
|
||||||
if Node.GetFirstChild<>nil then begin
|
|
||||||
Node:=Node.GetFirstChild;
|
|
||||||
Node.Text:=FilePart;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Node:=fFilteredTreeview.Items.AddChild(Node,FilePart);
|
|
||||||
fTVNodeStack.Add(Node);
|
|
||||||
end;
|
|
||||||
if (Filename<>'') then begin
|
|
||||||
Node.ImageIndex:=fImageIndexDirectory;
|
|
||||||
Node.SelectedIndex:=Node.ImageIndex;
|
|
||||||
end;
|
|
||||||
inc(p);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ object ProjectInspectorForm: TProjectInspectorForm
|
|||||||
RightClickSelect = True
|
RightClickSelect = True
|
||||||
TabOrder = 0
|
TabOrder = 0
|
||||||
OnDblClick = ItemsTreeViewDblClick
|
OnDblClick = ItemsTreeViewDblClick
|
||||||
|
OnGetImageIndex = ItemsTreeViewGetImageIndex
|
||||||
OnKeyDown = ItemsTreeViewKeyDown
|
OnKeyDown = ItemsTreeViewKeyDown
|
||||||
OnSelectionChanged = ItemsTreeViewSelectionChanged
|
OnSelectionChanged = ItemsTreeViewSelectionChanged
|
||||||
Options = [tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoRightClickSelect, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw]
|
Options = [tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoRightClickSelect, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw]
|
||||||
|
@ -102,8 +102,8 @@ type
|
|||||||
procedure DirectoryHierarchySpeedButtonClick(Sender: TObject);
|
procedure DirectoryHierarchySpeedButtonClick(Sender: TObject);
|
||||||
procedure ItemsPopupMenuPopup(Sender: TObject);
|
procedure ItemsPopupMenuPopup(Sender: TObject);
|
||||||
procedure ItemsTreeViewDblClick(Sender: TObject);
|
procedure ItemsTreeViewDblClick(Sender: TObject);
|
||||||
procedure ItemsTreeViewKeyDown(Sender: TObject; var Key: Word;
|
procedure ItemsTreeViewGetImageIndex(Sender: TObject; Node: TTreeNode);
|
||||||
Shift: TShiftState);
|
procedure ItemsTreeViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||||
procedure ItemsTreeViewSelectionChanged(Sender: TObject);
|
procedure ItemsTreeViewSelectionChanged(Sender: TObject);
|
||||||
procedure MoveDependencyUpClick(Sender: TObject);
|
procedure MoveDependencyUpClick(Sender: TObject);
|
||||||
procedure MoveDependencyDownClick(Sender: TObject);
|
procedure MoveDependencyDownClick(Sender: TObject);
|
||||||
@ -211,6 +211,11 @@ begin
|
|||||||
OpenBitBtnClick(Self);
|
OpenBitBtnClick(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TProjectInspectorForm.ItemsTreeViewGetImageIndex(Sender: TObject; Node: TTreeNode);
|
||||||
|
begin
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TProjectInspectorForm.ItemsTreeViewKeyDown(Sender: TObject;
|
procedure TProjectInspectorForm.ItemsTreeViewKeyDown(Sender: TObject;
|
||||||
var Key: Word; Shift: TShiftState);
|
var Key: Word; Shift: TShiftState);
|
||||||
begin
|
begin
|
||||||
@ -614,6 +619,7 @@ procedure TProjectInspectorForm.UpdateProjectFiles(Immediately: boolean);
|
|||||||
var
|
var
|
||||||
CurFile: TUnitInfo;
|
CurFile: TUnitInfo;
|
||||||
Filename: String;
|
Filename: String;
|
||||||
|
FilteredBranch: TBranch;
|
||||||
begin
|
begin
|
||||||
if (not Immediately) or (FUpdateLock>0) or (not Visible) then begin
|
if (not Immediately) or (FUpdateLock>0) or (not Visible) then begin
|
||||||
Include(FFlags,pifFilesChanged);
|
Include(FFlags,pifFilesChanged);
|
||||||
@ -622,20 +628,17 @@ begin
|
|||||||
end;
|
end;
|
||||||
Exclude(FFlags,pifFilesChanged);
|
Exclude(FFlags,pifFilesChanged);
|
||||||
if LazProject=nil then Exit;
|
if LazProject=nil then Exit;
|
||||||
FilterEdit.RootNode:=FFilesNode;
|
FilteredBranch := FilterEdit.GetBranch(FFilesNode);
|
||||||
FilterEdit.SelectedPart:=FNextSelectedPart;
|
FilterEdit.SelectedPart:=FNextSelectedPart;
|
||||||
FilterEdit.ShowDirHierarchy:=ShowDirectoryHierarchy;
|
FilterEdit.ShowDirHierarchy:=ShowDirectoryHierarchy;
|
||||||
FilterEdit.SortData:=SortAlphabetically;
|
FilterEdit.SortData:=SortAlphabetically;
|
||||||
FilterEdit.ImageIndexDirectory:=ImageIndexDirectory;
|
FilterEdit.ImageIndexDirectory:=ImageIndexDirectory;
|
||||||
FilterEdit.Data.Clear;
|
|
||||||
// collect and sort files
|
// collect and sort files
|
||||||
CurFile:=LazProject.FirstPartOfProject;
|
CurFile:=LazProject.FirstPartOfProject;
|
||||||
while CurFile<>nil do begin
|
while CurFile<>nil do begin
|
||||||
Filename:=CurFile.GetShortFilename(true);
|
Filename:=CurFile.GetShortFilename(true);
|
||||||
if Filename<>'' then begin
|
if Filename<>'' then
|
||||||
FilterEdit.Data.AddObject(Filename, CurFile);
|
FilteredBranch.AddNodeData(Filename, CurFile, CurFile.Filename);
|
||||||
FilterEdit.MapShortToFullFilename(Filename, CurFile.Filename);
|
|
||||||
end;
|
|
||||||
CurFile:=CurFile.NextPartOfProject;
|
CurFile:=CurFile.NextPartOfProject;
|
||||||
end;
|
end;
|
||||||
FilterEdit.InvalidateFilter; // Data is shown by FilterEdit.
|
FilterEdit.InvalidateFilter; // Data is shown by FilterEdit.
|
||||||
|
@ -146,7 +146,7 @@ begin
|
|||||||
InstallPkgSetDialog:=TInstallPkgSetDialog.Create(nil);
|
InstallPkgSetDialog:=TInstallPkgSetDialog.Create(nil);
|
||||||
try
|
try
|
||||||
InstallPkgSetDialog.OldInstalledPackages:=OldInstalledPackages;
|
InstallPkgSetDialog.OldInstalledPackages:=OldInstalledPackages;
|
||||||
InstallPkgSetDialog.UpdateAvailablePackages;
|
// InstallPkgSetDialog.UpdateAvailablePackages;
|
||||||
InstallPkgSetDialog.UpdateButtonStates;
|
InstallPkgSetDialog.UpdateButtonStates;
|
||||||
InstallPkgSetDialog.OnCheckInstallPackageList:=CheckInstallPackageList;
|
InstallPkgSetDialog.OnCheckInstallPackageList:=CheckInstallPackageList;
|
||||||
Result:=InstallPkgSetDialog.ShowModal;
|
Result:=InstallPkgSetDialog.ShowModal;
|
||||||
@ -306,8 +306,7 @@ begin
|
|||||||
AddToUninstall;
|
AddToUninstall;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TInstallPkgSetDialog.SetOldInstalledPackages(
|
procedure TInstallPkgSetDialog.SetOldInstalledPackages(const AValue: TPkgDependency);
|
||||||
const AValue: TPkgDependency);
|
|
||||||
begin
|
begin
|
||||||
if FOldInstalledPackages=AValue then exit;
|
if FOldInstalledPackages=AValue then exit;
|
||||||
FOldInstalledPackages:=AValue;
|
FOldInstalledPackages:=AValue;
|
||||||
@ -373,10 +372,14 @@ var
|
|||||||
ANode: TAVLTreeNode;
|
ANode: TAVLTreeNode;
|
||||||
Pkg: TLazPackageID;
|
Pkg: TLazPackageID;
|
||||||
PkgName: String;
|
PkgName: String;
|
||||||
|
DuplCheck: TStringList; // Add pkg names also here to filter out duplicates.
|
||||||
|
FilteredBranch: TBranch;
|
||||||
begin
|
begin
|
||||||
|
DuplCheck:=TStringList.Create;
|
||||||
|
try
|
||||||
if fAvailablePackages.Count=0 then
|
if fAvailablePackages.Count=0 then
|
||||||
PackageGraph.IteratePackages(fpfSearchAllExisting,@OnIteratePackages);
|
PackageGraph.IteratePackages(fpfSearchAllExisting,@OnIteratePackages);
|
||||||
AvailableFilterEdit.Data.Clear;
|
FilteredBranch := AvailableFilterEdit.GetBranch(Nil); // All items are top level.
|
||||||
ANode:=fAvailablePackages.FindLowest;
|
ANode:=fAvailablePackages.FindLowest;
|
||||||
while ANode<>nil do begin
|
while ANode<>nil do begin
|
||||||
Pkg:=TLazPackageID(ANode.Data);
|
Pkg:=TLazPackageID(ANode.Data);
|
||||||
@ -385,13 +388,18 @@ begin
|
|||||||
then begin
|
then begin
|
||||||
if (not PackageInInstallList(Pkg.Name)) then begin
|
if (not PackageInInstallList(Pkg.Name)) then begin
|
||||||
PkgName:=Pkg.IDAsString;
|
PkgName:=Pkg.IDAsString;
|
||||||
if (AvailableFilterEdit.Data.IndexOf(PkgName)<0) then
|
if (DuplCheck.IndexOf(PkgName)<0) then begin
|
||||||
AvailableFilterEdit.Data.AddObject(PkgName,Pkg);
|
DuplCheck.Add(PkgName);
|
||||||
|
FilteredBranch.AddNodeData(PkgName, Pkg);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
ANode:=fAvailablePackages.FindSuccessor(ANode);
|
ANode:=fAvailablePackages.FindSuccessor(ANode);
|
||||||
end;
|
end;
|
||||||
AvailableFilterEdit.InvalidateFilter;
|
AvailableFilterEdit.InvalidateFilter;
|
||||||
|
finally
|
||||||
|
DuplCheck.Free;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TInstallPkgSetDialog.UpdateNewInstalledPackages;
|
procedure TInstallPkgSetDialog.UpdateNewInstalledPackages;
|
||||||
|
@ -1635,24 +1635,22 @@ var
|
|||||||
CurFile: TPkgFile;
|
CurFile: TPkgFile;
|
||||||
CurNode: TTreeNode;
|
CurNode: TTreeNode;
|
||||||
NextNode: TTreeNode;
|
NextNode: TTreeNode;
|
||||||
|
FilteredBranch: TBranch;
|
||||||
Filename: String;
|
Filename: String;
|
||||||
ena: Boolean;
|
ena: Boolean;
|
||||||
begin
|
begin
|
||||||
if LazPackage=nil then exit;
|
if LazPackage=nil then exit;
|
||||||
FilterEdit.RootNode:=FFilesNode;
|
FilteredBranch := FilterEdit.GetBranch(FFilesNode);
|
||||||
FilterEdit.SelectedPart:=FNextSelectedPart;
|
FilterEdit.SelectedPart:=FNextSelectedPart;
|
||||||
FilterEdit.ShowDirHierarchy:=ShowDirectoryHierarchy;
|
FilterEdit.ShowDirHierarchy:=ShowDirectoryHierarchy;
|
||||||
FilterEdit.SortData:=SortAlphabetically;
|
FilterEdit.SortData:=SortAlphabetically;
|
||||||
FilterEdit.ImageIndexDirectory:=ImageIndexDirectory;
|
FilterEdit.ImageIndexDirectory:=ImageIndexDirectory;
|
||||||
FilterEdit.Data.Clear;
|
|
||||||
// collect and sort files
|
// collect and sort files
|
||||||
for i:=0 to LazPackage.FileCount-1 do begin
|
for i:=0 to LazPackage.FileCount-1 do begin
|
||||||
CurFile:=LazPackage.Files[i];
|
CurFile:=LazPackage.Files[i];
|
||||||
Filename:=CurFile.GetShortFilename(true);
|
Filename:=CurFile.GetShortFilename(true);
|
||||||
if Filename<>'' then begin
|
if Filename<>'' then
|
||||||
FilterEdit.Data.AddObject(Filename, CurFile);
|
FilteredBranch.AddNodeData(Filename, CurFile, CurFile.Filename);
|
||||||
FilterEdit.MapShortToFullFilename(Filename, CurFile.Filename);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
FilterEdit.InvalidateFilter; // Data is shown by FilterEdit.
|
FilterEdit.InvalidateFilter; // Data is shown by FilterEdit.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user