mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-07 15:57:56 +02:00
Improve ListFilterEdit, make it more object oriented
git-svn-id: trunk@31539 -
This commit is contained in:
parent
7bf73f4406
commit
ebb595fe19
@ -16,6 +16,56 @@ type
|
||||
TImageIndexEvent = function (Str: String; Data: TObject;
|
||||
var IsEnabled: Boolean): Integer of object;
|
||||
|
||||
TListFilterEdit = class;
|
||||
|
||||
{ TViewControl }
|
||||
|
||||
// A wrapper for the visual control displaying data
|
||||
TViewControl = class
|
||||
private
|
||||
fOwner: TListFilterEdit;
|
||||
fImgIndex: Integer;
|
||||
fSortedData: TStringList;
|
||||
function CompareFNs(AFilename1,AFilename2: string): integer;
|
||||
procedure SortAndFilter;
|
||||
procedure ApplyFilter; virtual; abstract;
|
||||
procedure StoreSelection; virtual; abstract;
|
||||
procedure RestoreSelection; virtual; abstract;
|
||||
public
|
||||
constructor Create(AOwner: TListFilterEdit);
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
{ TViewControlTreeview }
|
||||
|
||||
TViewControlTreeview = class(TViewControl)
|
||||
private
|
||||
fTreeview: TTreeview;
|
||||
fTVNodeStack: TFPList;
|
||||
procedure ApplyFilter; override;
|
||||
procedure StoreSelection; override;
|
||||
procedure RestoreSelection; override;
|
||||
procedure FreeTVNodeData(Node: TTreeNode);
|
||||
procedure TVDeleteUnneededNodes(p: integer);
|
||||
procedure TVClearUnneededAndCreateHierachy(Filename: string);
|
||||
public
|
||||
constructor Create(AOwner: TListFilterEdit; aTreeview: TTreeview);
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
{ TViewControlListbox }
|
||||
|
||||
TViewControlListbox = class(TViewControl)
|
||||
private
|
||||
fListbox: TListbox;
|
||||
procedure ApplyFilter; override;
|
||||
procedure StoreSelection; override;
|
||||
procedure RestoreSelection; override;
|
||||
public
|
||||
constructor Create(AOwner: TListFilterEdit; aListbox: TListbox);
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
{ TListFilterEdit }
|
||||
|
||||
TListFilterEdit = class(TCustomEditButton)
|
||||
@ -30,10 +80,12 @@ type
|
||||
// A control showing the (filtered) data. These are exclusive, only one is used.
|
||||
fFilteredTreeview: TTreeview;
|
||||
fFilteredListbox: TListbox;
|
||||
fImageIndexDirectory: integer; // Needed if directory structure is shown.
|
||||
fViewControlWrapper: TViewControl; // Wraps either TTreeview or TListbox.
|
||||
fImageIndexDirectory: integer; // Needed if directory structure is shown.
|
||||
fImages4Listbox: TCustomImageList; // Listbox does not have ImageList of its own.
|
||||
fNeedUpdate: boolean;
|
||||
fIdleConnected: boolean;
|
||||
fNeedUpdate: Boolean;
|
||||
fIdleConnected: Boolean;
|
||||
fIsFirstUpdate: Boolean;
|
||||
fSelectedPart: TObject; // Select this node on next update
|
||||
fSelectionList: TStringList; // or store/restore the old selections here.
|
||||
fShowDirHierarchy: Boolean; // Show direcories / files as a tree structure.
|
||||
@ -41,30 +93,17 @@ type
|
||||
// Full filename in node data is needed when showing the directory hierarchy.
|
||||
// It is stored automatically if the map is populated by MapShortToFullFilename.
|
||||
fFilenameMap: TStringToStringTree;
|
||||
fTVNodeStack: TFPList;
|
||||
// Data supplied by caller through Data property.
|
||||
// Objects property is passed to OnGetImageIndex.
|
||||
fOriginalData: TStringList;
|
||||
// Data sorted for viewing.
|
||||
fSortedData: TStringList;
|
||||
fRootNode: TTreeNode; // The filtered items are under this node.
|
||||
fOnGetImageIndex: TImageIndexEvent;
|
||||
procedure SetFilter(const AValue: string);
|
||||
procedure SetFilteredTreeview(const AValue: TTreeview);
|
||||
procedure SetFilteredListbox(const AValue: TListBox);
|
||||
procedure SetShowDirHierarchy(const AValue: Boolean);
|
||||
procedure StoreTreeSelection;
|
||||
procedure StoreListSelection;
|
||||
procedure RestoreTreeSelection;
|
||||
procedure RestoreListSelection;
|
||||
procedure FreeTVNodeData(Node: TTreeNode);
|
||||
procedure TVDeleteUnneededNodes(p: integer);
|
||||
procedure TVClearUnneededAndCreateHierachy(Filename: string);
|
||||
function CompareFNs(AFilename1,AFilename2: string): integer;
|
||||
procedure SortAndFilter;
|
||||
procedure ApplyFilterToListBox;
|
||||
procedure ApplyFilterToTreeview;
|
||||
procedure SetIdleConnected(const AValue: boolean);
|
||||
procedure SetIdleConnected(const AValue: Boolean);
|
||||
protected
|
||||
function GetDefaultGlyph: TBitmap; override;
|
||||
function GetDefaultGlyphName: String; override;
|
||||
@ -78,8 +117,9 @@ type
|
||||
public
|
||||
property Filter: string read fFilter write SetFilter;
|
||||
property ImageIndexDirectory: integer read fImageIndexDirectory write fImageIndexDirectory;
|
||||
property IdleConnected: boolean read fIdleConnected write SetIdleConnected;
|
||||
property IdleConnected: Boolean read fIdleConnected write SetIdleConnected;
|
||||
property SelectedPart: TObject read fSelectedPart write fSelectedPart;
|
||||
property SelectionList: TStringList read fSelectionList;
|
||||
property ShowDirHierarchy: Boolean read fShowDirHierarchy write SetShowDirHierarchy;
|
||||
property SortData: Boolean read fSortData write fSortData;
|
||||
property Data: TStringList read fOriginalData;
|
||||
@ -163,11 +203,297 @@ begin
|
||||
RegisterComponents('LazControls',[TListFilterEdit]);
|
||||
end;
|
||||
|
||||
{ TFileNameItem }
|
||||
|
||||
constructor TFileNameItem.Create(AFilename: string);
|
||||
begin
|
||||
Filename:=AFilename;
|
||||
end;
|
||||
|
||||
{ TViewControl }
|
||||
|
||||
constructor TViewControl.Create(AOwner: TListFilterEdit);
|
||||
begin
|
||||
inherited Create;
|
||||
fOwner:=AOwner;
|
||||
fImgIndex:=-1;
|
||||
fSortedData:=TStringList.Create;
|
||||
end;
|
||||
|
||||
destructor TViewControl.Destroy;
|
||||
begin
|
||||
fSortedData.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TViewControl.CompareFNs(AFilename1,AFilename2: string): integer;
|
||||
begin
|
||||
if fOwner.fSortData then
|
||||
Result:=CompareFilenames(AFilename1, AFilename2)
|
||||
else if fOwner.fShowDirHierarchy then
|
||||
Result:=CompareFilenames(ExtractFilePath(AFilename1), ExtractFilePath(AFilename2))
|
||||
else
|
||||
Result:=0;
|
||||
end;
|
||||
|
||||
procedure TViewControl.SortAndFilter;
|
||||
// Copy data from fOriginalData to fSortedData in sorted order
|
||||
var
|
||||
Origi, i: Integer;
|
||||
FileN: string;
|
||||
begin
|
||||
fSortedData.Clear;
|
||||
for Origi:=0 to fOwner.fOriginalData.Count-1 do begin
|
||||
FileN:=fOwner.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, fOwner.fOriginalData.Objects[Origi]);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TViewControlTreeview }
|
||||
|
||||
constructor TViewControlTreeview.Create(AOwner: TListFilterEdit; aTreeview: TTreeview);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
fTreeview:=aTreeview;
|
||||
end;
|
||||
|
||||
destructor TViewControlTreeview.Destroy;
|
||||
begin
|
||||
FreeTVNodeData(fOwner.fRootNode);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TViewControlTreeview.ApplyFilter;
|
||||
var
|
||||
TVNode: TTreeNode;
|
||||
i: Integer;
|
||||
FileN, s: string;
|
||||
ena: Boolean;
|
||||
begin
|
||||
with fOwner do 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
|
||||
fTreeview.Items.Clear;
|
||||
if fShowDirHierarchy then
|
||||
fTVNodeStack:=TFPList.Create;
|
||||
fTreeview.BeginUpdate;
|
||||
for i:=0 to fSortedData.Count-1 do begin
|
||||
FileN:=fSortedData[i];
|
||||
if fShowDirHierarchy then begin
|
||||
TVClearUnneededAndCreateHierachy(FileN);
|
||||
TVNode:=TTreeNode(fTVNodeStack[fTVNodeStack.Count-1]);
|
||||
end
|
||||
else if Assigned(fRootNode) then
|
||||
TVNode:=fTreeview.Items.AddChild(fRootNode,FileN)
|
||||
else
|
||||
TVNode:=fTreeview.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;
|
||||
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;
|
||||
fTreeview.EndUpdate;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TViewControlTreeview.StoreSelection;
|
||||
var
|
||||
ANode: TTreeNode;
|
||||
begin
|
||||
ANode:=fTreeview.Selected;
|
||||
while ANode<>nil do begin
|
||||
fOwner.fSelectionList.Insert(0,ANode.Text);
|
||||
ANode:=ANode.Parent;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TViewControlTreeview.RestoreSelection;
|
||||
var
|
||||
ANode: TTreeNode;
|
||||
CurText: string;
|
||||
begin
|
||||
ANode:=nil;
|
||||
with fOwner do begin
|
||||
while fSelectionList.Count>0 do begin
|
||||
CurText:=fSelectionList[0];
|
||||
if ANode=nil then
|
||||
ANode:=fTreeview.Items.GetFirstNode
|
||||
else
|
||||
ANode:=ANode.GetFirstChild;
|
||||
while (ANode<>nil) and (ANode.Text<>CurText) do
|
||||
ANode:=ANode.GetNextSibling;
|
||||
if ANode=nil then break;
|
||||
fSelectionList.Delete(0);
|
||||
end;
|
||||
if ANode<>nil then
|
||||
fTreeview.Selected:=ANode;
|
||||
fSelectionList.Clear;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TViewControlTreeview.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 TViewControlTreeview.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 TViewControlTreeview.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:=fTreeview.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:=fOwner.fRootNode;
|
||||
if Node.GetFirstChild<>nil then begin
|
||||
Node:=Node.GetFirstChild;
|
||||
Node.Text:=FilePart;
|
||||
end
|
||||
else
|
||||
Node:=fTreeview.Items.AddChild(Node,FilePart);
|
||||
fTVNodeStack.Add(Node);
|
||||
end;
|
||||
if (Filename<>'') then begin
|
||||
Node.ImageIndex:=fOwner.fImageIndexDirectory;
|
||||
Node.SelectedIndex:=Node.ImageIndex;
|
||||
end;
|
||||
inc(p);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ TViewControlListbox }
|
||||
|
||||
constructor TViewControlListbox.Create(AOwner: TListFilterEdit; aListbox: TListbox);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
fListbox:=aListbox;
|
||||
end;
|
||||
|
||||
destructor TViewControlListbox.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TViewControlListbox.ApplyFilter;
|
||||
var
|
||||
i: Integer;
|
||||
FileN: string;
|
||||
begin
|
||||
fListbox.Clear;
|
||||
fListbox.Items.BeginUpdate;
|
||||
with fOwner do
|
||||
for i:=0 to fSortedData.Count-1 do begin
|
||||
FileN:=fSortedData[i];
|
||||
fListbox.Items.AddObject(FileN, fSortedData.Objects[i]);
|
||||
if Assigned(fSelectedPart) then
|
||||
fListbox.Selected[i]:=fSelectedPart=fSortedData.Objects[i];
|
||||
end;
|
||||
fListbox.Items.EndUpdate;
|
||||
end;
|
||||
|
||||
procedure TViewControlListbox.StoreSelection;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to fListbox.Count-1 do begin
|
||||
if fListbox.Selected[i] then
|
||||
fOwner.fSelectionList.Add(fListbox.Items[i]);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TViewControlListbox.RestoreSelection;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to fListbox.Count-1 do begin
|
||||
if fOwner.fSelectionList.IndexOf(fListbox.Items[i])>0 then
|
||||
fListbox.Selected[i]:=True;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ TListBoxFilterEdit }
|
||||
|
||||
@ -175,7 +501,6 @@ constructor TListFilterEdit.Create(AOwner: TComponent);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
fOriginalData:=TStringList.Create;
|
||||
fSortedData:=TStringList.Create;
|
||||
fSelectionList:=TStringList.Create;
|
||||
fFilenameMap:=TStringToStringTree.Create(True);
|
||||
fImageIndexDirectory := -1;
|
||||
@ -185,15 +510,15 @@ begin
|
||||
OnChange:=@FilterEditChange;
|
||||
OnEnter:=@FilterEditEnter;
|
||||
OnExit:=@FilterEditExit;
|
||||
fIsFirstUpdate:=True;
|
||||
end;
|
||||
|
||||
destructor TListFilterEdit.Destroy;
|
||||
begin
|
||||
FreeTVNodeData(fRootNode);
|
||||
fFilenameMap.Free;
|
||||
fSelectionList.Free;
|
||||
fSortedData.Free;
|
||||
fOriginalData.Free;
|
||||
fViewControlWrapper.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
@ -206,9 +531,11 @@ begin
|
||||
if Index < 0 then Exit;
|
||||
ena:=True;
|
||||
ImgIndex:=-1;
|
||||
if Assigned(fImages4Listbox) and Assigned(OnGetImageIndex) then
|
||||
if Assigned(fImages4Listbox) and Assigned(OnGetImageIndex) then begin
|
||||
ena:=True;
|
||||
ImgIndex:=OnGetImageIndex(fFilteredListbox.Items[Index],
|
||||
fFilteredListbox.Items.Objects[Index], ena);
|
||||
end;
|
||||
fFilteredListbox.Canvas.FillRect(ARect);
|
||||
if ImgIndex<>-1 then
|
||||
begin
|
||||
@ -294,6 +621,9 @@ begin
|
||||
if Assigned(fFilteredListbox) then
|
||||
raise Exception.Create('Sorry, both Treeview and ListBox should not be assigned.');
|
||||
fFilteredTreeview:=AValue;
|
||||
if Assigned(fViewControlWrapper) then
|
||||
fViewControlWrapper.Free;
|
||||
fViewControlWrapper:=TViewControlTreeview.Create(Self, fFilteredTreeview);
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.SetFilteredListbox(const AValue: TListBox);
|
||||
@ -301,15 +631,15 @@ begin
|
||||
if Assigned(fFilteredTreeview) then
|
||||
raise Exception.Create('Sorry, both Treeview and ListBox should not be assigned.');
|
||||
fFilteredListbox:=AValue;
|
||||
if fFilteredListbox.Style=lbStandard then begin
|
||||
// ToDo: support normal drawing (lbStandard).
|
||||
end
|
||||
else begin
|
||||
if fFilteredListbox.Style<>lbStandard then begin
|
||||
if Assigned(fFilteredListbox.OnDrawItem) then
|
||||
raise Exception.Create('Listbox.OnDrawItem should not be defined.'+
|
||||
' ListFilterEdit assigns its own handler.');
|
||||
fFilteredListbox.OnDrawItem:=@ListBoxDrawItem;
|
||||
end;
|
||||
if Assigned(fViewControlWrapper) then
|
||||
fViewControlWrapper.Free;
|
||||
fViewControlWrapper:=TViewControlListbox.Create(Self, fFilteredListbox);
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.SetShowDirHierarchy(const AValue: Boolean);
|
||||
@ -325,262 +655,21 @@ begin
|
||||
fFilenameMap[ShortFilename]:=FullFilename;
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.StoreTreeSelection;
|
||||
var
|
||||
ANode: TTreeNode;
|
||||
begin
|
||||
ANode:=fFilteredTreeview.Selected;
|
||||
while ANode<>nil do begin
|
||||
fSelectionList.Insert(0,ANode.Text);
|
||||
ANode:=ANode.Parent;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.StoreListSelection;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to fFilteredListbox.Count-1 do begin
|
||||
if fFilteredListbox.Selected[i] then
|
||||
fSelectionList.Add(fFilteredListbox.Items[i]);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.RestoreTreeSelection;
|
||||
var
|
||||
ANode: TTreeNode;
|
||||
CurText: string;
|
||||
begin
|
||||
ANode:=nil;
|
||||
while fSelectionList.Count>0 do begin
|
||||
CurText:=fSelectionList[0];
|
||||
if ANode=nil then
|
||||
ANode:=fFilteredTreeview.Items.GetFirstNode
|
||||
else
|
||||
ANode:=ANode.GetFirstChild;
|
||||
while (ANode<>nil) and (ANode.Text<>CurText) do
|
||||
ANode:=ANode.GetNextSibling;
|
||||
if ANode=nil then break;
|
||||
fSelectionList.Delete(0);
|
||||
end;
|
||||
if ANode<>nil then
|
||||
fFilteredTreeview.Selected:=ANode;
|
||||
fSelectionList.Clear;
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.RestoreListSelection;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to fFilteredListbox.Count-1 do begin
|
||||
if fSelectionList.IndexOf(fFilteredListbox.Items[i])>0 then
|
||||
fFilteredListbox.Selected[i]:=True;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.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 TListFilterEdit.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 TListFilterEdit.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;
|
||||
|
||||
function TListFilterEdit.CompareFNs(AFilename1,AFilename2: string): integer;
|
||||
begin
|
||||
if fSortData then
|
||||
Result:=CompareFilenames(AFilename1, AFilename2)
|
||||
else if fShowDirHierarchy then
|
||||
Result:=CompareFilenames(ExtractFilePath(AFilename1), ExtractFilePath(AFilename2))
|
||||
else
|
||||
Result:=0;
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.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 (Filter='') or (Pos(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 TListFilterEdit.ApplyFilterToTreeview;
|
||||
var
|
||||
TVNode: TTreeNode;
|
||||
ImgIndex, i: Integer;
|
||||
FileN, s: string;
|
||||
ena: Boolean;
|
||||
begin
|
||||
ImgIndex:=-1;
|
||||
if fSelectedPart=Nil then
|
||||
StoreTreeSelection;
|
||||
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;
|
||||
for i:=0 to fSortedData.Count-1 do begin
|
||||
FileN:=fSortedData[i];
|
||||
if fShowDirHierarchy then begin
|
||||
TVClearUnneededAndCreateHierachy(FileN);
|
||||
TVNode:=TTreeNode(fTVNodeStack[fTVNodeStack.Count-1]);
|
||||
end
|
||||
else if Assigned(fRootNode) then
|
||||
TVNode:=fFilteredTreeview.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;
|
||||
if Assigned(OnGetImageIndex) then
|
||||
ImgIndex:=OnGetImageIndex(FileN, fSortedData.Objects[i], ena);
|
||||
TVNode.ImageIndex:=ImgIndex;
|
||||
TVNode.SelectedIndex:=ImgIndex;
|
||||
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;
|
||||
if fSelectedPart=Nil then
|
||||
RestoreTreeSelection;
|
||||
fFilteredTreeview.EndUpdate;
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.ApplyFilterToListBox;
|
||||
var
|
||||
i: Integer;
|
||||
FileN: string;
|
||||
begin
|
||||
if fSelectedPart=Nil then
|
||||
StoreListSelection;
|
||||
fFilteredListbox.Clear;
|
||||
fFilteredListbox.Items.BeginUpdate;
|
||||
for i:=0 to fSortedData.Count-1 do begin
|
||||
FileN:=fSortedData[i];
|
||||
fFilteredListbox.Items.AddObject(FileN, fSortedData.Objects[i]);
|
||||
if Assigned(fSelectedPart) then
|
||||
fFilteredListbox.Selected[i]:=fSelectedPart=fSortedData.Objects[i];
|
||||
end;
|
||||
if fSelectedPart=Nil then
|
||||
RestoreListSelection;
|
||||
fFilteredListbox.Items.EndUpdate;
|
||||
end;
|
||||
|
||||
procedure TListFilterEdit.ApplyFilter(Immediately: Boolean);
|
||||
begin
|
||||
if Immediately then begin
|
||||
fNeedUpdate:=false;
|
||||
SortAndFilter;
|
||||
if Assigned(fFilteredTreeview) then
|
||||
ApplyFilterToTreeview
|
||||
else if Assigned(fFilteredListbox) then
|
||||
ApplyFilterToListBox
|
||||
else
|
||||
if not (Assigned(fFilteredTreeview) or Assigned(fFilteredListbox)) then
|
||||
raise Exception.Create(
|
||||
'Set either FilteredTreeview or FilteredListbox before using the filter.');
|
||||
fNeedUpdate:=false;
|
||||
fViewControlWrapper.SortAndFilter;
|
||||
if (fSelectedPart=Nil) and not fIsFirstUpdate then
|
||||
fViewControlWrapper.StoreSelection; // At first round the selection is from caller
|
||||
if fIsFirstUpdate then
|
||||
fIsFirstUpdate:=False;
|
||||
fViewControlWrapper.ApplyFilter;
|
||||
fSelectedPart:=Nil;
|
||||
fViewControlWrapper.RestoreSelection;
|
||||
end
|
||||
else begin
|
||||
if csDestroying in ComponentState then exit;
|
||||
|
Loading…
Reference in New Issue
Block a user