Improve ListFilterEdit, make it more object oriented

git-svn-id: trunk@31539 -
This commit is contained in:
juha 2011-07-03 13:39:00 +00:00
parent 7bf73f4406
commit ebb595fe19

View File

@ -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;