~ubuntu-branches/ubuntu/gutsy/lazarus/gutsy

« back to all changes in this revision

Viewing changes to lcl/include/treeview.inc

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner
  • Date: 2007-05-06 13:46:10 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070506134610-lf4rbsb7p0mx31x1
Tags: 0.9.22-1
* Add homepage to debian/control.
* New upstream release. (Closes: #421850, #408512)
* Remove old patch and add new symlink /usr/bin/startlazarus.
* Add myself to Uploaders.
* Add XS-X-Vcs-Svn header to debian/control.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
  ToDo:
26
26
    - Editing
27
27
    - Columns
28
 
    - create FTopLvlItems only on demand and update only if easy
29
28
}
30
29
 
31
30
 
64
63
  raise ETreeViewError.Create(Msg);
65
64
end;
66
65
 
67
 
{procedure TreeViewErrorFmt(const Msg: string; Format: array of const);
68
 
begin
69
 
  raise ETreeViewError.CreateFmt(Msg, Format);
70
 
end;}
71
 
 
72
66
procedure TreeNodeError(const Msg: string);
73
67
begin
74
68
  raise ETreeNodeError.Create(Msg);
89
83
  r:=Count-1;
90
84
  while (l<=r) do begin
91
85
    m:=(l+r) shr 1;
92
 
//DebugLn(':0 [IndexOfNodeAtTop] m=',m,' y=',y,' ',NodeArray[m].Text,' NodeArray[m].Top=',NodeArray[m].Top,' NodeArray[m].BottomExpanded=',NodeArray[m].BottomExpanded);
 
86
    //DebugLn(':0 [IndexOfNodeAtTop] m=',m,' y=',y,' ',NodeArray[m].Text,' NodeArray[m].Top=',NodeArray[m].Top,' NodeArray[m].BottomExpanded=',NodeArray[m].BottomExpanded);
93
87
    if NodeArray[m].Top>y then
94
88
      r:=m-1
95
89
    else if NodeArray[m].BottomExpanded<=y then
100
94
  Result:=-1;
101
95
end;
102
96
 
103
 
{ procedure for sorting a TTreeNodeArray}
104
 
 
 
97
// procedure for sorting a TTreeNodeArray
105
98
procedure Sort(Nodes: TTreeNodeArray; Count: integer;
106
 
  SortProc: TTreeNodeCompare);
 
99
  SortProc: TTreeNodeCompare; UpdateIndex: Boolean);
107
100
// Sorts the nodes using merge sort and updates the sibling links
108
101
var
109
102
  Buffer: TTreeNodeArray;
169
162
    // update sibling links
170
163
    Nodes[0].FPrevBrother := nil;
171
164
    Nodes[Count-1].FNextBrother := nil;
 
165
    if UpdateIndex then Nodes[0].FIndex:=0;
172
166
    for i:= 1 to Count-1 do begin
173
167
      Nodes[i].FPrevBrother := Nodes[i-1];
174
168
      Nodes[i-1].FNextBrother := Nodes[i];
 
169
      if UpdateIndex then Nodes[i].FIndex:=i;
175
170
    end;
176
171
  end;
177
172
end;
264
259
  FStateIndex := -1;
265
260
  FStates := [];
266
261
  FOwner := AnOwner;
267
 
  FSubTreeCount:=1;
 
262
  FSubTreeCount := 1;
 
263
  FIndex := -1;
268
264
  if Owner<>nil then inc(Owner.FCount);
269
265
end;
270
266
 
273
269
  {$IFDEF TREEVIEW_DEBUG}
274
270
  DebugLn('[TTreeNode.Destroy] Self=',DbgS(Self),' Self.Text=',Text);
275
271
  {$ENDIF}
276
 
  FDeleting := True;
 
272
  Include(FStates,nsDeleting);
277
273
  // delete childs
278
274
  HasChildren := false;
279
275
  // unbind all references
280
276
  Unbind;
281
277
  if Owner<>nil then begin
282
278
    if Owner.Owner<>nil then
283
 
      Owner.Owner.Delete(self);
 
279
      Owner.Owner.Delete(Self);
284
280
    dec(Owner.FCount);
285
281
  end;
286
282
  Data := nil;
356
352
  FText := S;
357
353
  if TreeView=nil then exit;
358
354
  Include(TreeView.FStates,tvsMaxRightNeedsUpdate);
359
 
  if (TreeView.SortType in [stText, stBoth]) and FInTree then begin
 
355
  if (TreeView.SortType in [stText, stBoth])
 
356
  and (nsInTree in FStates) then begin
360
357
    if (Parent <> nil) then Parent.AlphaSort
361
358
    else TreeView.AlphaSort;
362
359
  end;
369
366
  FData := AValue;
370
367
  if (TreeView<>nil)
371
368
  and (TreeView.SortType in [stData, stBoth]) and Assigned(TreeView.OnCompare)
372
 
  and (not Deleting) and FInTree then
 
369
  and (not Deleting)
 
370
  and (nsInTree in FStates) then
373
371
  begin
374
372
    if Parent <> nil then
375
373
      Parent.AlphaSort
400
398
  Update;
401
399
end;
402
400
 
 
401
procedure TTreeNode.SetIndex(const AValue: Integer);
 
402
 
 
403
  procedure RaiseMissingTreeNodes;
 
404
  begin
 
405
    TreeViewError('TTreeNode.SetIndex missing Owner');
 
406
  end;
 
407
 
 
408
var
 
409
  OldIndex: LongInt;
 
410
begin
 
411
  OldIndex:=Index;
 
412
  if OldIndex=AValue then exit;
 
413
  if Parent=nil then begin
 
414
    // moving a top level node
 
415
    if Owner=nil then RaiseMissingTreeNodes;
 
416
    if AValue=0 then
 
417
      MoveTo(Owner.GetFirstNode,naInsert)
 
418
    else if AValue<OldIndex then
 
419
      MoveTo(Owner.TopLvlItems[AValue-1],naInsertBehind)
 
420
    else
 
421
      MoveTo(Owner.TopLvlItems[AValue],naInsertBehind);
 
422
  end else begin
 
423
    // moving a normal node
 
424
    if AValue=0 then
 
425
      MoveTo(Parent.GetFirstChild,naInsert)
 
426
    else if AValue<OldIndex then
 
427
      MoveTo(Parent.Items[AValue-1],naInsertBehind)
 
428
    else
 
