77
77
// NodeArray must be sorted via Top
78
78
// returns index of Node with Node.Top <= y < Node[+1].Top
80
l, m, r, VisibleCount: integer;
81
VisibleNodesAlloc: Boolean;
82
VisibleNodes: TTreeNodeArray;
82
84
if (Count = 0) or (NodeArray = nil) then
89
//DebugLn(':0 [IndexOfNodeAtTop] m=',m,' y=',y,' ',NodeArray[m].Text,' NodeArray[m].Top=',NodeArray[m].Top,' NodeArray[m].BottomExpanded=',NodeArray[m].BottomExpanded);
90
if NodeArray[m].Top > y then
93
if NodeArray[m].BottomExpanded <= y then
86
// Count the visible nodes
88
VisibleNodesAlloc := False;
89
for l := 0 to Count-1 do
90
if NodeArray[l].Visible then
93
// Make a temporary array of visible nodes if there are hidden nodes
94
if VisibleCount < Count then begin
95
GetMem(VisibleNodes,SizeOf(Pointer)*VisibleCount);
97
for l := 0 to Count-1 do
98
if NodeArray[l].Visible then begin
99
VisibleNodes[m] := NodeArray[l];
102
Count := VisibleCount;
103
VisibleNodesAlloc := True;
106
VisibleNodes := NodeArray;
107
// Binary search for the Y coordinate
113
//DebugLn(':0 [IndexOfNodeAtTop] m=',m,' y=',y,' ',NodeArray[m].Text,' NodeArray[m].Top=',NodeArray[m].Top,' NodeArray[m].BottomExpanded=',NodeArray[m].BottomExpanded);
114
if VisibleNodes[m].Top > y then
116
else if VisibleNodes[m].BottomExpanded <= y then
119
Exit(VisibleNodes[m].Index);
123
if VisibleNodesAlloc then
124
Freemem(VisibleNodes);
101
128
// procedure for sorting a TTreeNodeArray
233
260
while ChildNode<>nil do begin
234
261
ChildNodeText:=ChildNode.Text;
235
262
ANode:=Children.FindKey(PChar(ChildNodeText),@CompareTextWithExpandedNode);
236
ChildNode.Expanded:=ANode<>nil;
238
TTreeNodeExpandedState(ANode.Data).Apply(ChildNode.GetFirstChild);
264
ChildNode.Expanded:=true
265
else if CollapseToo then
266
ChildNode.Expanded:=false;
268
TTreeNodeExpandedState(ANode.Data).Apply(ChildNode.GetFirstChild,CollapseToo);
239
269
ChildNode:=ChildNode.GetNextSibling;
243
procedure TTreeNodeExpandedState.Apply(TreeView: TCustomTreeView);
273
procedure TTreeNodeExpandedState.Apply(TreeView: TCustomTreeView; CollapseToo: boolean);
245
Apply(TreeView.Items.GetFirstNode);
275
Apply(TreeView.Items.GetFirstNode,CollapseToo);
267
298
FOwner := AnOwner;
268
299
FSubTreeCount := 1;
270
302
if Owner<>nil then inc(Owner.FCount);
273
305
destructor TTreeNode.Destroy;
307
lOwnerAccessibleObject, lAccessibleObject: TLazAccessibleObject;
275
309
{$IFDEF TREEVIEW_DEBUG}
276
310
DebugLn('[TTreeNode.Destroy] Self=',DbgS(Self),' Self.Text=',Text);
280
314
// we must trigger TCustomTreeView.OnDeletion event before
281
315
// unbinding.See issue #17832.
282
if (Owner <> nil) and (Owner.Owner <> nil) then
316
if Assigned(Owner) and Assigned(Owner.Owner) then
283
317
Owner.Owner.Delete(Self);
319
// Remove the accessibility object too
320
if Assigned(Owner) and Assigned(Owner.Owner) then
322
lOwnerAccessibleObject := Owner.Owner.GetAccessibleObject();
323
if lOwnerAccessibleObject<>nil then
325
lAccessibleObject := lOwnerAccessibleObject.GetChildAccessibleObjectWithDataObject(Self);
326
if lAccessibleObject <> nil then
327
lOwnerAccessibleObject.RemoveChildAccessibleObject(lAccessibleObject);
285
331
// delete children
286
332
HasChildren := false;
287
333
// unbind all references
336
if Assigned(Owner) then begin
291
337
dec(Owner.FCount);
338
if FStates * [nsSelected, nsMultiSelected] <> [] then
339
Owner.FSelection.Remove(Self);
295
if FItems<>nil then begin
344
if Assigned(FItems) then
299
349
inherited Destroy;
514
procedure TTreeNode.SetVisible(const AValue: Boolean);
516
if FVisible = AValue then exit;
519
if TreeView<>nil then
520
TreeView.FStates:=TreeView.FStates+[tvsScrollbarChanged,tvsTopsNeedsUpdate,
521
tvsTopItemNeedsUpdate,tvsBottomItemNeedsUpdate,
522
tvsMaxLvlNeedsUpdate,tvsMaxRightNeedsUpdate];
451
526
procedure TTreeNode.SetOverlayIndex(AValue: Integer);
453
528
if FOverlayIndex = AValue then exit;
465
function TTreeNode.AreParentsExpanded: Boolean;
466
var ANode: TTreeNode;
540
function TTreeNode.AreParentsExpandedAndVisible: Boolean;
470
546
while ANode<>nil do begin
471
if not ANode.Expanded then exit;
547
if not (ANode.Expanded and ANode.Visible) then exit;
472
548
ANode:=ANode.Parent;
690
765
Exclude(FStates,nsSelected);
691
766
if (TV<>nil) and (TV.Selected=Self) then
768
{$IFDEF TREEVIEW_DEBUG}
769
DebugLn('TTreeNode.SetSelected: Removing selection from Node (but it does not work): ', Text);
771
// TV.EndEditing(true); // Done in TV.SetSelection
694
772
TV.Selected:=nil;
695
if TV.Selected=Self then
696
Include(FStates,nsSelected);
773
Assert(TV.Selected<>Self, 'Should not happen');
774
//if TV.Selected=Self then
775
// Include(FStates,nsSelected);
757
836
function TTreeNode.BottomExpanded: integer;
759
if GetNextSibling <> nil then
760
Result := GetNextSibling.Top
762
if Expanded and (GetLastChild <> nil) then
763
Result := GetLastChild.BottomExpanded
840
Node := GetNextVisibleSibling;
844
Node := GetLastVisibleChild;
845
if Expanded and (Node <> nil) then
846
Result := Node.BottomExpanded
768
852
function TTreeNode.GetFocused: Boolean;
773
857
procedure TTreeNode.SetHasChildren(AValue: Boolean);
776
859
if AValue=HasChildren then exit;
777
860
//DebugLn('[TTreeNode.SetHasChildren] Self=',DbgS(Self),' Self.Text=',Text,' AValue=',AValue);
807
881
function TTreeNode.GetNextVisible: TTreeNode;
809
if Expanded and (GetFirstChild<>nil) then
810
Result:=GetFirstChild
883
if FVisible and Expanded and (GetFirstVisibleChild<>nil) then
884
Result:=GetFirstVisibleChild
813
while (Result<>nil) and (Result.GetNextSibling=nil) do
887
while (Result<>nil) and (Result.GetNextVisibleSibling=nil) do
814
888
Result:=Result.Parent;
815
if Result<>nil then Result:=Result.GetNextSibling;
890
Result:=Result.GetNextVisibleSibling;
817
if (Result<>nil) and (not Result.IsVisible) then
892
if (Result<>nil) and ( (not Result.FVisible) or (not AreParentsExpandedAndVisible) ) then
896
function TTreeNode.GetNextVisibleSibling: TTreeNode;
900
Result := Result.GetNextSibling;
901
until ((Result=nil) or (Result.FVisible));
902
if (Result<>nil) and (not Result.FVisible) then // Result := nil ... will be removed
903
Assert(False,'TTreeNode.GetNextVisibleSibling: (Result<>nil) and (not Result.FVisible)');
821
906
function TTreeNode.GetPrevVisible: TTreeNode;
823
908
ANode: TTreeNode;
825
Result:=GetPrevSibling;
910
Result:=GetPrevVisibleSibling;
826
911
if Result <> nil then begin
827
while Result.Expanded do begin
828
ANode:=Result.GetLastChild;
912
while Result.Visible and Result.Expanded do begin
913
ANode:=Result.GetLastVisibleChild;
829
914
if ANode=nil then break;
833
919
Result := Parent;
834
if (Result<>nil) and (TreeView<>nil) and (not TreeView.IsNodeVisible(Result))
920
if (Result<>nil) and ( (not Result.FVisible) or (not AreParentsExpandedAndVisible) ) then
924
function TTreeNode.GetPrevVisibleSibling: TTreeNode;
928
Result := Result.GetPrevSibling;
929
until ((Result=nil) or (Result.FVisible));
930
if (Result<>nil) and (not Result.FVisible) then // Result := nil ... will be removed
931
Assert(False,'TTreeNode.GetPrevVisibleSibling: (Result<>nil) and (not Result.FVisible)');
839
934
function TTreeNode.GetPrevExpanded: TTreeNode;
841
936
ANode: TTreeNode;
843
Result:=GetPrevSibling;
938
Result:=GetPrevVisibleSibling;
844
939
if Result <> nil then begin
845
while Result.Expanded do begin
846
ANode:=Result.GetLastChild;
940
while Result.Visible and Result.Expanded do begin
941
ANode:=Result.GetLastVisibleChild;
847
942
if ANode=nil then break;
854
950
function TTreeNode.GetNextChild(AValue: TTreeNode): TTreeNode;
862
958
function TTreeNode.GetNextExpanded: TTreeNode;
864
if Expanded and (GetFirstChild<>nil) then
865
Result:=GetFirstChild
962
ANode := GetFirstVisibleChild;
963
if Expanded and (ANode<>nil) then
868
while (Result<>nil) and (Result.GetNextSibling=nil) do
967
while (Result<>nil) and (Result.GetNextVisibleSibling=nil) do
869
968
Result:=Result.Parent;
870
if Result<>nil then Result:=Result.GetNextSibling;
970
Result:=Result.GetNextVisibleSibling;
1026
function TTreeNode.GetLastVisibleChild: TTreeNode;
1028
Result := GetLastChild;
1029
if Assigned(Result) and not Result.Visible then begin
1030
Result := Result.GetPrevVisible;
1031
// ToDo: implement this better. Now it works only when Self is visible.
1032
if Result = Self then begin // No visible nodes found.
1033
Assert(Visible, 'TTreeNode.GetLastVisibleChild: Node is not Visible');
919
1039
function TTreeNode.GetLastSubChild: TTreeNode;
922
1043
Result:=GetLastChild;
923
1044
if Result<>nil then begin
930
1051
function TTreeNode.GetNext: TTreeNode;
932
1053
Result:=GetFirstChild;
933
if Result=nil then begin
934
// no children, search next
936
while (Result<>nil) and (Result.FNextBrother=nil) do
937
Result:=Result.Parent;
938
if Result<>nil then Result:=Result.FNextBrother;
1055
Result:=GetNextSkipChildren;
1058
function TTreeNode.GetNextSkipChildren: TTreeNode;
1061
while (Result<>nil) and (Result.FNextBrother=nil) do
1062
Result:=Result.Parent;
1064
Result:=Result.FNextBrother;
942
1067
function TTreeNode.GetPrev: TTreeNode;
1057
1182
function TTreeNode.IndexOf(AValue: TTreeNode): Integer;
1059
if (AValue=nil) or (AValue.FParent<>Self) then begin
1184
if (AValue = nil) or (AValue.FParent <> Self) then
1063
Result:=AValue.GetIndex;
1189
Result := AValue.GetIndex;
1066
1192
function TTreeNode.IndexOfText(const NodeText: string): Integer;
1069
while Result>=0 do begin
1070
if FItems[Result].Text=NodeText then exit;
1194
Result := Count - 1;
1195
while Result >= 0 do
1197
if FItems[Result].Text = NodeText then exit;
1201
1329
FPrevMultiSelected:=nil;
1204
procedure TTreeNode.InternalMove(ANode: TTreeNode;
1332
function AddModeStr(AddMode: TAddMode): string;
1334
WriteStr(Result, AddMode);
1337
procedure TTreeNode.InternalMove(ANode: TTreeNode; AddMode: TAddMode);
1207
1339
TAddMode = (taAddFirst, taAdd, taInsert);
1218
1350
{$IFDEF TREEVIEW_DEBUG}
1219
1351
DbgOut('[TTreeNode.InternalMove] Self=',DbgS(Self),' Self.Text=',Text
1220
,' ANode=',ANode<>nil,' AddMode=',AddModeNames[AddMode]);
1221
if ANode<>nil then DbgOut(' ANode.Text=',ANode.Text);
1352
,' ANode=',ANode<>nil,' AddMode=', AddModeStr(AddMode));
1354
DbgOut(' ANode.Text=',ANode.Text);
1224
1357
if TreeView<>nil then TreeView.BeginUpdate;
1332
1465
{$IFDEF TREEVIEW_DEBUG}
1333
1466
DbgOut('[TTreeNode.InternalMove] END Self=',DbgS(Self),' Self.Text=',Text
1334
,' ANode=',DbgS(ANode<>nil),' AddMode=',AddModeNames[AddMode]);
1335
if ANode<>nil then DbgOut(' ANode.Text=',ANode.Text);
1467
,' ANode=',DbgS(ANode<>nil),' AddMode=',AddModeStr(AddMode));
1469
DbgOut(' ANode.Text=',ANode.Text);
1355
1489
OldOnChanging: TTVChangingEvent;
1356
1490
OldOnChange: TTVChangedEvent;
1358
if (Destination=nil)
1359
and (Mode in [naAddChild,naAddChildFirst,naInsert,naInsertBehind]) then
1492
if (Destination=nil) and not(Mode in [naAdd,naAddFirst]) then
1360
1493
TreeNodeError('TTreeNode.MoveTo Destination=nil');
1361
if Mode=naInsertBehind then begin
1362
// convert naInsertBehind
1363
if Destination.GetNextSibling=nil then begin
1494
if Mode=naInsertBehind then begin // convert naInsertBehind
1495
if Destination.GetNextSibling=nil then
1366
1498
Mode:=naInsert;
1367
1499
Destination:=Destination.GetNextSibling;
1376
1508
if (Destination <> nil) and (Mode in [naAdd, naAddFirst]) then
1377
1509
Destination := Destination.Parent;
1380
naAddChild: AddMode := taAdd;
1382
1512
naAddChildFirst: AddMode := taAddFirst;
1383
naInsert: AddMode := taInsert;
1513
naInsert: AddMode := taInsert;
1385
1515
AddMode:=taAdd;
1398
1528
FirstNode, LastNode, ANode: TTreeNode;
1400
if (TreeView<>nil) and (not (tvoAllowMultiselect in TreeView.Options)) then
1402
if (TreeView<>nil) then TreeView.LockSelectionChangeEvent;
1530
if Assigned(TreeView) and not (tvoAllowMultiselect in TreeView.Options) then
1532
if Assigned(TreeView) then TreeView.LockSelectionChangeEvent;
1404
FirstNode:=GetPrevSibling;
1405
while (FirstNode<>nil) and (not FirstNode.MultiSelected) do
1406
FirstNode:=FirstNode.GetPrevSibling;
1407
if FirstNode=nil then FirstNode:=Self;
1408
LastNode:=GetNextSibling;
1409
while (LastNode<>nil) and (not LastNode.MultiSelected) do
1410
LastNode:=LastNode.GetNextSibling;
1411
if LastNode=nil then LastNode:=Self;
1413
while ANode<>nil do begin
1414
ANode.MultiSelected:=true;
1415
if ANode=LastNode then break;
1416
ANode:=ANode.GetNextSibling;
1534
// We need to select the nodes between the selected node and the current node
1535
FirstNode := GetPrevSibling;
1536
while Assigned(FirstNode) and not FirstNode.Selected do
1537
FirstNode := FirstNode.GetPrevSibling;
1538
if not Assigned(FirstNode) then FirstNode := Self;
1539
LastNode := GetNextSibling;
1540
while Assigned(LastNode) and not LastNode.Selected do
1541
LastNode := LastNode.GetNextSibling;
1542
if not Assigned(LastNode) then LastNode := Self;
1544
while Assigned(ANode) do
1546
ANode.MultiSelected := True;
1547
if ANode = LastNode then Break;
1548
ANode := ANode.GetNextSibling;
1419
if (TreeView<>nil) then TreeView.UnlockSelectionChangeEvent;
1551
if Assigned(TreeView) then TreeView.UnlockSelectionChangeEvent;
1423
1555
procedure TTreeNode.MakeVisible;
1425
if TreeView<>nil then
1557
if Assigned(TreeView) then
1426
1558
TreeView.EnsureNodeIsVisible(Self)
1449
1582
function TTreeNode.IsNodeVisible: Boolean;
1451
if TreeView<>nil then
1452
Result:=TreeView.IsNodeVisible(Self)
1584
if Assigned(TreeView) then
1585
Result := TreeView.IsNodeVisible(Self)
1454
Result:=AreParentsExpanded;
1587
Result := AreParentsExpandedAndVisible;
1457
1590
function TTreeNode.IsNodeHeightFullVisible: Boolean;
1459
if TreeView<>nil then
1460
Result:=TreeView.IsNodeHeightFullVisible(Self)
1592
if Assigned(TreeView) then
1593
Result := TreeView.IsNodeHeightFullVisible(Self)
1462
Result:=AreParentsExpanded;
1595
Result := AreParentsExpandedAndVisible;
1465
1598
procedure TTreeNode.Update;
1467
1600
TV: TCustomTreeView;
1470
if (TV<>nil) and (Owner.FUpdateCount=0) and (not (csLoading in TV.ComponentState)) then
1603
if Assigned(TV) and (Owner.FUpdateCount = 0) and (not (csLoading in TV.ComponentState)) then
1660
1794
SetLength(FText,Info.TextLen);
1662
1796
if FText<>'' then
1663
1798
Stream.Read(FText[1],length(FText));
1799
// Update accessibility information
1800
if TreeView<>nil then
1802
lSelfAX := TreeView.GetAccessibleObject.GetChildAccessibleObjectWithDataObject(Self);
1803
if lSelfAX <> nil then
1804
lSelfAX.AccessibleValue := FText;
1664
1807
if Owner<>nil then begin
1665
1808
for I := 0 to ItemCount - 1 do begin
1666
1809
Node:=Owner.AddChild(Self, '');
1872
2014
procedure TTreeNodes.Clear;
1876
if GetLastNode<>nil then begin
1877
while GetLastNode<>nil do
1879
if (FUpdateCount=0) and (Owner<>nil) then
2020
Node := GetLastNode;
2021
if Assigned(Node) then
2023
while Assigned(Node) do
2026
Node := GetLastNode;
1882
2029
FSelection.Clear;
2030
if (FOwner <> nil) then
2031
FOwner.GetAccessibleObject().ClearChildAccessibleObjects();
1888
2037
ANode, OldNode: TTreeNode;
1890
if Owner<>nil then Owner.LockSelectionChangeEvent;
2039
if Assigned(Owner) then Owner.LockSelectionChangeEvent;
1892
ANode:=FFirstMultiSelected;
1893
while ANode<>nil do begin
1895
ANode:=ANode.GetNextMultiSelected;
1896
OldNode.MultiSelected:=false;
2041
ANode := FFirstMultiSelected;
2042
while Assigned(ANode) do
2045
ANode := ANode.GetNextMultiSelected;
2046
OldNode.MultiSelected := false;
1898
2048
if ClearSelected then
1899
Owner.Selected:=nil;
2049
Owner.Selected := nil;
1901
if Owner<>nil then Owner.UnlockSelectionChangeEvent;
2051
if Assigned(Owner) then Owner.UnlockSelectionChangeEvent;
1957
2107
Result := InternalAddObject(ParentNode, S, Data, taAddFirst);
2110
function TTreeNodes.AddNode(Node: TTreeNode; Relative: TTreeNode;
2111
const S: string; Ptr: Pointer; Method: TNodeAttachMode): TTreeNode;
2115
if (Relative=nil) and not (Method in [naAdd,naAddFirst]) then
2116
TreeNodeError('TTreeNode.AddNode Relative=nil');
2117
if Method=naInsertBehind then begin // convert naInsertBehind
2118
if Relative.GetNextSibling=nil then
2122
Relative:=Relative.GetNextSibling;
2125
if (Relative <> nil) and (Method in [naAdd, naAddFirst]) then
2126
Relative := Relative.Parent;
2127
// Convert TNodeAttachMode to TAddMode
2129
naAddFirst,naAddChildFirst: AddMode := taAddFirst;
2130
naInsert: AddMode := taInsert;
2134
fNewNodeToBeAdded := Node;
2135
Result := InternalAddObject(Relative, S, Ptr, AddMode);
1960
2138
procedure TTreeNodes.SelectionsChanged(ANode: TTreeNode; const AIsSelected: Boolean);
1962
2140
if ANode <> nil then
2018
2196
Result:=InternalAddObject(NextNode,S,Data,taInsert);
2021
function TTreeNodes.InsertBehind(PrevNode: TTreeNode; const S: string
2199
function TTreeNodes.InsertBehind(PrevNode: TTreeNode; const S: string): TTreeNode;
2024
2201
Result := InsertObjectBehind(PrevNode, S, nil);
2049
2226
taAddFirst: add Result as first child of Node
2050
2227
taInsert: add Result in front of Node
2052
//var Item: HTreeItem;
2232
lAccessibleObject: TLazAccessibleObject;
2055
2234
if Owner=nil then
2056
2235
TreeNodeError('TTreeNodes.InternalAddObject Owner=nil');
2057
2236
{$IFDEF TREEVIEW_DEBUG}
2058
2237
write('[TTreeNodes.InternalAddObject] Node=',Node<>nil,' S=',S,
2059
' AddMode=',AddModeNames[AddMode]);
2060
if Node<>nil then DbgOut(' Node.Text=',Node.Text);
2238
' AddMode=',AddModeStr(AddMode));
2240
DbgOut(' Node.Text=',Node.Text);
2063
Result := Owner.CreateNode;
2243
Result := fNewNodeToBeAdded; // Used by AddNode to pass an existing node.
2244
if Result = Nil then
2245
Result := Owner.CreateNode;
2246
fNewNodeToBeAdded := nil;
2066
2249
Result.Data := Data;
2071
2254
Result.Parent.Expanded:=true;
2072
2255
if (Owner<>nil) and (not (csReading in Owner.ComponentState)) then
2073
2256
Owner.Added(Result);
2074
if (FUpdateCount=0) and (Owner<>nil) then
2258
if ok and (Owner<>nil) and (Owner.AccessibilityOn) then
2260
lAccessibleObject := FOwner.GetAccessibleObject().AddChildAccessibleObject();
2261
lAccessibleObject.AccessibleDescription := 'Item';
2262
lAccessibleObject.AccessibleValue := S;
2263
lAccessibleObject.AccessibleRole := larTreeItem;
2264
lAccessibleObject.DataObject := Result;
2078
2267
// this construction creates nicer exception output
2084
2273
function TTreeNodes.GetFirstNode: TTreeNode;
2086
if FTopLvlItems<>nil then
2275
if Assigned(FTopLvlItems) then
2087
2276
Result := FTopLvlItems[0]
2090
2279
//Result := GetNode(TreeView_GetRoot(Handle));
2282
function TTreeNodes.GetFirstVisibleNode: TTreeNode;
2288
if Assigned(FTopLvlItems) then
2289
for i := 0 to FTopLvlCount-1 do begin
2290
Node := FTopLvlItems[i];
2291
if Node.Visible then begin
2093
2298
function TTreeNodes.GetLastNode: TTreeNode;
2095
if FTopLvlItems<>nil then
2096
Result := FTopLvlItems[FTopLvlCount-1]
2300
if Assigned(FTopLvlItems) then
2301
Result := FTopLvlItems[FTopLvlCount - 1]
2306
function TTreeNodes.GetLastVisibleNode: TTreeNode;
2312
if Assigned(FTopLvlItems) then
2313
for i := FTopLvlCount-1 downto 0 do begin
2314
Node := FTopLvlItems[i];
2315
if Node.Visible then begin
2101
2322
function TTreeNodes.GetLastSubNode: TTreeNode;
2102
2323
// absolute last node
2103
var Node: TTreeNode;
2105
Result:=GetLastNode;
2106
if Result<>nil then begin
2107
Node:=Result.GetLastSubChild;
2108
if Node<>nil then Result:=Node;
2327
Result := GetLastNode;
2328
if Assigned(Result) then
2330
Node := Result.GetLastSubChild;
2331
if Assigned(Node) then Result := Node;
2112
2335
function TTreeNodes.GetLastExpandedSubNode: TTreeNode;
2113
2336
// absolute last expanded node
2114
var Node: TTreeNode;
2116
Result:=GetLastNode;
2117
while (Result<>nil) and (Result.Expanded) do begin
2118
Node:=Result.GetLastChild;
2340
Result := GetLastVisibleNode;
2341
while Assigned(Result) and (Result.Expanded) do
2343
Node := Result.GetLastVisibleChild;
2344
if Assigned(Node) then
2126
2351
function TTreeNodes.FindTopLvlNode(const NodeText: string): TTreeNode;
2128
Result:=GetFirstNode;
2129
while (Result<>nil) and (Result.Text<>NodeText) do
2130
Result:=Result.GetNextSibling;
2353
Result := GetFirstNode;
2354
while Assigned(Result) and (Result.Text <> NodeText) do
2355
Result := Result.GetNextSibling;
2133
2358
function TTreeNodes.FindNodeWithText(const NodeText: string): TTreeNode;
2135
Result:=GetFirstNode;
2136
while (Result<>nil) and (Result.Text<>NodeText) do
2137
Result:=Result.GetNext;
2360
Result := GetFirstNode;
2361
while Assigned(Result) and (Result.Text <> NodeText) do
2362
Result := Result.GetNext;
2140
2365
function TTreeNodes.FindNodeWithData(const NodeData: Pointer): TTreeNode;
2142
Result:=GetFirstNode;
2143
while (Result<>nil) and (Result.Data<>NodeData) do
2144
Result:=Result.GetNext;
2367
Result := GetFirstNode;
2368
while Assigned(Result) and (Result.Data <> NodeData) do
2369
Result := Result.GetNext;
2147
2372
function TTreeNodes.GetNodeFromIndex(Index: Integer): TTreeNode;
2263
2488
Include(Owner.FStates,tvsUpdating)
2265
2490
Exclude(Owner.FStates,tvsUpdating);
2266
if not Updating then Owner.Refresh;
2491
if not Updating then
2269
2495
procedure TTreeNodes.EndUpdate;
2637
2865
Node := Owner.GetNodeFromIndex(Index);
2638
2866
Level := Node.Level;
2639
for I := 0 to Level - 1 do Result := Result + TabChar;
2867
for I := 0 to Level - 1 do
2868
Result := Result + TabChar;
2640
2869
Result := Result + Node.Text;
2679
2908
procedure TTreeStrings.SetUpdateState(Updating: Boolean);
2681
2910
//SendMessage(Owner.Handle, WM_SETREDRAW, Ord(not Updating), 0);
2682
if not Updating then Owner.Owner.Refresh;
2911
if not Updating then
2912
Owner.Owner.Invalidate;
2685
2915
function TTreeStrings.Add(const S: string): Integer;
2837
3062
FTreeLineColor := clWindowFrame;
2838
3063
FTreeLinePenStyle := psPattern;
2839
3064
FExpandSignColor := clWindowFrame;
3066
AccessibleDescription := rsTTreeViewAccessibilityDescription;
3067
AccessibleRole := larTreeView;
3068
FAccessibilityOn := WidgetSet.GetLCLCapability(lcAccessibilitySupport) = LCL_CAPABILITY_YES;
2842
3071
destructor TCustomTreeView.Destroy;
2897
3126
//DebugLn(['TCustomTreeView.BeginEditing tvsIsEditing=',tvsIsEditing in FStates,' Selected=',Selected<>nil]);
2898
3127
if (tvsIsEditing in FStates) or (ANode=nil) then exit;
2899
if not CanEdit(ANode) then exit;
3128
if (not CanEdit(ANode)) or (not ANode.FVisible) then exit;
2900
3129
// if we are asked to edit another node while one is already being edited then
2901
3130
// stop editing that node
2902
3131
if FEditingItem <> nil then
2952
3180
Result := False;
2953
3181
if FTreeNodes.Count>0 then begin
2954
3183
if not assigned(SortProc) then SortProc := @DefaultTreeViewSort;
2955
3184
FTreeNodes.SortTopLevelNodes(SortProc);
2957
3186
Node := FTreeNodes.GetFirstNode;
2958
3187
while Node <> nil do begin
2959
if Node.HasChildren then Node.CustomSort(SortProc);
3188
if (Node.GetFirstChild<>nil) then Node.CustomSort(SortProc);
2960
3189
Node := Node.GetNext;
2962
3191
Items.ClearCache;
2963
3192
FStates:= FStates+[tvsTopsNeedsUpdate, tvsTopItemNeedsUpdate,
2964
tvsBottomItemNeedsUpdate,
2965
tvsScrollbarChanged,tvsMaxRightNeedsUpdate];
3193
tvsBottomItemNeedsUpdate,tvsScrollbarChanged];
3037
3265
if AValue=FScrolledTop then exit;
3038
3266
EndEditing(true);
3039
3267
FScrolledTop:=AValue;
3040
FStates:=FStates+[tvsTopItemNeedsUpdate,tvsBottomItemNeedsUpdate,
3041
tvsScrollbarChanged];
3268
FStates:=FStates+[tvsTopItemNeedsUpdate,tvsBottomItemNeedsUpdate,tvsScrollbarChanged];
3101
3328
if (tvoAllowMultiselect in ChangedOptions) then begin
3102
3329
if (tvoAllowMultiselect in FOptions) then begin
3103
if Selected<>nil then Selected.MultiSelected:=true;
3330
if Selected<>nil then
3331
Selected.MultiSelected:=true;
3105
3333
Items.ClearMultiSelection;
3125
3353
NewDefItemHeight:=Images.Height;
3126
3354
if (StateImages<>nil) and (StateImages.Height>NewDefItemHeight) then
3127
3355
NewDefItemHeight:=StateImages.Height;
3356
if Odd(NewDefItemHeight) then Inc(NewDefItemHeight);
3128
3357
if NewDefItemHeight<>FDefItemHeight then begin
3129
3358
FDefItemHeight:=NewDefItemHeight;
3130
FStates:=FStates+[tvsTopsNeedsUpdate,tvsTopItemNeedsUpdate,
3131
tvsBottomItemNeedsUpdate];
3359
FStates:=FStates+[tvsTopsNeedsUpdate,tvsTopItemNeedsUpdate,tvsBottomItemNeedsUpdate];
3137
3365
procedure TCustomTreeView.UpdateAllTops;
3139
procedure CalculateTops(FirstSibling: TTreeNode; var CurTop: integer);
3369
procedure CalculateTops(Node: TTreeNode);
3141
while FirstSibling<>nil do begin
3142
FirstSibling.fTop:=CurTop;
3143
inc(CurTop,FirstSibling.Height);
3144
if FirstSibling.Expanded then
3145
CalculateTops(FirstSibling.GetFirstChild,CurTop);
3146
FirstSibling:=FirstSibling.GetNextSibling;
3371
while Node<>nil do begin
3372
if Node.FVisible then begin
3374
inc(CurTop, Node.Height);
3375
if Node.Expanded then
3376
CalculateTops(Node.GetFirstChild);
3378
Node:=Node.GetNextSibling;
3152
3383
if not (tvsTopsNeedsUpdate in FStates) then exit;
3154
CalculateTops(Items.GetFirstNode,i);
3385
CalculateTops(Items.GetFirstVisibleNode);
3155
3386
Exclude(FStates,tvsTopsNeedsUpdate);
3156
3387
Include(FStates,tvsScrollbarChanged);
3231
3462
procedure TCustomTreeView.UpdateBottomItem;
3233
if (FStates*[tvsTopItemNeedsUpdate,tvsTopsNeedsUpdate,
3234
tvsBottomItemNeedsUpdate]=[])
3464
if (FStates*[tvsTopItemNeedsUpdate,tvsTopsNeedsUpdate,tvsBottomItemNeedsUpdate]=[])
3236
if not (tvsBottomItemNeedsUpdate in FStates) then exit;
3466
// if not (tvsBottomItemNeedsUpdate in FStates) then exit; already above
3237
3467
FBottomItem:=TopItem;
3238
3468
while (FBottomItem<>nil) and (FBottomItem.GetNextVisible<>nil) do
3239
3469
FBottomItem:=FBottomItem.GetNextVisible;
3481
procedure TCustomTreeView.SetSeparatorColor(const AValue: TColor);
3483
if fSeparatorColor=AValue then exit;
3484
fSeparatorColor:=AValue;
3485
if tvoShowSeparators in Options then
3251
3489
procedure TCustomTreeView.SetShowButton(Value: Boolean);
3253
3491
if ShowButtons <> Value then begin
3368
3606
function TCustomTreeView.GetMaxScrollTop: integer;
3369
var LastVisibleNode: TTreeNode;
3608
LastVisibleNode: TTreeNode;
3371
3610
LastVisibleNode:=Items.GetLastExpandedSubNode;
3372
3611
if LastVisibleNode=nil then
3382
function TCustomTreeView.GetNodeAtInternalY(Y: Integer): TTreeNode;
3383
// search in all expanded nodes for the node at the absolute coordinate Y
3387
i := IndexOfNodeAtTop(Items.FTopLvlItems, Items.FTopLvlCount, Y);
3390
Result := Items.FTopLvlItems[i];
3391
while Result.Expanded do
3393
i := IndexOfNodeAtTop(Result.FItems, Result.FCount, Y);
3395
Result := Result.Items[i]
3404
3621
function TCustomTreeView.GetNodeAtY(Y: Integer): TTreeNode;
3405
3622
// search in all expanded nodes for the node at the screen coordinate Y
3627
if not Assigned(Items) then
3408
3629
if (Y >= BorderWidth) and (Y < (ClientHeight - ScrollBarWidth) - BorderWidth) then
3410
3631
inc(Y, FScrolledTop - BorderWidth);
3411
Result := GetNodeAtInternalY(Y);
3632
i := IndexOfNodeAtTop(Items.FTopLvlItems, Items.FTopLvlCount, Y);
3635
Result := Items.FTopLvlItems[i];
3636
while Result.Visible and Result.Expanded do
3638
i := IndexOfNodeAtTop(Result.FItems, Result.FCount, Y);
3640
Result := Result.Items[i]
3595
3825
function TCustomTreeView.IsNodeVisible(ANode: TTreeNode): Boolean;
3597
Result:=(ANode<>nil) and (ANode.AreParentsExpanded);
3598
//DebugLn('[TCustomTreeView.IsNodeVisible] A Node=',DbgS(ANode),
3599
//' ANode.AreParentsExpanded=',ANode.AreParentsExpanded);
3827
Result:=(ANode<>nil) and (ANode.Visible) and (ANode.AreParentsExpandedAndVisible);
3600
3828
if Result then begin
3601
3829
//DebugLn('[TCustomTreeView.IsNodeVisible] B Node=',DbgS(ANode),
3602
3830
// ' ',dbgs(FScrolledTop)+'>=',dbgs(ANode.Top+ANode.Height)+' or =',dbgs(FScrolledTop),'+'+dbgs(ClientHeight)+'<',dbgs(ANode.Top));
3612
3840
function TCustomTreeView.IsNodeHeightFullVisible(ANode: TTreeNode): Boolean;
3614
Result:=(ANode<>nil) and (ANode.AreParentsExpanded);
3615
//DebugLn('[TCustomTreeView.IsNodeVisible] A Node=',DbgS(ANode),
3616
//' ANode.AreParentsExpanded=',ANode.AreParentsExpanded);
3842
Result:=(ANode<>nil) and (ANode.AreParentsExpandedAndVisible);
3617
3843
if Result then begin
3618
3844
//DebugLn('[TCustomTreeView.IsNodeVisible] B Node=',DbgS(ANode),
3619
3845
//' ',FScrolledTop,'>=',ANode.Top,'+',ANode.Height,' or ',FScrolledTop,'+',ClientHeight,'<',ANode.Top);
3692
3918
lNode.Expanded := False;
3695
if Items.GetFirstNode<>nil then
3696
lNode := Items.GetFirstNode;
3922
tempNode := Items.GetFirstVisibleNode;
3923
if tempNode<>nil then
3699
if Items.GetFirstNode<>nil then
3700
lNode := Items.GetLastExpandedSubNode;
3929
tempNode := Items.GetLastExpandedSubNode;
3930
if tempNode<>nil then
3702
3934
VK_PRIOR: // Page Up
3703
3935
if lNode <> nil then
3896
4119
procedure TCustomTreeView.SetSelection(Value: TTreeNode);
3897
var OldNode: TTreeNode;
3899
if FSelectedNode=Value then exit;
4123
if FSelectedNode = Value then Exit;
3900
4124
if not CanChange(FSelectedNode) then
4126
{$IFDEF TREEVIEW_DEBUG}
4127
DebugLn('TCustomTreeView.SetSelection: Changing selection for Node: ', Text);
3902
4129
EndEditing(true); // end editing before FSelectedNode change
3903
OldNode:=FSelectedNode;
3904
FSelectedNode:=Value;
3905
if OldNode<>nil then begin
3906
OldNode.Selected:=false;
3908
if Value <> nil then begin
4130
OldNode := FSelectedNode;
4131
FSelectedNode := Value;
4132
if Assigned(OldNode) then
4133
OldNode.Selected := False;
4134
if Assigned(Value) then
3909
4136
Value.Selected := True;
3910
4137
Value.MakeVisible;
4069
4296
procedure TCustomTreeView.DoSelectionChanged;
4298
lAccessibleObject: TLazAccessibleObject;
4299
lSelection: TTreeNode;
4300
lSelectedText: string;
4302
// Update the accessibility information
4303
lAccessibleObject := GetAccessibleObject();
4304
lSelection := Self.Selected;
4305
if lSelection = nil then lSelectedText := ''
4306
else lSelectedText := lSelection.Text;
4307
lAccessibleObject.AccessibleValue := lSelectedText;
4071
4309
if Assigned(OnSelectionChanged) then OnSelectionChanged(Self);
4187
4425
//if Node<>nil then DebugLn(' Node.Text=',Node.Text) else DebugLn('');
4188
4426
while Node <> nil do
4428
if Node.Visible then
4191
4430
Node := Node.GetNextVisible;
4192
4431
//write('[TCustomTreeView.DoPaint] B Node=',DbgS(Node));
4193
4432
//if Node<>nil then DebugLn(' Node.Text=',Node.Text) else DebugLn('');
4340
4569
DrawHorzLine(VertMid, CurMid, Result + Indent);
4343
if (CurNode.GetNextSibling <> nil) then
4572
if (CurNode.GetNextVisibleSibling <> nil) then
4345
4574
// draw vertical line to next brother
4346
4575
if (CurNode = Node) and HasExpandSign then
4548
4777
Details := ThemeServices.GetElementDetails(ttItemSelected)
4550
4779
Details := ThemeServices.GetElementDetails(ttItemSelectedNotFocus);
4780
if ThemeServices.HasTransparentParts(Details) then
4782
Canvas.Brush.Color := BackgroundColor;
4783
Canvas.FillRect(ARect);
4551
4785
ThemeServices.DrawElement(Canvas.Handle, Details, ARect, nil);
4589
4823
Details := ThemeServices.GetElementDetails(ttItemNormal);
4591
4825
if (tvoThemedDraw in Options) then
4592
ThemeServices.DrawText(Canvas, Details, AText, NodeRect, DT_CENTER or DT_VCENTER or DT_SINGLELINE, 0)
4826
ThemeServices.DrawText(Canvas, Details, AText, NodeRect, DT_CENTER or DT_VCENTER or DT_SINGLELINE or DT_NOPREFIX, 0)
4594
DrawText(Canvas.Handle, PChar(AText), -1, NodeRect, DT_CENTER or DT_VCENTER or DT_SINGLELINE);
4828
DrawText(Canvas.Handle, PChar(AText), -1, NodeRect, DT_CENTER or DT_VCENTER or DT_SINGLELINE or DT_NOPREFIX);
4654
4888
if (ImgIndex >= 0) and (ImgIndex < Images.Count) then
4655
4889
Images.Draw(Canvas, x + 1, (NodeRect.Top + NodeRect.Bottom - Images.Height) div 2,
4890
ImgIndex, Node.FNodeEffect);
4657
4891
inc(x, Images.Width + 2);
4870
5104
if (ssShift in Shift) then
4872
5106
Exclude(FStates,tvsEditOnMouseUp);
4873
CursorNode.MultiSelectGroup;
5107
LockSelectionChangeEvent;
5109
Items.ClearMultiSelection;
5110
CursorNode.MultiSelectGroup;
5112
UnlockSelectionChangeEvent;
4876
5116
if (ssCtrl in Shift) then
4908
5148
if Button=mbLeft then
4909
5149
MouseCapture := False;
4910
5150
if (Button=mbLeft)
4911
and (fStates * [tvsDblClicked, tvsTripleClicked, tvsQuadClicked] = [])
5151
and (FStates * [tvsDblClicked, tvsTripleClicked, tvsQuadClicked] = [])
4913
5153
//AquirePrimarySelection;
4914
5154
if (tvsEditOnMouseUp in FStates) and (not ReadOnly)
4916
5156
and (GetNodeAt(fMouseDownPos.X,fMouseDownPos.Y)=GetNodeAt(X,Y)) then
4917
5157
BeginEditing(Selected);
4919
fStates:=fStates-[tvsDblClicked,tvsTripleClicked,tvsQuadClicked,tvsEditOnMouseUp];
5159
FStates:=FStates-[tvsDblClicked,tvsTripleClicked,tvsQuadClicked,tvsEditOnMouseUp];
4922
procedure TCustomTreeView.Notification(AComponent: TComponent;
4923
Operation: TOperation);
5162
procedure TCustomTreeView.Notification(AComponent: TComponent; Operation: TOperation);
4925
5164
inherited Notification(AComponent, Operation);
4926
5165
if Operation = opRemove then begin
5106
5341
procedure TCustomTreeView.Resize;
5108
FStates:=FStates+[tvsScrollbarChanged,
5109
tvsBottomItemNeedsUpdate];
5343
FStates:=FStates+[tvsScrollbarChanged,tvsBottomItemNeedsUpdate];
5110
5344
inherited Resize;
5347
function TCustomTreeView.GetSelectedChildAccessibleObject: TLazAccessibleObject;
5352
lNode := GetSelection();
5353
if lNode = nil then Exit;
5354
Result := FAccessibleObject.GetChildAccessibleObjectWithDataObject(lNode);
5357
function TCustomTreeView.GetChildAccessibleObjectAtPos(APos: TPoint): TLazAccessibleObject;
5362
lNode := GetNodeAt(APos.X, APos.Y);
5363
//if lNode = nil then DebugLn('[TCustomTreeView.GetChildAccessibleObjectAtPos] lNode=nil')
5364
//else DebugLn('[TCustomTreeView.GetChildAccessibleObjectAtPos] lNode=' + lNode.Text);
5365
if lNode = nil then Exit;
5366
Result := FAccessibleObject.GetChildAccessibleObjectWithDataObject(lNode);
5113
5369
procedure TCustomTreeView.InternalSelectionChanged;
5115
if fSelectionChangeEventLock>0 then begin
5116
Include(fStates,tvsSelectionChanged);
5118
Exclude(fStates,tvsSelectionChanged);
5371
if FSelectionChangeEventLock > 0 then
5372
Include(FStates, tvsSelectionChanged)
5375
Exclude(FStates, tvsSelectionChanged);
5119
5376
DoSelectionChanged;
5120
FChangeTimer.Enabled := false;
5121
FChangeTimer.Enabled := true;
5377
FChangeTimer.Enabled := False;
5378
FChangeTimer.Enabled := True;
5122
5379
//debugln('TCustomTreeView.InternalSelectionChanged');
5158
5415
WasFocused: Boolean;
5160
if (Key=VK_ESCAPE) or (Key=VK_RETURN) then begin
5161
WasFocused:=(FEditor<>nil) and FEditor.Focused;
5162
EndEditing(Key=VK_ESCAPE);
5417
if (Key = VK_ESCAPE) or (Key = VK_RETURN) then
5419
WasFocused := Assigned(FEditor) and FEditor.Focused;
5420
EndEditing(Key = VK_ESCAPE);
5163
5421
if WasFocused then
5165
Key:=0; // key was handled
5423
Key := 0; // key was handled
5294
5552
procedure TCustomTreeView.LockSelectionChangeEvent;
5296
inc(fSelectionChangeEventLock);
5554
inc(FSelectionChangeEventLock);
5299
5557
procedure TCustomTreeView.UnlockSelectionChangeEvent;
5301
dec(fSelectionChangeEventLock);
5302
if fSelectionChangeEventLock<0 then
5559
dec(FSelectionChangeEventLock);
5560
if FSelectionChangeEventLock<0 then
5303
5561
RaiseGDBException('TCustomTreeView.UnlockSelectionChangeEvent');
5304
if (fSelectionChangeEventLock=0)
5305
and (tvsSelectionChanged in fStates) then
5562
if (FSelectionChangeEventLock=0) and (tvsSelectionChanged in FStates) then
5306
5563
InternalSelectionChanged;
5351
5608
ANode.MakeVisible;
5354
procedure TCustomTreeView.SetSeparatorColor(const AValue: TColor);
5356
if fSeparatorColor=AValue then exit;
5357
fSeparatorColor:=AValue;
5358
if tvoShowSeparators in Options then
5611
procedure TCustomTreeView.ClearInvisibleSelection;
5615
if tvoAllowMultiSelect in FOptions then begin
5616
Items.ClearMultiSelection(True); // Now clears all multi-selected
5619
ANode := Selected; // Clear a single selection only if not visible
5620
if Assigned(ANode) and not ANode.Visible then
5621
ANode.Selected:=False; // Selected := nil;
5625
procedure TCustomTreeView.MoveToNextNode;
5629
if tvoAllowMultiSelect in FOptions then
5630
ANode := FTreeNodes.FLastMultiSelected
5633
if ANode <> nil then
5634
ANode := ANode.GetNextVisible;
5635
if (ANode = nil) and (Items.Count > 0) then
5636
ANode := FTreeNodes.GetFirstVisibleNode;
5637
if ANode <> nil then
5638
if tvoAllowMultiSelect in FOptions then
5639
FTreeNodes.SelectOnlyThis(ANode)
5644
procedure TCustomTreeView.MoveToPrevNode;
5648
if tvoAllowMultiSelect in FOptions then
5649
ANode := FTreeNodes.FLastMultiSelected
5652
if ANode <> nil then
5653
ANode := ANode.GetPrevVisible;
5654
if (ANode = nil) and (Items.Count > 0) then
5655
ANode := Items.GetLastExpandedSubNode;
5656
if ANode <> nil then
5657
if tvoAllowMultiSelect in FOptions then
5658
FTreeNodes.SelectOnlyThis(ANode)
5663
function TCustomTreeView.StoreCurrentSelection: TStringList;
5667
Result:=TStringList.Create;
5669
while ANode<>nil do begin
5670
Result.Insert(0,ANode.Text);
5671
ANode:=ANode.Parent;
5675
procedure TCustomTreeView.ApplyStoredSelection(ASelection: TStringList; FreeList: boolean);
5681
while ASelection.Count>0 do begin
5682
CurText:=ASelection[0];
5684
ANode:=Items.GetFirstNode
5686
ANode:=ANode.GetFirstChild;
5687
while (ANode<>nil) and (ANode.Text<>CurText) do
5688
ANode:=ANode.GetNextSibling;
5689
if ANode=nil then break;
5690
ASelection.Delete(0);
5362
5698
// back to comctrls.pp