Skip to content

Commit 2e290bc

Browse files
joachimmarderSharlikran
authored andcommitted
Fixed issue JAM-Software#820: CheckBox state propagation slow for large number of nodes
1 parent 1a4e8d3 commit 2e290bc

File tree

1 file changed

+121
-113
lines changed

1 file changed

+121
-113
lines changed

Source/VirtualTrees.pas

+121-113
Original file line numberDiff line numberDiff line change
@@ -12413,134 +12413,142 @@ function TBaseVirtualTree.ChangeCheckState(Node: PVirtualNode; Value: TCheckStat
1241312413
end;//if
1241412414

1241512415
// Indicate that we are going to propagate check states up and down the hierarchy.
12416-
if FCheckPropagationCount = 0 then // WL, 05.02.2004: Do not enter tsCheckPropagation more than once
12416+
if FCheckPropagationCount = 0 then begin
12417+
// Do not enter tsCheckPropagation more than once
1241712418
DoStateChange([tsCheckPropagation]);
12418-
Inc(FCheckPropagationCount); // WL, 05.02.2004
12419-
// Do actions which are associated with the given check state.
12420-
case CheckType of
12421-
// Check state change with additional consequences for check states of the children.
12422-
ctTriStateCheckBox:
12423-
begin
12424-
// Propagate state down to the children.
12425-
if toAutoTristateTracking in FOptions.FAutoOptions then
12426-
case Value of
12427-
csUncheckedNormal:
12428-
if Node.ChildCount > 0 then
12429-
begin
12430-
Run := FirstChild;
12431-
CheckedCount := 0;
12432-
MixedCheckCount := 0;
12433-
UncheckedCount := 0;
12434-
while Assigned(Run) do
12419+
BeginUpdate();
12420+
end;
12421+
Inc(FCheckPropagationCount);
12422+
try
12423+
// Do actions which are associated with the given check state.
12424+
case CheckType of
12425+
// Check state change with additional consequences for check states of the children.
12426+
ctTriStateCheckBox:
12427+
begin
12428+
// Propagate state down to the children.
12429+
if toAutoTristateTracking in FOptions.FAutoOptions then
12430+
case Value of
12431+
csUncheckedNormal:
12432+
if Node.ChildCount > 0 then
1243512433
begin
12436-
if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
12434+
Run := FirstChild;
12435+
CheckedCount := 0;
12436+
MixedCheckCount := 0;
12437+
UncheckedCount := 0;
12438+
while Assigned(Run) do
1243712439
begin
12438-
if not Self.GetCheckState(Run).IsDisabled() then
12439-
SetCheckState(Run, csUncheckedNormal);
12440-
// Check if the new child state was set successfully, otherwise we have to adjust the
12441-
// node's new check state accordingly.
12442-
case Self.GetCheckState(Run) of
12443-
csCheckedNormal, csCheckedDisabled:
12444-
Inc(CheckedCount);
12445-
csMixedNormal:
12446-
Inc(MixedCheckCount);
12447-
csUncheckedNormal, csUncheckedDisabled:
12448-
Inc(UncheckedCount);
12440+
if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
12441+
begin
12442+
if not Self.GetCheckState(Run).IsDisabled() then
12443+
SetCheckState(Run, csUncheckedNormal);
12444+
// Check if the new child state was set successfully, otherwise we have to adjust the
12445+
// node's new check state accordingly.
12446+
case Self.GetCheckState(Run) of
12447+
csCheckedNormal, csCheckedDisabled:
12448+
Inc(CheckedCount);
12449+
csMixedNormal:
12450+
Inc(MixedCheckCount);
12451+
csUncheckedNormal, csUncheckedDisabled:
12452+
Inc(UncheckedCount);
12453+
end;
1244912454
end;
12455+
Run := Run.NextSibling;
1245012456
end;
12451-
Run := Run.NextSibling;
12452-
end;
1245312457

12454-
// If there is still a mixed state child node checkbox then this node must be mixed checked too.
12455-
if MixedCheckCount > 0 then
12456-
Value := csMixedNormal
12457-
else
12458-
// If nodes are normally checked child nodes then the unchecked count determines what
12459-
// to set for the node itself.
12460-
if CheckedCount > 0 then
12461-
if UncheckedCount > 0 then
12462-
Value := csMixedNormal
12463-
else
12464-
Value := csCheckedNormal;
12465-
end;
12466-
csCheckedNormal:
12467-
if Node.ChildCount > 0 then
12468-
begin
12469-
Run := FirstChild;
12470-
CheckedCount := 0;
12471-
MixedCheckCount := 0;
12472-
UncheckedCount := 0;
12473-
while Assigned(Run) do
12458+
// If there is still a mixed state child node checkbox then this node must be mixed checked too.
12459+
if MixedCheckCount > 0 then
12460+
Value := csMixedNormal
12461+
else
12462+
// If nodes are normally checked child nodes then the unchecked count determines what
12463+
// to set for the node itself.
12464+
if CheckedCount > 0 then
12465+
if UncheckedCount > 0 then
12466+
Value := csMixedNormal
12467+
else
12468+
Value := csCheckedNormal;
12469+
end;
12470+
csCheckedNormal:
12471+
if Node.ChildCount > 0 then
1247412472
begin
12475-
if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
12473+
Run := FirstChild;
12474+
CheckedCount := 0;
12475+
MixedCheckCount := 0;
12476+
UncheckedCount := 0;
12477+
while Assigned(Run) do
1247612478
begin
12477-
if not Self.GetCheckState(Run).IsDisabled() then
12478-
SetCheckState(Run, csCheckedNormal);
12479-
// Check if the new child state was set successfully, otherwise we have to adjust the
12480-
// node's new check state accordingly.
12481-
case Self.GetCheckState(Run) of
12482-
csCheckedNormal:
12483-
Inc(CheckedCount);
12484-
csMixedNormal:
12485-
Inc(MixedCheckCount);
12486-
csUncheckedNormal:
12487-
Inc(UncheckedCount);
12479+
if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
12480+
begin
12481+
if not Self.GetCheckState(Run).IsDisabled() then
12482+
SetCheckState(Run, csCheckedNormal);
12483+
// Check if the new child state was set successfully, otherwise we have to adjust the
12484+
// node's new check state accordingly.
12485+
case Self.GetCheckState(Run) of
12486+
csCheckedNormal:
12487+
Inc(CheckedCount);
12488+
csMixedNormal:
12489+
Inc(MixedCheckCount);
12490+
csUncheckedNormal:
12491+
Inc(UncheckedCount);
12492+
end;
1248812493
end;
12494+
Run := Run.NextSibling;
1248912495
end;
12490-
Run := Run.NextSibling;
12491-
end;
1249212496

12493-
// If there is still a mixed state child node checkbox then this node must be mixed checked too.
12494-
if MixedCheckCount > 0 then
12495-
Value := csMixedNormal
12496-
else
12497-
// If nodes are normally checked child nodes then the unchecked count determines what
12498-
// to set for the node itself.
12499-
if CheckedCount > 0 then
12500-
if UncheckedCount > 0 then
12501-
Value := csMixedNormal
12502-
else
12503-
Value := csCheckedNormal;
12504-
end;
12505-
end;
12506-
end;
12507-
// radio button check state change
12508-
ctRadioButton:
12509-
if Value = csCheckedNormal then
12510-
begin
12511-
Value := csCheckedNormal;
12512-
// Make sure only this node is checked.
12513-
Run := Parent.FirstChild;
12514-
while Assigned(Run) do
12497+
// If there is still a mixed state child node checkbox then this node must be mixed checked too.
12498+
if MixedCheckCount > 0 then
12499+
Value := csMixedNormal
12500+
else
12501+
// If nodes are normally checked child nodes then the unchecked count determines what
12502+
// to set for the node itself.
12503+
if CheckedCount > 0 then
12504+
if UncheckedCount > 0 then
12505+
Value := csMixedNormal
12506+
else
12507+
Value := csCheckedNormal;
12508+
end;
12509+
end;
12510+
end;
12511+
// radio button check state change
12512+
ctRadioButton:
12513+
if Value = csCheckedNormal then
1251512514
begin
12516-
if Run.CheckType = ctRadioButton then
12517-
Run.CheckState := csUncheckedNormal;
12518-
Run := Run.NextSibling;
12515+
Value := csCheckedNormal;
12516+
// Make sure only this node is checked.
12517+
Run := Parent.FirstChild;
12518+
while Assigned(Run) do
12519+
begin
12520+
if Run.CheckType = ctRadioButton then
12521+
Run.CheckState := csUncheckedNormal;
12522+
Run := Run.NextSibling;
12523+
end;
12524+
Invalidate;
1251912525
end;
12520-
Invalidate;
12521-
end;
12522-
end;
12523-
12524-
if Result then
12525-
CheckState := Value // Set new check state
12526-
else
12527-
CheckState := Self.GetCheckState(Node).GetUnpressed(); // Reset dynamic check state.
12528-
12529-
// Propagate state up to the parent.
12530-
if not (vsInitialized in Parent.States) then
12531-
InitNode(Parent);
12532-
if (toAutoTristateTracking in FOptions.FAutoOptions) and ([vsChecking, vsDisabled] * Parent.States = []) and
12533-
(CheckType in [ctCheckBox, ctTriStateCheckBox]) and (Parent <> FRoot) and
12534-
(Parent.CheckType = ctTriStateCheckBox) then
12535-
Result := CheckParentCheckState(Node, Value)
12536-
else
12537-
Result := True;
12526+
end;
1253812527

12539-
InvalidateNode(Node);
12528+
if Result then
12529+
CheckState := Value // Set new check state
12530+
else
12531+
CheckState := Self.GetCheckState(Node).GetUnpressed(); // Reset dynamic check state.
12532+
12533+
// Propagate state up to the parent.
12534+
if not (vsInitialized in Parent.States) then
12535+
InitNode(Parent);
12536+
if (toAutoTristateTracking in FOptions.FAutoOptions) and ([vsChecking, vsDisabled] * Parent.States = []) and
12537+
(CheckType in [ctCheckBox, ctTriStateCheckBox]) and (Parent <> FRoot) and
12538+
(Parent.CheckType = ctTriStateCheckBox) then
12539+
Result := CheckParentCheckState(Node, Value)
12540+
else
12541+
Result := True;
1254012542

12541-
Dec(FCheckPropagationCount); // WL, 05.02.2004
12542-
if FCheckPropagationCount = 0 then // WL, 05.02.2004: Allow state change event after all check operations finished
12543-
DoStateChange([], [tsCheckPropagation]);
12543+
InvalidateNode(Node);
12544+
finally
12545+
Dec(FCheckPropagationCount); // WL, 05.02.2004
12546+
if FCheckPropagationCount = 0 then begin
12547+
// Allow state change event after all check operations finished
12548+
DoStateChange([], [tsCheckPropagation]);
12549+
EndUpdate();
12550+
end;
12551+
end;
1254412552
finally
1254512553
Exclude(States, vsChecking);
1254612554
end;

0 commit comments

Comments
 (0)