429
      MoveTo(Parent.Items[AValue],naInsertBehind);
 
430
  end;
 
431
end;
 
432
 
403
433
procedure TTreeNode.SetSelectedIndex(AValue: Integer);
404
434
begin
405
435
  if FSelectedIndex = AValue then exit;
558
588
end;
559
589
 
560
590
procedure TTreeNode.SetSelected(AValue: Boolean);
 
591
var
 
592
  MultiSelect: Boolean;
561
593
begin
562
594
  if AValue=GetSelected then exit;
563
595
  if AValue then begin
564
596
    Include(FStates,nsSelected);
565
 
    if (TreeView<>nil) and (TreeView.Selected=nil) then begin
566
 
      TreeView.Selected:=Self;
567
 
      if TreeView.Selected<>Self then
568
 
        Exclude(FStates,nsSelected);
 
597
    if (TreeView<>nil) then begin
 
598
      MultiSelect:=tvoAllowMultiselect in TreeView.Options;
 
599
      if MultiSelect then TreeView.LockSelectionChangeEvent;
 
600
      try
 
601
        TreeView.Selected:=Self;
 
602
        if TreeView.Selected<>Self then
 
603
          Exclude(FStates,nsSelected);
 
604
        if (nsSelected in FStates) and MultiSelect then
 
605
          MultiSelected:=true;
 
606
      finally
 
607
        if MultiSelect then TreeView.UnlockSelectionChangeEvent;
 
608
      end;
569
609
    end;
570
610
  end else begin
571
611
    Exclude(FStates,nsSelected);
879
919
  until ANode=nil;
880
920
end;
881
921
 
 
922
function TTreeNode.GetDeleting: Boolean;
 
923
begin
 
924
  Result:=nsDeleting in FStates;
 
925
end;
 
926
 
882
927
function TTreeNode.GetHeight: integer;
883
928
begin
884
929
  if FHeight<=0 then begin
895
940
var
896
941
  ANode: TTreeNode;
897
942
begin
 
943
  if FIndex>=0 then begin
 
944
    Result:=FIndex;
 
945
  end;
898
946
  // many algorithms uses the last sibling, so we check that first for speed
899
947
  if (Parent<>nil) and (Parent[Parent.Count-1]=Self) then begin
900
948
    Result:=Parent.Count-1;
914
962
  if (AnIndex<0) or (AnIndex>=Count) then
915
963
    TreeNodeErrorFmt(rsIndexOutOfBounds,[ClassName, AnIndex, Count]);
916
964
  Result:=FItems[AnIndex];
917
 
  {Result := GetFirstChild;
918
 
  while (Result <> nil) and (Index > 0) do
919
 
  begin
920
 
    Result := GetNextChild(Result);
921
 
    Dec(Index);
922
 
  end;
923
 
  if Result = nil then TreeViewError(SListIndexError);}
924
965
end;
925
966
 
926
967
procedure TTreeNode.SetItems(AnIndex: Integer; AValue: TTreeNode);
948
989
 
949
990
function TTreeNode.IndexOf(AValue: TTreeNode): Integer;
950
991
begin
951
 
  if AValue=nil then begin
 
992
  if (AValue=nil) or (AValue.FParent<>Self) then begin
952
993
    Result:=-1;
953
994
    exit;
954
995
  end;
955
 
  Result:=Count-1;
956
 
  while Result>=0 do begin
957
 
    if FItems[Result]=AValue then exit;
958
 
    dec(Result);
959
 
  end;
 
996
  Result:=AValue.GetIndex;
960
997
end;
961
998
 
962
999
function TTreeNode.IndexOfText(const NodeText: string): Integer;
975
1012
    Result:=Result.GetNextSibling;
976
1013
end;
977
1014
 
 
1015
function TTreeNode.GetTextPath: string;
 
1016
var
 
1017
  Node: TTreeNode;
 
1018
begin
 
1019
  Result:='';
 
1020
  Node:=Self;
 
1021
  while Node<>nil do begin
 
1022
    if Result<>'' then
 
1023
      Result:='/'+Result;
 
1024
    Result:=Node.Text+Result;
 
1025
    Node:=Node.Parent;
 
1026
  end;
 
1027
end;
 
1028
 
978
1029
function TTreeNode.GetCount: Integer;
979
1030
begin
980
1031
  Result:=FCount;
1014
1065
        TheTreeView.FInsertMarkNode:=nil;
1015
1066
    end;
1016
1067
  end;
1017
 
  // unselect (multi)
 
1068
  // unmultiselect (keeping MultiSelected, but leaving multiselection list)
1018
1069
  UnbindFromMultiSelected;
1019
1070
  // remove from sibling list
1020
1071
  if FPrevBrother<>nil then FPrevBrother.FNextBrother:=FNextBrother;
1031
1082
    end;
1032
1083
    //if TreeNodes<>nil then Dec(TreeNodes.FCount,FSubTreeCount);
1033
1084
    // remove from parents list
1034
 
    OldIndex:=FParent.FCount-1;
1035
 
    while (OldIndex>=0) and (FParent.FItems[OldIndex]<>Self) do
1036
 
      dec(OldIndex);
 
1085
    OldIndex:=FIndex;
1037
1086
    if OldIndex<0 then
1038
1087
      RaiseGDBException('');
1039
 
    for i:=OldIndex to FParent.FCount-2 do
 
1088
    for i:=OldIndex to FParent.FCount-2 do begin
1040
1089
      FParent.FItems[i]:=FParent.FItems[i+1];
 
1090
      FParent.FItems[i].FIndex:=i;
 
1091
    end;
1041
1092
    dec(FParent.FCount);
1042
1093
    if (FParent.FCapacity>15) and (FParent.FCount<(FParent.FCapacity shr 2))
1043
1094
    then begin
1080
1131
}
1081
1132
var HigherNode: TTreeNode;
1082
1133
  NewIndex, NewParentItemSize, i: integer;
 
1134
  WasSelected: Boolean;
1083
1135
begin
1084
1136
  {$IFDEF TREEVIEW_DEBUG}
1085
1137
  DbgOut('[TTreeNode.InternalMove]  Self=',DbgS(Self),' Self.Text=',Text
1087
1139
  if ANode<>nil then DbgOut(' ANode.Text=',ANode.Text);
1088
1140
  DebugLn('');
1089
1141
  {$ENDIF}
1090
 
  Unbind;
1091
 
  // set parent
1092
 
  if AddMode in [taAdd, taAddFirst] then
1093
 
    FParent:=ANode
1094
 
  else begin // taInsert
1095
 
    if (ANode=nil) then
1096
 
      TreeNodeError('TTreeNode.InternalMove AddMode=taInsert but ANode=nil');
1097
 
    FParent:=ANode.Parent;
1098
 
    FPrevBrother:=ANode.FPrevBrother;
1099
 
    FNextBrother:=ANode;
1100
 
  end;
1101
 
  if FParent<>nil then begin
1102
 
    FParent.HasChildren:=true;
1103
 
    if (FParent.FCount=FParent.FCapacity) then begin
1104
 
      // grow FParent.FItems
1105
 
      if FParent.FCapacity=0 then
1106
 
        FParent.FCapacity:=5
1107
 
      else
1108
 
        FParent.FCapacity:=FParent.FCapacity shl 1;
1109
 
      NewParentItemSize:=SizeOf(Pointer)*FParent.FCapacity;
1110
 
      if FParent.FItems=nil then
1111
 
        GetMem(FParent.FItems,NewParentItemSize)
1112
 
      else
1113
 
        ReAllocMem(FParent.FItems,NewParentItemSize);
1114
 
    end;
1115
 
    inc(FParent.FCount);
1116
 
    // calculate new Index
1117
 
    case AddMode of
1118
 
    taAdd: NewIndex:=FParent.Count-1;
1119
 
    taAddFirst: NewIndex:=0;
1120
 
    else
1121
 
      // taInsert
1122
 
      NewIndex:=ANode.Index;
1123
 
    end;
1124
 
    // move next siblings
1125
 
    for i:=FParent.FCount-1 downto NewIndex+1 do
1126
 
      FParent.FItems[i]:=FParent.FItems[i-1];
1127
 
    // insert this node to parent's items
1128
 
    FParent.FItems[NewIndex]:=Self;
1129
 
    // set Next and Prev sibling
1130
 
    if NewIndex>0 then
1131
 
      FPrevBrother:=FParent.FItems[NewIndex-1]
1132
 
    else
1133
 
      FPrevBrother:=nil;
1134
 
    if NewIndex<FParent.Count-1 then
1135
 
      FNextBrother:=FParent.FItems[NewIndex+1]
1136
 
    else
1137
 
      FNextBrother:=nil;
1138
 
    // update total node count of all parents
1139
 
    HigherNode:=FParent;
1140
 
    while HigherNode<>nil do begin
1141
 
      inc(HigherNode.FSubTreeCount,FSubTreeCount);
1142
 
      HigherNode:=HigherNode.Parent;
1143
 
    end;
1144
 
    //if TreeNodes<>nil then inc(TreeNodes.FCount,FSubTreeCount);
1145
 
  end else begin
1146
 
    // add as top level node
1147
 
    case AddMode of
1148
 
    taAdd:
1149
 
      begin
1150
 
        // add as last top level node
1151
 
        if Owner<>nil then begin
1152
 
          FPrevBrother:=Owner.GetLastNode;
1153
 
          Owner.MoveTopLvlNode(-1,Owner.FTopLvlCount,Self);
1154
 
        end;
1155
 
      end;
1156
 
    taAddFirst:
1157
 
      begin
1158
 
        // add as first top level node = root node
1159
 
        if Owner<>nil then begin
1160
 
          FNextBrother:=Owner.GetFirstNode;
1161
 
          Owner.MoveTopLvlNode(-1,0,Self);
1162
 
        end;
1163
 
      end;
1164
 
    taInsert:
1165
 
      begin
1166
 
        // insert node in front of ANode
1167
 
        //DebugLn('[TTreeNode.InternalMove] ANode.Index=',ANode.Index,' ANode=',DbgS(ANode));
1168
 
        FNextBrother:=ANode;
1169
 
        FPrevBrother:=ANode.GetPrevSibling;
1170
 
        if Owner<>nil then begin
1171
 
          Owner.MoveTopLvlNode(-1,ANode.Index,Self);
1172
 
        end;
1173
 
      end;
1174
 
    end;
1175
 
  end;
1176
 
  // connect Next and Prev sibling
1177
 
  if FPrevBrother<>nil then FPrevBrother.FNextBrother:=Self;
1178
 
  if FNextBrother<>nil then FNextBrother.FPrevBrother:=Self;
1179
 
  if Owner.Owner<>nil then
1180
 
    Owner.Owner.FStates:=Owner.Owner.FStates+[tvsMaxRightNeedsUpdate,
1181
 
      tvsTopsNeedsUpdate,tvsTopItemNeedsUpdate,tvsBottomItemNeedsUpdate];
 
1142
  if TreeView<>nil then TreeView.BeginUpdate;
 
1143
  try
 
1144
    WasSelected:=Selected;
 
1145
    Unbind;
 
1146
    // set parent
 
1147
    if AddMode in [taAdd, taAddFirst] then
 
1148
      FParent:=ANode
 
1149
    else begin // taInsert
 
1150
      if (ANode=nil) then
 
1151
        TreeNodeError('TTreeNode.InternalMove AddMode=taInsert but ANode=nil');
 
1152
      FParent:=ANode.Parent;
 
1153
      FPrevBrother:=ANode.FPrevBrother;
 
1154
      FNextBrother:=ANode;
 
1155
    end;
 
1156
    if FParent<>nil then begin
 
1157
      FParent.HasChildren:=true;
 
1158
      if (FParent.FCount=FParent.FCapacity) then begin
 
1159
        // grow FParent.FItems
 
1160
        if FParent.FCapacity=0 then
 
1161
          FParent.FCapacity:=5
 
1162
        else
 
1163
          FParent.FCapacity:=FParent.FCapacity shl 1;
 
1164
        NewParentItemSize:=SizeOf(Pointer)*FParent.FCapacity;
 
1165
        if FParent.FItems=nil then
 
1166
          GetMem(FParent.FItems,NewParentItemSize)
 
1167
        else
 
1168
          ReAllocMem(FParent.FItems,NewParentItemSize);
 
1169
      end;
 
1170
      inc(FParent.FCount);
 
1171
      // calculate new Index
 
1172
      case AddMode of
 
1173
      taAdd: NewIndex:=FParent.Count-1;
 
1174
      taAddFirst: NewIndex:=0;
 
1175
      else
 
1176
        // taInsert
 
1177
        NewIndex:=ANode.Index;
 
1178
      end;
 
1179
      // move next siblings
 
1180
      for i:=FParent.FCount-1 downto NewIndex+1 do begin
 
1181
        FParent.FItems[i]:=FParent.FItems[i-1];
 
1182
        FParent.FItems[i].FIndex:=i;
 
1183
      end;
 
1184
      // insert this node to parent's items
 
1185
      FParent.FItems[NewIndex]:=Self;
 
1186
      FIndex:=NewIndex;
 
1187
      // set Next and Prev sibling
 
1188
      if NewIndex>0 then
 
1189
        FPrevBrother:=FParent.FItems[NewIndex-1]
 
1190
      else
 
1191
        FPrevBrother:=nil;
 
1192
      if NewIndex<FParent.Count-1 then
 
1193
        FNextBrother:=FParent.FItems[NewIndex+1]
 
1194
      else
 
1195
        FNextBrother:=nil;
 
1196
      // update total node count of all parents
 
1197
      HigherNode:=FParent;
 
1198
      while HigherNode<>nil do begin
 
1199
        inc(HigherNode.FSubTreeCount,FSubTreeCount);
 
1200
        HigherNode:=HigherNode.Parent;
 
1201
      end;
 
1202
      //if TreeNodes<>nil then inc(TreeNodes.FCount,FSubTreeCount);
 
1203
    end else begin
 
1204
      // add as top level node
 
1205
      case AddMode of
 
1206
      taAdd:
 
1207
        begin
 
1208
          // add as last top level node
 
1209
          if Owner<>nil then begin
 
1210
            FPrevBrother:=Owner.GetLastNode;
 
1211
            Owner.MoveTopLvlNode(-1,Owner.FTopLvlCount,Self);
 
1212
          end;
 
1213
        end;
 
1214
      taAddFirst:
 
1215
        begin
 
1216
          // add as first top level node = root node
 
1217
          if Owner<>nil then begin
 
1218
            FNextBrother:=Owner.GetFirstNode;
 
1219
            Owner.MoveTopLvlNode(-1,0,Self);
 
1220
          end;
 
1221
        end;
 
1222
      taInsert:
 
1223
        begin
 
1224
          // insert node in front of ANode
 
1225
          //DebugLn('[TTreeNode.InternalMove] ANode.Index=',ANode.Index,' ANode=',DbgS(ANode));
 
1226
          FNextBrother:=ANode;
 
1227
          FPrevBrother:=ANode.GetPrevSibling;
 
1228
          if Owner<>nil then begin
 
1229
            Owner.MoveTopLvlNode(-1,ANode.Index,Self);
 
1230
          end;
 
1231
        end;
 
1232
      end;
 
1233
    end;
 
1234
    // connect Next and Prev sibling
 
1235
    if FPrevBrother<>nil then FPrevBrother.FNextBrother:=Self;
 
1236
    if FNextBrother<>nil then FNextBrother.FPrevBrother:=Self;
 
1237
    if Owner.Owner<>nil then
 
1238
      Owner.Owner.FStates:=Owner.Owner.FStates+[tvsMaxRightNeedsUpdate,
 
1239
        tvsTopsNeedsUpdate,tvsTopItemNeedsUpdate,tvsBottomItemNeedsUpdate];
 
1240
    // re-add to multiselection list
 
1241
    if MultiSelected then
 
1242
      BindToMultiSelected;
 
1243
    if WasSelected then
 
1244
      Selected:=true;
 
1245
  finally
 
1246
    if TreeView<>nil then TreeView.EndUpdate;
 
1247
  end;
1182
1248
 
1183
1249
  {$IFDEF TREEVIEW_DEBUG}
1184
1250
  DbgOut('[TTreeNode.InternalMove] END Self=',DbgS(Self),' Self.Text=',Text
1186
1252
  if ANode<>nil then DbgOut(' ANode.Text=',ANode.Text);
1187
1253
  DebugLn('');
1188
1254
  {$ENDIF}
1189
 
 
1190
 
{var
1191
 
  I: Integer;
1192
 
  NodeId: HTreeItem;
1193
 
  TreeViewItem: TTVItem;
1194
 
  Children: Boolean;
1195
 
  IsSelected: Boolean;
1196
 
begin
1197
 
  Owner.ClearCache;
1198
 
  if (AddMode = taInsert) and (Node <> nil) then
1199
 
    NodeId := Node.ItemId else
1200
 
    NodeId := nil;
1201
 
  Children := HasChildren;
1202
 
  IsSelected := Selected;
1203
 
  if (Parent <> nil) and (Parent.CompareCount(1)) then
1204
 
  begin
1205
 
    Parent.Expanded := False;
1206
 
    Parent.HasChildren := False;
1207
 
  end;
1208
 
  with TreeViewItem do
1209
 
  begin
1210
 
    mask := TVIF_PARAM;
1211
 
    hItem := ItemId;
1212
 
    lParam := 0;
1213
 
  end;
1214
 
  TreeView_SetItem(Handle, TreeViewItem);
1215
 
  with Owner do
1216
 
    HItem := AddItem(HItem, NodeId, CreateItem(Self), AddMode);
1217
 
  if HItem = nil then
1218
 
    raise EOutOfResources.Create(sInsertError);
1219
 
  for I := Count - 1 downto 0 do
1220
 
    Item[I].InternalMove(Self, nil, HItem, taAddFirst);
1221
 
  TreeView_DeleteItem(Handle, ItemId);
1222
 
  FItemId := HItem;
1223
 
  Assign(Self);
1224
 
  HasChildren := Children;
1225
 
  Selected := IsSelected;}
1226
1255
end;
1227
1256
 
1228
1257
procedure TTreeNode.MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode);
1272
1301
      else
1273
1302
        AddMode:=taAdd;
1274
1303
      end;
1275
 
      {if ANode <> nil then
1276
 
        HItem := ANode.ItemId else
1277
 
        HItem := nil;}
1278
1304
      if (Destination <> Self) then
1279
1305
        InternalMove(Destination, AddMode);
1280
 
      if Parent <> nil then
1281
 
        Parent.Expanded := True;
1282
1306
    finally
1283
1307
      TreeView.OnChanging := OldOnChanging;
1284
1308
      TreeView.OnChange := OldOnChange;
1293
1317
  if (TreeView<>nil) and (not (tvoAllowMultiselect in TreeView.Options)) then
1294
1318
    exit;
1295
1319
  if (TreeView<>nil) then TreeView.LockSelectionChangeEvent;
1296
 
  FirstNode:=GetPrevSibling;
1297
 
  while (FirstNode<>nil) and (not FirstNode.MultiSelected) do
1298
 
    FirstNode:=FirstNode.GetPrevSibling;
1299
 
  if FirstNode=nil then FirstNode:=Self;
1300
 
  LastNode:=GetNextSibling;
1301
 
  while (LastNode<>nil) and (not LastNode.MultiSelected) do
1302
 
    LastNode:=LastNode.GetNextSibling;
1303
 
  if LastNode=nil then LastNode:=Self;
1304
 
  ANode:=FirstNode;
1305
 
  while ANode<>nil do begin
1306
 
    ANode.MultiSelected:=true;
1307
 
    if ANode=LastNode then break;
1308
 
    ANode:=ANode.GetNextSibling;
 
1320
  try
 
1321
    FirstNode:=GetPrevSibling;
 
1322
    while (FirstNode<>nil) and (not FirstNode.MultiSelected) do
 
1323
      FirstNode:=FirstNode.GetPrevSibling;
 
1324
    if FirstNode=nil then FirstNode:=Self;
 
1325
    LastNode:=GetNextSibling;
 
1326
    while (LastNode<>nil) and (not LastNode.MultiSelected) do
 
1327
      LastNode:=LastNode.GetNextSibling;
 
1328
    if LastNode=nil then LastNode:=Self;
 
1329
    ANode:=FirstNode;
 
1330
    while ANode<>nil do begin
 
1331
      ANode.MultiSelected:=true;
 
1332
      if ANode=LastNode then break;
 
1333
      ANode:=ANode.GetNextSibling;
 
1334
    end;
 
1335
  finally
 
1336
    if (TreeView<>nil) then TreeView.UnlockSelectionChangeEvent;
1309
1337
  end;
1310
 
  if (TreeView<>nil) then TreeView.UnlockSelectionChangeEvent;
1311
1338
end;
1312
1339
 
1313
1340
procedure TTreeNode.MakeVisible;
1378
1405
      if Result.Left>Result.Right then
1379
1406
        Result.Left:=Result.Right;
1380
1407
      Result.Right:=DisplayTextRight;
 
1408
      if Result.Right<Result.Left then
 
1409
        Result.Right:=Result.Left;
1381
1410
    end;
1382
1411
    //TreeView_GetItemRect(Handle, ItemId, Result, TextOnly);
1383
1412
  end;
1387
1416
begin
1388
1417
  Result:=0;
1389
1418
  if TreeView<>nil then begin
1390
 
    inc(Result,TreeView.Indent*Level+TreeView.BorderWidth);
 
1419
    inc(Result,TreeView.Indent*Level+TreeView.BorderWidth-TreeView.FScrolledLeft);
1391
1420
  end;
1392
1421
end;
1393
1422
 
1444
1473
end;
1445
1474
 
1446
1475
function TTreeNode.CustomSort(SortProc: TTreeNodeCompare): Boolean;
1447
 
//var SortCB: TTVSortCB;
1448
1476
begin
1449
1477
  if FCount>0 then begin
1450
1478
    if Owner<>nil then Owner.ClearCache;
1451
1479
    if not Assigned(SortProc) then SortProc:=@DefaultTreeViewSort;
1452
 
    Sort(FItems, FCount, SortProc);
1453
 
    {
1454
 
    with SortCB do begin
1455
 
      if not Assigned(SortProc) then lpfnCompare := @DefaultTreeViewSort
1456
 
      else lpfnCompare := SortProc;
1457
 
      hParent := ItemId;
1458
 
      lParam := Data;
1459
 
    end;
1460
 
    Result := TreeView_SortChildrenCB(Handle, SortCB, 0);
1461
 
    }
 
1480
    Sort(FItems, FCount, SortProc, true);
1462
1481
  end;
1463
1482
  Result:=true;
1464
1483
end;
1596
1615
begin
1597
1616
  if FOwner<>nil then begin
1598
1617
  end;
1599
 
  if FCapacity<0 then RaiseGDBException('');
1600
 
  if FCapacity<FCount then RaiseGDBException('');
1601
 
  if FCount<0 then RaiseGDBException('');
1602
 
  if FHeight<0 then RaiseGDBException('');
1603
 
  if (FItems<>nil) and (FCapacity<=0) then RaiseGDBException('');
1604
 
  if (FCapacity>0) and (FItems=nil) then RaiseGDBException('');
 
1618
  if FCapacity<0 then
 
1619
    RaiseGDBException('');
 
1620
  if FCapacity<FCount then
 
1621
    RaiseGDBException('');
 
1622
  if FCount<0 then
 
1623
    RaiseGDBException('');
 
1624
  if FHeight<0 then
 
1625
    RaiseGDBException('');
 
1626
  if (FItems<>nil) and (FCapacity<=0) then
 
1627
    RaiseGDBException('');
 
1628
  if (FCapacity>0) and (FItems=nil) then
 
1629
    RaiseGDBException('');
1605
1630
  if (FNextBrother<>nil) and (FNextBrother.FPrevBrother<>Self) then
1606
1631
    RaiseGDBException('');
1607
1632
  if (FPrevBrother<>nil) and (FPrevBrother.FNextBrother<>Self) then
1608
1633
    RaiseGDBException('');
 
1634
  if (FNextMultiSelected<>nil) and (FNextMultiSelected.FPrevMultiSelected<>Self) then
 
1635
    RaiseGDBException('');
 
1636
  if (FPrevMultiSelected<>nil) and (FPrevMultiSelected.FNextMultiSelected<>Self) then
 
1637
    RaiseGDBException('');
 
1638
  if MultiSelected then begin
 
1639
    Node1:=TreeView.GetFirstMultiSelected;
 
1640
    while (Node1<>nil) and (Node1<>Self) do Node1:=Node1.FNextMultiSelected;
 
1641
    if Node1=nil then
 
1642
      RaiseGDBException('');
 
1643
  end;
 
1644
  if Selected and (TreeView<>nil) and (tvoAllowMultiselect in TreeView.Options)
 
1645
  and (not MultiSelected) then
 
1646
    RaiseGDBException('');// selected, but not multiselected
 
1647
 
1609
1648
  // check childs
1610
1649
  RealSubTreeCount:=1;
1611
1650
  for i:=0 to FCount-1 do begin
1612
1651
    if (Items[i]=nil) then RaiseGDBException('');
1613
 
    if (i=0) and (Items[i].FPrevBrother<>nil) then RaiseGDBException('');
1614
 
    if (i>0) and (Items[i].FPrevBrother=nil) then RaiseGDBException('');
1615
 
    if (i>0) and (Items[i].FPrevBrother<>Items[i-1]) then RaiseGDBException('');
1616
 
    if (i<FCount-1) and (Items[i].FNextBrother=nil) then
1617
 
      RaiseGDBException('');
1618
 
    if (i<FCount-1) and (Items[i].FNextBrother<>Items[i+1]) then
1619
 
      RaiseGDBException('');
1620
 
    if (i=FCount-1) and (Items[i].FNextBrother<>nil) then
1621
 
      RaiseGDBException('');
1622
 
    if Items[i].FParent<>Self then RaiseGDBException('');
1623
 
    Items[i].ConsistencyCheck;
1624
 
    inc(RealSubTreeCount,Items[i].SubTreeCount);
 
1652
    Node1:=Items[i];
 
1653
    if Node1.FParent<>Self then RaiseGDBException('');
 
1654
    if (i=0) and (Node1.FPrevBrother<>nil) then
 
1655
      RaiseGDBException('');
 
1656
    if (i>0) and (Node1.FPrevBrother=nil) then
 
1657
      RaiseGDBException('');
 
1658
    if (i>0) and (Node1.FPrevBrother<>Items[i-1]) then
 
1659
      RaiseGDBException('');
 
1660
    if (i<FCount-1) and (Node1.FNextBrother=nil) then
 
1661
      RaiseGDBException('');
 
1662
    if (i<FCount-1) and (Node1.FNextBrother<>Items[i+1]) then
 
1663
      RaiseGDBException('');
 
1664
    if (i=FCount-1) and (Node1.FNextBrother<>nil) then
 
1665
      RaiseGDBException('');
 
1666
    if Node1.FIndex<>i then
 
1667
      RaiseGDBException('');
 
1668
    Node1.ConsistencyCheck;
 
1669
    inc(RealSubTreeCount,Node1.SubTreeCount);
1625
1670
  end;
1626
1671
  if FParent<>nil then begin
1627
1672
    if FParent.IndexOf(Self)<0 then RaiseGDBException('');
1683
1728
 
1684
1729
procedure TTreeNodes.Delete(Node: TTreeNode);
1685
1730
begin
1686
 
  //Calling Owner.Delete is done in by TTreeNode.Destroy
1687
 
  //if Owner<>nil then
1688
 
  ////if (Node.ItemId = nil) then
1689
 
  //  Owner.Delete(Node);
1690
1731
  Node.Delete;
 
1732
  if (FUpdateCount=0) and (Owner<>nil) then
 
1733
    Owner.Invalidate;
1691
1734
end;
1692
1735
 
1693
1736
procedure TTreeNodes.Clear;
1697
1740
    GetLastNode.Delete;
1698
1741
end;
1699
1742
 
1700
 
procedure TTreeNodes.ClearMultiSelection;
 
1743
procedure TTreeNodes.ClearMultiSelection(ClearSelected: boolean = false);
1701
1744
var
1702
1745
  ANode, OldNode: TTreeNode;
1703
1746
begin
1704
1747
  if Owner<>nil then Owner.LockSelectionChangeEvent;
1705
 
  ANode:=FFirstMultiSelected;
1706
 
  while ANode<>nil do begin
1707
 
    OldNode:=ANode;
1708
 
    ANode:=ANode.GetNextMultiSelected;
1709
 
    OldNode.MultiSelected:=false;
1710
 
  end;
1711
 
  if Owner<>nil then Owner.UnlockSelectionChangeEvent;
 
1748
  try
 
1749
    ANode:=FFirstMultiSelected;
 
1750
    while ANode<>nil do begin
 
1751
      OldNode:=ANode;
 
1752
      ANode:=ANode.GetNextMultiSelected;
 
1753
      OldNode.MultiSelected:=false;
 
1754
    end;
 
1755
    if ClearSelected then
 
1756
      Owner.Selected:=nil;
 
1757
  finally
 
1758
    if Owner<>nil then Owner.UnlockSelectionChangeEvent;
 
1759
  end;
 
1760
end;
 
1761
 
 
1762
procedure TTreeNodes.SelectOnlyThis(Node: TTreeNode);
 
1763
begin
 
1764
  if Owner<>nil then Owner.LockSelectionChangeEvent;
 
1765
  try
 
1766
    ClearMultiSelection(true);
 
1767
    Node.Selected:=true;
 
1768
  finally
 
1769
    if Owner<>nil then Owner.UnlockSelectionChangeEvent;
 
1770
  end;
1712
1771
end;
1713
1772
 
1714
1773
function TTreeNodes.IsMultiSelection: boolean;
1824
1883
 
1825
1884
procedure TTreeNodes.SortTopLevelNodes(SortProc: TTreeNodeCompare);
1826
1885
begin
1827
 
  Sort(FTopLvlItems, FTopLvlCount, SortProc);
 
1886
  Sort(FTopLvlItems, FTopLvlCount, SortProc, true);
1828
1887
end;
1829
1888
 
1830
1889
function TTreeNodes.InternalAddObject(Node: TTreeNode; const S: string;
1915
1974
    Result:=Result.GetNextSibling;
1916
1975
end;
1917
1976
 
 
1977
function TTreeNodes.FindNodeWithText(const NodeText: string): TTreeNode;
 
1978
begin
 
1979
  Result:=GetFirstNode;
 
1980
  while (Result<>nil) and (Result.Text<>NodeText) do
 
1981
    Result:=Result.GetNext;
 
1982
end;
 
1983
 
 
1984
function TTreeNodes.FindNodeWithData(const NodeData: Pointer): TTreeNode;
 
1985
begin
 
1986
  Result:=GetFirstNode;
 
1987
  while (Result<>nil) and (Result.Data<>NodeData) do
 
1988
    Result:=Result.GetNext;
 
1989
end;
 
1990
 
1918
1991
function TTreeNodes.GetNodeFromIndex(Index: Integer): TTreeNode;
1919
1992
// find node with absolute index in ALL nodes (even collapsed)
 
1993
 
 
1994
  procedure RaiseIndexOutOfBounds;
 
1995
  begin
 
1996
    TreeNodeError('TTreeNodes.GetNodeFromIndex Index '+IntToStr(Index)
 
1997
           +' out of bounds (Count='+IntToStr(FCount)+')');
 
1998
  end;
 
1999
  
 
2000
  procedure RaiseSubTreeCount0;
 
2001
  begin
 
2002
    TreeNodeError(
 
2003
      'TTreeNodes.GetNodeFromIndex: Consistency error - SubTreeCount=0');
 
2004
  end;
 
2005
  
 
2006
  procedure RaiseSubTreeCountTooBig;
 
2007
  begin
 
2008
    TreeNodeError(
 
2009
      'TTreeNodes.GetNodeFromIndex: Consistency error - invalid SubTreeCount');
 
2010
  end;
 
2011
  
 
2012
  procedure RaiseCountTooBig;
 
2013
  begin
 
2014
    TreeNodeError(
 
2015
      'TTreeNodes.GetNodeFromIndex: Consistency Error - Count too big');
 
2016
  end;
 
2017
 
1920
2018
var
1921
2019
  I, J: Integer;
1922
2020
begin
1923
2021
  if (Index < 0) or (Index >= FCount) then
1924
 
    TreeNodeError('TTreeNodes.GetNodeFromIndex Index '+IntToStr(Index)
1925
 
           +' out of bounds (Count='+IntToStr(FCount)+')');
 
2022
    RaiseIndexOutOfBounds;
1926
2023
  if (FNodeCache.CacheNode <> nil) and (Abs(FNodeCache.CacheIndex - Index) <= 1)
1927
2024
  then begin
1928
2025
    with FNodeCache do
1932
2029
      else Result := CacheNode.GetNext;
1933
2030
    end;
1934
2031
  end
 
2032
  else if Index>Count-5 then begin
 
2033
    // optimization for the last nodes
 
2034
    Result:=GetLastSubNode;
 
2035
    i:=Count-1;
 
2036
    while (Index<i) do begin
 
2037
      Result:=Result.GetPrev;
 
2038
      dec(i);
 
2039
    end;
 
2040
  end
1935
2041
  else begin
1936
2042
    Result := GetFirstNode;
1937
2043
    I:=0;
1939
2045
      Repeat
1940
2046
        // calculate the absolute index of the next sibling
1941
2047
        J:=I+Result.FSubTreeCount;
1942
 
        if J=I then
1943
 
          TreeNodeError(
1944
 
            'TTreeNodes.GetNodeFromIndex: Consistency error - SubTreeCount=0');
 
2048
        if J=I then RaiseSubTreeCount0;
1945
2049
        if J<=Index then begin
1946
2050
          // Index > absolute index of next sibling -> search in next sibling
1947
2051
          Result:=Result.GetNextSibling;
1952
2056
      if (Result<>nil) and (Index>I) then begin
1953
2057
        // Index is somewhere in subtree of Result
1954
2058
        Result:=Result.GetFirstChild;
1955
 
        if Result=nil then
1956
 
          TreeNodeError(
1957
 
            'TTreeNodes.GetNodeFromIndex: Consistency error'
1958
 
            +' - invalid SubTreeCount');
 
2059
        if Result=nil then RaiseSubTreeCountTooBig;
1959
2060
        inc(I);
1960
2061
      end;
1961
2062
    end;
1962
2063
  end;
1963
 
  if Result = nil then
1964
 
    TreeNodeError(
1965
 
      'TTreeNodes.GetNodeFromIndex: Consistency Error - Count too big');
 
2064
  if Result = nil then RaiseCountTooBig;
1966
2065
  FNodeCache.CacheNode := Result;
1967
2066
  FNodeCache.CacheIndex := Index;
1968
2067
end;
2055
2154
 
2056
2155
function TTreeNodes.IndexOfTopLvlItem(Node: TTreeNode): integer;
2057
2156
begin
2058
 
  if (FTopLvlItems<>nil) and (FTopLvlItems[0]=Node) then exit(0);
2059
 
  Result:=FTopLvlCount-1;
2060
 
  while (Result>=0) and (FTopLvlItems[Result]<>Node) do dec(Result);
 
2157
  if (Node<>nil) and (Node.Owner=Self) then
 
2158
    Result:=Node.FIndex
 
2159
  else
 
2160
    Result:=-1;
2061
2161
end;
2062
2162
 
2063
2163
procedure TTreeNodes.MoveTopLvlNode(TopLvlFromIndex, TopLvlToIndex: integer;
2081
2181
      // move node
2082
2182
      if TopLvlFromIndex<TopLvlToIndex then begin
2083
2183
        // move forward
2084
 
        for i:=TopLvlFromIndex to TopLvlToIndex-1 do
 
2184
        for i:=TopLvlFromIndex to TopLvlToIndex-1 do begin
2085
2185
          FTopLvlItems[i]:=FTopLvlItems[i+1];
 
2186
          FTopLvlItems[i].FIndex:=i;
 
2187
        end;
2086
2188
      end else begin
2087
2189
        // move backward
2088
 
        for i:=TopLvlToIndex downto TopLvlFromIndex+1 do
 
2190
        for i:=TopLvlToIndex downto TopLvlFromIndex+1 do begin
2089
2191
          FTopLvlItems[i]:=FTopLvlItems[i-1];
 
2192
          FTopLvlItems[i].FIndex:=i;
 
2193
        end;
2090
2194
      end;
2091
2195
      FTopLvlItems[TopLvlToIndex]:=Node;
 
2196
      FTopLvlItems[TopLvlToIndex].FIndex:=TopLvlToIndex;
2092
2197
    end else begin
2093
2198
      // remove node
2094
2199
      if FTopLvlItems<>nil then begin
2095
 
        for i:=TopLvlFromIndex to FTopLvlCount-2 do
 
2200
        for i:=TopLvlFromIndex to FTopLvlCount-2 do begin
2096
2201
          FTopLvlItems[i]:=FTopLvlItems[i+1];
 
2202
          FTopLvlItems[i].FIndex:=i;
 
2203
        end;
2097
2204
      end;
2098
2205
      Dec(FTopLvlCount);
2099
2206
      if FTopLvlCount<0 then
2108
2215
      if (FTopLvlCount=FTopLvlCapacity) then GrowTopLvlItems;
2109
2216
      inc(FTopLvlCount);
2110
2217
      if FTopLvlItems<>nil then begin
2111
 
        for i:=FTopLvlCount-1 downto TopLvlToIndex+1 do
 
2218
        for i:=FTopLvlCount-1 downto TopLvlToIndex+1 do begin
2112
2219
          FTopLvlItems[i]:=FTopLvlItems[i-1];
 
2220
          FTopLvlItems[i].FIndex:=i;
 
2221
        end;
2113
2222
        FTopLvlItems[TopLvlToIndex]:=Node;
 
2223
        FTopLvlItems[TopLvlToIndex].FIndex:=TopLvlToIndex;
2114
2224
      end;
2115
2225
    end else begin
2116
2226
      // nothing to do
2284
2394
  if (FTopLvlCount<0) then
2285
2395
    RaiseGDBException('');
2286
2396
  for i:=0 to FTopLvlCount-1 do begin
2287
 
    if (i=0) and (FTopLvlItems[i].FPrevBrother<>nil) then
2288
 
      RaiseGDBException('');
2289
 
    if (i>0) and (FTopLvlItems[i].FPrevBrother<>FTopLvlItems[i-1]) then
2290
 
      RaiseGDBException('');
2291
 
    if (i<FTopLvlCount-1) and (FTopLvlItems[i].FNextBrother<>FTopLvlItems[i+1])
 
2397
    Node:=FTopLvlItems[i];
 
2398
    if (i=0) and (Node.FPrevBrother<>nil) then
 
2399
      RaiseGDBException('');
 
2400
    if (i>0) and (Node.FPrevBrother<>FTopLvlItems[i-1]) then
 
2401
      RaiseGDBException('');
 
2402
    if (i<FTopLvlCount-1) and (Node.FNextBrother<>FTopLvlItems[i+1])
2292
2403
    then begin
2293
2404
      DebugLn(' CONSISTENCY i=%d FTopLvlCount=%d FTopLvlItems[i]=%p FTopLvlItems[i].FNextBrother=%p FTopLvlItems[i+1]=%p',
2294
 
             [i, FTopLvlCount, Pointer(FTopLvlItems[i]), Pointer(FTopLvlItems[i].FNextBrother), Pointer(FTopLvlItems[i+1])]);
 
2405
             [i, FTopLvlCount, Pointer(Node), Pointer(Node.FNextBrother), Pointer(FTopLvlItems[i+1])]);
2295
2406
      RaiseGDBException('');
2296
2407
    end;
2297
 
    if (i=FTopLvlCount-1) and (FTopLvlItems[i].FNextBrother<>nil) then
 
2408
    if (i=FTopLvlCount-1) and (Node.FNextBrother<>nil) then
 
2409
      RaiseGDBException('');
 
2410
    if Node.FIndex<>i then
2298
2411
      RaiseGDBException('');
2299
2412
  end;
2300
2413
  if FNodeCache.CacheNode<>nil then begin
3076
3189
  if (X>=BorderWidth) and (X<ClientWidth-BorderWidth) then begin
3077
3190
    Result:=GetNodeAtY(Y);
3078
3191
    if Result<>nil then begin
3079
 
      inc(X,FScrolledLeft-BorderWidth);
3080
3192
      if (X<Result.DisplayExpandSignLeft) then
3081
3193
        Result:=nil;
3082
3194
    end;
3172
3284
  then begin
3173
3285
    Node:=GetNodeAtY(Y);
3174
3286
    if Node<>nil then begin
3175
 
      inc(X,FScrolledLeft);
3176
3287
      Include(Result,htOnItem);
3177
3288
      if X<Node.DisplayExpandSignLeft then
3178
3289
        Include(Result,htOnIndent)
3274
3385
begin
3275
3386
  inherited KeyDown(Key, Shift);
3276
3387
 
3277
 
  if tvoAllowMultiSelect in FOptions then 
 
3388
  if (tvoAllowMultiSelect in FOptions) and (ssShift in Shift) then
3278
3389
    lNode := FTreeNodes.FFirstMultiSelected
3279
3390
  else
3280
3391
    lNode := Selected;
3375
3486
      if ([ssCtrl,ssShift] * Shift) <> [] then
3376
3487
        lNode.MultiSelectGroup
3377
3488
      else begin
3378
 
        LockSelectionChangeEvent;
3379
 
        FTreeNodes.ClearMultiSelection;
3380
 
        lNode.MultiSelected := true;
3381
 
        UnlockSelectionChangeEvent;
 
3489
        FTreeNodes.SelectOnlyThis(lNode);
3382
3490
      end;
3383
3491
    end else
3384
3492
      Selected := lNode;
3895
4003
      tvestPlusMinus:
3896
4004
        begin
3897
4005
          // draw a plus or a minus sign
3898
 
          Rectangle(ALeft, ATop, ARight, ABottom);
 
4006
          Rectangle(ALeft, ATop, ARight+1, ABottom+1);
3899
4007
          MoveTo(ALeft+2,MidY);
3900
4008
          LineTo(ARight-2+1,MidY);
3901
4009
          if not CollapseSign then begin
4224
4332
  inherited MouseDown(Button, Shift, X, Y);
4225
4333
 
4226
4334
  CursorNode:=GetNodeAt(X,Y);
4227
 
  LogicalX:=X+FScrolledLeft-BorderWidth;
 
4335
  LogicalX:=X;
4228
4336
  bStartDrag := false;
4229
4337
  if ([ssDouble,ssTriple,ssQuad]*Shift)=[] then begin
4230
4338
    if (Button = mbLeft) and (CursorNode<>nil) then begin
4251
4359
            CursorNode.MultiSelected:=not CursorNode.MultiSelected;
4252
4360
          end else begin
4253
4361
            if (Selected<>CursorNode) or Items.IsMultiSelection then begin
4254
 
              LockSelectionChangeEvent;
4255
 
              Items.ClearMultiSelection;
4256
 
              CursorNode.MultiSelected:=true;
4257
 
              UnlockSelectionChangeEvent;
 
4362
              Items.SelectOnlyThis(CursorNode);
4258
4363
            end;
4259
4364
          end;
4260
4365
        end;
4269
4374
      Include(fStates,tvsWaitForDragging);
4270
4375
    end;
4271
4376
  end else
4272
 
  if (ssDouble in Shift) and (Button = mbLeft) and (CursorNode<>nil) then
 
4377
  if not (tvoNoDoubleClickExpand in Options) and (ssDouble in Shift)
 
4378
     and (Button = mbLeft) and (CursorNode<>nil) then
4273
4379
    CursorNode.Expanded := not CursorNode.Expanded;
4274
4380
end;
4275
4381