ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/ibcontrols/IBTreeView.pas
Revision: 80
Committed: Mon Jan 1 11:31:07 2018 UTC (6 years, 11 months ago) by tony
Content type: text/x-pascal
File size: 21771 byte(s)
Log Message:
Fixes merged into public release

File Contents

# Content
1 (*
2 * IBX For Lazarus (Firebird Express)
3 *
4 * The contents of this file are subject to the Initial Developer's
5 * Public License Version 1.0 (the "License"); you may not use this
6 * file except in compliance with the License. You may obtain a copy
7 * of the License here:
8 *
9 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
10 *
11 * Software distributed under the License is distributed on an "AS
12 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
13 * implied. See the License for the specific language governing rights
14 * and limitations under the License.
15 *
16 * The Initial Developer of the Original Code is Tony Whyman.
17 *
18 * The Original Code is (C) 2015 Tony Whyman, MWA Software
19 * (http://www.mwasoftware.co.uk).
20 *
21 * All Rights Reserved.
22 *
23 * Contributor(s): ______________________________________.
24 *
25 *)
26 unit IBTreeView;
27
28 {$mode objfpc}{$H+}
29
30 interface
31
32 uses
33 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ComCtrls,
34 DB, IBSQLParser, IBCustomDataSet;
35
36 type
37 {
38 TIBTreeView is intended to be a data aware descendent of TCustomTreeView and used to display
39 hierarchically structured data in a natural manner. Nodes can be deleted, moved
40 and added to the tree and each change is reflected in the underlying dataset. The
41 Node text can similarly be edited.
42 }
43
44 TVariantArray = array of variant;
45
46 TIBTreeView = class;
47
48 { TIBTreeViewDatalink }
49
50 TIBTreeViewDatalink = class(TDataLink)
51 private
52 FOwner: TIBTreeView;
53 protected
54 procedure ActiveChanged; override;
55 procedure DataSetChanged; override;
56 procedure RecordChanged(Field: TField); override;
57 procedure UpdateData; override;
58 public
59 constructor Create(AOwner: TIBTreeView);
60 end;
61
62 { TIBTreeViewControlLink }
63
64 TIBTreeViewControlLink = class(TIBControlLink)
65 private
66 FOwner: TIBTreeView;
67 protected
68 procedure UpdateSQL(Sender: TObject); override;
69 procedure UpdateParams(Sender: TObject); override;
70 public
71 constructor Create(AOwner: TIBTreeView);
72 end;
73
74 { TIBTreeNode }
75
76 TIBTreeNode = class(TTreeNode)
77 private
78 FKeyValue: variant;
79 public
80 constructor Create(AnOwner: TTreeNodes); override;
81 procedure DeleteAll;
82 property KeyValue: variant read FKeyValue;
83 end;
84
85 TIBTreeView = class(TCustomTreeView)
86 private
87 { Private declarations }
88 FDataLink: TIBTreeViewDatalink;
89 FIBTreeViewControlLink: TIBTreeViewControlLink;
90 FHasChildField: string;
91 FKeyField: string;
92 FTextField: string;
93 FParentField: string;
94 FExpandNode: TTreeNode;
95 FNoAddNodeToDataset: boolean;
96 FRelationName: string;
97 FUpdateNode: TIBTreeNode;
98 FModifiedNode: TIBTreeNode;
99 FUpdating: boolean;
100 FLocatingNode: boolean;
101 FLastSelected: TVariantArray;
102 procedure ActiveChanged(Sender: TObject);
103 procedure AddNodes;
104 procedure DataSetChanged(Sender: TObject);
105 function GetDataSet: TDataSet;
106 function GetDataSource: TDataSource;
107 function GetRelationNameQualifier: string;
108 function GetSelectedKeyValue: variant;
109 procedure IBControlLinkChanged;
110 procedure NodeMoved(Node: TTreeNode);
111 procedure NodeUpdated(Node: TTreeNode);
112 procedure RecordChanged(Sender: TObject; Field: TField);
113 procedure SetHasChildField(AValue: string);
114 procedure SetKeyField(AValue: string);
115 procedure SetTextField(AValue: string);
116 procedure SetDataSource(AValue: TDataSource);
117 procedure SetParentField(AValue: string);
118 function ScrollToNode(Node: TIBTreeNode): boolean;
119 procedure UpdateData(Sender: TObject);
120 procedure UpdateParams(Sender: TObject; Parser: TSelectSQLParser);
121 procedure UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
122 protected
123 { Protected declarations }
124 procedure Added(Node: TTreeNode); override;
125 procedure Delete(Node: TTreeNode); override;
126 procedure Change(Node: TTreeNode); override;
127 function CreateNode: TTreeNode; override;
128 function CanEdit(Node: TTreeNode): Boolean; override;
129 procedure Expand(Node: TTreeNode); override;
130 procedure Loaded; override;
131 procedure NodeChanged(Node: TTreeNode; ChangeEvent: TTreeNodeChangeReason); override;
132 procedure Notification(AComponent: TComponent; Operation: TOperation); override;
133 procedure Reinitialise;
134 public
135 { Public declarations }
136 constructor Create(TheComponent: TComponent); override;
137 destructor Destroy; override;
138 function FindNode(KeyValuePath: TVariantArray; SelectNode: boolean): TIBTreeNode; overload;
139 function FindNode(KeyValue: variant): TIBTreeNode; overload;
140 function GetNodePath(Node: TTreeNode): TVariantArray;
141 property DataSet: TDataSet read GetDataSet;
142 property SelectedKeyValue: variant read GetSelectedKeyValue;
143 published
144 { Published declarations }
145 property Align;
146 property Anchors;
147 property AutoExpand;
148 property BorderSpacing;
149 //property BiDiMode;
150 property BackgroundColor;
151 property BorderStyle;
152 property BorderWidth;
153 property Color;
154 property Constraints;
155 property TextField: string read FTextField write SetTextField;
156 property DataSource: TDataSource read GetDataSource write SetDataSource;
157 property DefaultItemHeight;
158 property DragKind;
159 property DragCursor;
160 property DragMode;
161 property Enabled;
162 property ExpandSignColor;
163 property ExpandSignType;
164 property Font;
165 property HideSelection;
166 property HotTrack;
167 property Images;
168 property Indent;
169 property HasChildField: string read FHasChildField write SetHasChildField;
170 property KeyField: string read FKeyField write SetKeyField;
171 property MultiSelect;
172 property MultiSelectStyle;
173 //property ParentBiDiMode;
174 property ParentColor default False;
175 property ParentField: string read FParentField write SetParentField;
176 property ParentFont;
177 property ParentShowHint;
178 property PopupMenu;
179 property ReadOnly;
180 property RelationName: string read FRelationName write FRelationName;
181 property RightClickSelect;
182 property RowSelect;
183 property ScrollBars;
184 property SelectionColor;
185 property ShowButtons;
186 property ShowHint;
187 property ShowLines;
188 property ShowRoot;
189 property StateImages;
190 property TabOrder;
191 property TabStop default True;
192 property Tag;
193 property ToolTips;
194 property Visible;
195 property OnAddition;
196 property OnAdvancedCustomDraw;
197 property OnAdvancedCustomDrawItem;
198 property OnChange;
199 property OnChanging;
200 property OnClick;
201 property OnCollapsed;
202 property OnCollapsing;
203 property OnCompare;
204 property OnContextPopup;
205 property OnCreateNodeClass;
206 property OnCustomCreateItem;
207 property OnCustomDraw;
208 property OnCustomDrawItem;
209 property OnDblClick;
210 property OnDeletion;
211 property OnDragDrop;
212 property OnDragOver;
213 property OnEdited;
214 property OnEditing;
215 property OnEditingEnd;
216 //property OnEndDock;
217 property OnEndDrag;
218 property OnEnter;
219 property OnExit;
220 property OnExpanded;
221 property OnExpanding;
222 property OnGetImageIndex;
223 property OnGetSelectedIndex;
224 property OnKeyDown;
225 property OnKeyPress;
226 property OnKeyUp;
227 property OnMouseDown;
228 property OnMouseEnter;
229 property OnMouseLeave;
230 property OnMouseMove;
231 property OnMouseUp;
232 property OnNodeChanged;
233 property OnSelectionChanged;
234 property OnShowHint;
235 //property OnStartDock;
236 property OnStartDrag;
237 property OnUTF8KeyPress;
238 property Options;
239 property Items;
240 property TreeLineColor;
241 property TreeLinePenStyle;
242 end;
243
244 function StrIntListToVar(s: string): TVariantArray;
245 function VarToStrIntList(a: TVariantArray): string;
246
247 implementation
248
249 uses IBQuery,Variants;
250
251 function StrIntListToVar(s: string): TVariantArray;
252 var i, idx: integer;
253 List: TStringList;
254 begin
255 List := TStringList.Create;
256 try
257 idx := 1;
258 List.Clear;
259 while idx <= Length(s) do
260 List.Add(ExtractFieldName(s,idx));
261
262 Setlength(Result,List.Count);
263 for i := 0 to List.Count - 1 do
264 Result[i] := StrToInt(List[i])
265 finally
266 List.Free
267 end;
268 end;
269
270 function VarToStrIntList(a: TVariantArray): string;
271 var i: integer;
272 begin
273 for i := 0 to Length(a) - 1 do
274 if VarIsOrdinal(a[i]) then
275 begin
276 if i = 0 then
277 Result := IntToStr(a[i])
278 else
279 Result := Result + ';' + IntToStr(a[i])
280 end
281 else
282 raise Exception.Create('Ordinal Type Expected when converting to integer string');
283 end;
284
285 { TIBTreeViewControlLink }
286
287 constructor TIBTreeViewControlLink.Create(AOwner: TIBTreeView);
288 begin
289 inherited Create;
290 FOwner := AOwner;
291 end;
292
293 procedure TIBTreeViewControlLink.UpdateParams(Sender: TObject);
294 begin
295 FOwner.UpdateParams(self,TIBParserDataSet(Sender).Parser)
296 end;
297
298 procedure TIBTreeViewControlLink.UpdateSQL(Sender: TObject);
299 begin
300 FOwner.UpdateSQL(self,TIBParserDataSet(Sender).Parser)
301 end;
302
303 { TIBTreeNode }
304
305 constructor TIBTreeNode.Create(AnOwner: TTreeNodes);
306 begin
307 inherited Create(AnOwner);
308 FKeyValue := NULL;
309 end;
310
311 procedure TIBTreeNode.DeleteAll;
312 var Node, NextNode: TTreeNode;
313 begin
314 Expand(true);
315 Node := GetFirstChild;
316 while Node <> nil do
317 begin
318 NextNode := Node.GetNextSibling;
319 TIBTreeNode(Node).DeleteAll;
320 Node := NextNode;
321 end;
322 Delete
323 end;
324
325 { TIBTreeView }
326
327 procedure TIBTreeView.ActiveChanged(Sender: TObject);
328 var AtTopLevel: boolean;
329 begin
330 if (csDesigning in ComponentState) then Exit;
331 IBControlLinkChanged;
332 if assigned(DataSet) and not DataSet.Active then
333 begin
334 if not assigned(FExpandNode) and not assigned(FUpdateNode) then {must really be closing}
335 Reinitialise
336 end
337 else
338 begin
339 AtTopLevel := Items.TopLvlCount = 0;
340 AddNodes;
341 if not FLocatingNode and (Selected = nil) and (Items.TopLvlCount > 0) then
342 begin
343 if Length(FLastSelected) > 0 then
344 Selected := FindNode(FLastSelected,true)
345 else
346 Selected := Items.TopLvlItems[0];
347 end
348 end
349 end;
350
351 procedure TIBTreeView.AddNodes;
352 var Node: TTreeNode;
353 ChildCount: integer;
354 begin
355 if assigned(FExpandNode) or (Items.Count = 0) then
356 begin
357 ChildCount := 0;
358 FNoAddNodeToDataset := true;
359 try
360 DataSet.First;
361 while not DataSet.EOF do
362 begin
363 Node := Items.AddChild(FExpandNode,DataSet.FieldByName(TextField).AsString);
364 TIBTreeNode(Node).FKeyValue := DataSet.FieldByName(KeyField).AsVariant;
365 Node.HasChildren := (HasChildField = '') or (DataSet.FieldByName(HasChildField).AsInteger <> 0);
366 Inc(ChildCount);
367 DataSet.Next
368 end;
369 finally
370 FNoAddNodeToDataset := false
371 end;
372 if assigned(FExpandNode) then
373 FExpandNode.HasChildren := ChildCount > 0;
374 FExpandNode := nil
375 end
376 end;
377
378 procedure TIBTreeView.DataSetChanged(Sender: TObject);
379 begin
380 // Reinitialise
381 end;
382
383 function TIBTreeView.GetDataSet: TDataSet;
384 begin
385 Result := FDataLink.DataSet
386 end;
387
388 function TIBTreeView.GetDataSource: TDataSource;
389 begin
390 Result := FDataLink.DataSource
391 end;
392
393 function TIBTreeView.GetRelationNameQualifier: string;
394 begin
395 if FRelationName <> '' then
396 Result := FRelationName + '.'
397 else
398 Result := ''
399 end;
400
401 function TIBTreeView.GetSelectedKeyValue: variant;
402 begin
403 Result := NULL;
404 if assigned(Selected) and (Selected is TIBTreeNode) then
405 Result := TIBTreeNode(Selected).KeyValue
406 end;
407
408 procedure TIBTreeView.NodeMoved(Node: TTreeNode);
409 begin
410 {Need to update Parent}
411 if ScrollToNode(TIBTreeNode(Node)) then
412 begin
413 FDataLink.Edit;
414 FModifiedNode := TIBTreeNode(Node)
415 end;
416 end;
417
418 procedure TIBTreeView.NodeUpdated(Node: TTreeNode);
419 begin
420 {Need to Update List Field}
421 if ScrollToNode(TIBTreeNode(Node)) then
422 begin
423 FDataLink.Edit;
424 FModifiedNode := TIBTreeNode(Node);
425 FDataLink.UpdateRecord
426 end;
427 end;
428
429 procedure TIBTreeView.RecordChanged(Sender: TObject; Field: TField);
430 var Node: TIBTreeNode;
431 Destination: TIBTreeNode;
432 begin
433 if DataSet.State = dsInsert then Exit;
434
435 if assigned(Field) and (Field.FieldName = TextField) then
436 begin
437 Node := FindNode(DataSet.FieldByName(KeyField).AsVariant);
438 if assigned(Node) then
439 begin
440 FUpdating := true;
441 try
442 Node.Text := Field.Text
443 finally
444 FUpdating := false
445 end;
446 end;
447 end
448 else
449 if assigned(Field) and (Field.FieldName = ParentField) then
450 begin
451 Node := FindNode(DataSet.FieldByName(KeyField).AsVariant);
452 if assigned(Node) then
453 begin
454 if DataSet.FieldByName(ParentField).IsNull then
455 Destination := nil
456 else
457 Destination := FindNode(DataSet.FieldByName(ParentField).AsVariant);
458
459 if (Destination = nil) or (Destination = Node.Parent) then Exit;
460
461 FUpdating := true;
462 try
463 Node.MoveTo(Destination,naAddChild);
464 finally
465 FUpdating := false
466 end;
467 end;
468 end
469 end;
470
471 procedure TIBTreeView.SetHasChildField(AValue: string);
472 begin
473 if FHasChildField = AValue then Exit;
474 FHasChildField := AValue;
475 Reinitialise
476 end;
477
478 procedure TIBTreeView.SetKeyField(AValue: string);
479 begin
480 if FKeyField = AValue then Exit;
481 FKeyField := AValue;
482 Reinitialise
483 end;
484
485 procedure TIBTreeView.SetTextField(AValue: string);
486 begin
487 if FTextField = AValue then Exit;
488 FTextField := AValue;
489 Reinitialise
490 end;
491
492 procedure TIBTreeView.SetDataSource(AValue: TDataSource);
493 begin
494 FDataLink.DataSource := AValue;
495 IBControlLinkChanged;
496 end;
497
498 procedure TIBTreeView.SetParentField(AValue: string);
499 begin
500 if FParentField = AValue then Exit;
501 FParentField := AValue;
502 Reinitialise
503 end;
504
505 function TIBTreeView.ScrollToNode(Node: TIBTreeNode): boolean;
506 begin
507 Result := assigned(DataSet) and DataSet.Active and assigned(Node) and not varIsNull(Node.KeyValue);
508 if Result then
509 begin
510 if DataSet.Active and (DataSet.RecordCount > 0)
511 and DataSet.Locate(KeyField,Node.KeyValue,[]) then Exit;
512
513 FUpdateNode := Node;
514 try
515 DataSet.Active := false;
516 DataSet.Active := true;
517 finally
518 FUpdateNode := nil
519 end;
520 Result := DataSet.FieldByName(KeyField).AsVariant = Node.KeyValue
521 end;
522 end;
523
524 procedure TIBTreeView.UpdateData(Sender: TObject);
525 begin
526 if assigned(FModifiedNode) then
527 begin
528 DataSet.FieldByName(TextField).AsString := FModifiedNode.Text;
529 if FModifiedNode.Parent = nil then
530 DataSet.FieldByName(ParentField).Clear
531 else
532 DataSet.FieldByName(ParentField).AsVariant := TIBTreeNode(FModifiedNode.Parent).KeyValue;
533 FModifiedNode := nil
534 end
535 end;
536
537 procedure TIBTreeView.UpdateParams(Sender: TObject; Parser: TSelectSQLParser);
538 begin
539 if not assigned(FExpandNode) and assigned(FUpdateNode) then {Scrolling dataset}
540 begin
541 if DataSource.DataSet is TIBQuery then
542 TIBQuery(DataSource.DataSet).ParamByName('IBX_KEY_VALUE').Value :=
543 FUpdateNode.KeyValue
544 else
545 if DataSource.DataSet is TIBDataSet then
546 TIBDataSet(DataSource.DataSet).ParamByName('IBX_KEY_VALUE').Value :=
547 FUpdateNode.KeyValue
548 end
549 else
550 if assigned(FExpandNode) then
551 begin
552 if DataSource.DataSet is TIBQuery then
553 TIBQuery(DataSource.DataSet).ParamByName('IBX_PARENT_VALUE').Value :=
554 TIBTreeNode(FExpandNode).KeyValue
555 else
556 if DataSource.DataSet is TIBDataSet then
557 TIBDataSet(DataSource.DataSet).ParamByName('IBX_PARENT_VALUE').Value :=
558 TIBTreeNode(FExpandNode).KeyValue
559 end;
560 end;
561
562 procedure TIBTreeView.UpdateSQL(Sender: TObject; Parser: TSelectSQLParser);
563 begin
564 if not assigned(FExpandNode) and assigned(FUpdateNode) then {Scrolling dataset}
565 Parser.Add2WhereClause(GetRelationNameQualifier + '"' + FKeyField + '" = :IBX_KEY_VALUE')
566 else
567 if (Items.Count = 0) then
568 {Need to Load Root Nodes}
569 Parser.Add2WhereClause(GetRelationNameQualifier + '"' + FParentField + '" is null')
570 else
571 if assigned(FExpandNode) then
572 Parser.Add2WhereClause(GetRelationNameQualifier + '"' + FParentField + '" = :IBX_PARENT_VALUE');
573 end;
574
575 procedure TIBTreeView.Added(Node: TTreeNode);
576 begin
577 if assigned(DataSet) and DataSet.Active and not FNoAddNodeToDataset then
578 begin
579 DataSet.Append;
580 TIBTreeNode(Node).FKeyValue := DataSet.FieldByName(KeyField).AsVariant;
581 if (Node.Text = '') and not DataSet.FieldByName(TextField).IsNull then
582 Node.Text := DataSet.FieldByName(TextField).AsString;
583 FModifiedNode := TIBTreeNode(Node);
584 FDataLink.UpdateRecord
585 end;
586 inherited Added(Node);
587 end;
588
589 procedure TIBTreeView.Delete(Node: TTreeNode);
590 begin
591 if not (tvsUpdating in States) {TreeNodes being cleared}
592 and not (tvsManualNotify in States) {Tree Collapse with node delete}
593 and ScrollToNode(TIBTreeNode(Node)) then
594 DataSet.Delete;
595 inherited Delete(Node);
596 end;
597
598 procedure TIBTreeView.Change(Node: TTreeNode);
599 begin
600 inherited Change(Node);
601 ScrollToNode(TIBTreeNode(Node));
602 end;
603
604 function TIBTreeView.CreateNode: TTreeNode;
605 var
606 NewNodeClass: TTreeNodeClass;
607 begin
608 Result := nil;
609 if Assigned(OnCustomCreateItem) then
610 OnCustomCreateItem(Self, Result);
611 if Result = nil then
612 begin
613 NewNodeClass:=TIBTreeNode;
614 if Assigned(OnCreateNodeClass) then
615 OnCreateNodeClass(Self,NewNodeClass);
616 Result := NewNodeClass.Create(Items);
617 end;
618 end;
619
620 function TIBTreeView.CanEdit(Node: TTreeNode): Boolean;
621 begin
622 Result := inherited CanEdit(Node)
623 and assigned(DataSet) and not DataSet.FieldByName(TextField).ReadOnly
624 end;
625
626 procedure TIBTreeView.Expand(Node: TTreeNode);
627 begin
628 inherited Expand(Node);
629 if Node.HasChildren and assigned(DataSet) and (Node.GetFirstChild = nil) then
630 begin
631 FExpandNode := Node;
632 DataSet.Active := false;
633 DataSet.Active := true;
634 if assigned(Selected) then
635 ScrollToNode(TIBTreeNode(Selected))
636 end;
637 end;
638
639 procedure TIBTreeView.IBControlLinkChanged;
640 begin
641 if assigned(DataSource) and (DataSource.DataSet <> nil) and (DataSource.DataSet is TIBParserDataset) then
642 FIBTreeViewControllink.IBDataSet := TIBCustomDataSet(DataSource.DataSet)
643 else
644 FIBTreeViewControllink.IBDataSet := nil;
645 end;
646
647 procedure TIBTreeView.Loaded;
648 begin
649 inherited Loaded;
650 IBControlLinkChanged;
651 Reinitialise
652 end;
653
654 procedure TIBTreeView.NodeChanged(Node: TTreeNode;
655 ChangeEvent: TTreeNodeChangeReason);
656 begin
657 inherited NodeChanged(Node, ChangeEvent);
658 if not FNoAddNodeToDataset and not FUpdating then
659 case ChangeEvent of
660 ncTextChanged:
661 NodeUpdated(Node);
662 ncParentChanged:
663 NodeMoved(Node);
664 end;
665 end;
666
667 procedure TIBTreeView.Notification(AComponent: TComponent; Operation: TOperation
668 );
669 begin
670 inherited Notification(AComponent, Operation);
671 if (Operation = opRemove) and
672 (FDataLink <> nil) and (AComponent = DataSource) then
673 DataSource := nil;
674 end;
675
676 procedure TIBTreeView.Reinitialise;
677 begin
678 if [csDesigning,csLoading] * ComponentState <> [] then Exit;
679 FLastSelected := GetNodePath(Selected);
680 Items.Clear;
681 end;
682
683 constructor TIBTreeView.Create(TheComponent: TComponent);
684 begin
685 inherited Create(TheComponent);
686 FDataLink := TIBTreeViewDatalink.Create(self);
687 FIBTreeViewControlLink := TIBTreeViewControlLink.Create(self);
688 end;
689
690 destructor TIBTreeView.Destroy;
691 begin
692 if assigned(FDataLink) then FDataLink.Free;
693 if assigned(FIBTreeViewControlLink) then FIBTreeViewControlLink.Free;
694 inherited Destroy;
695 end;
696
697 function TIBTreeView.FindNode(KeyValuePath: TVariantArray; SelectNode: boolean
698 ): TIBTreeNode;
699 var Node: TTreeNode;
700 i,j: integer;
701 begin
702 Result := nil;
703 if Length(KeyValuePath) = 0 then Exit;
704
705 FLocatingNode := true;
706 try
707 for j := 0 to Items.TopLvlCount - 1 do
708 begin
709 Node := Items.TopLvlItems[j];
710 i := 0;
711 Node.Expand(false);
712 while assigned(Node) do
713 begin
714 if not VarIsNull(TIBTreeNode(Node).KeyValue) and
715 (TIBTreeNode(Node).KeyValue = KeyValuePath[i]) then
716 begin
717 Inc(i);
718 if i = Length(KeyValuePath) then
719 begin
720 Result := TIBTreeNode(Node);
721 if SelectNode then
722 Selected := Node;
723 Exit
724 end
725 else
726 begin
727 Node.Expand(false);
728 Node := Node.GetFirstChild;
729 end
730 end
731 else
732 Node := Node.GetNextSibling
733 end
734 end
735 finally
736 FLocatingNode := false
737 end
738 end;
739
740 function TIBTreeView.FindNode(KeyValue: variant): TIBTreeNode;
741 var i: integer;
742 begin
743 Result := nil;
744 if (Selected <> nil) and (TIBTreeNode(Selected).KeyValue = KeyValue) then
745 Result := TIBTreeNode(Selected)
746 else
747 {Find it the hard way}
748 begin
749 FullExpand;
750 for i := 0 to Items.Count -1 do
751 if TIBTreeNode(Items[i]).KeyValue = KeyValue then
752 begin
753 Result := TIBTreeNode(Items[i])
754 end;
755 end;
756 end;
757
758 function TIBTreeView.GetNodePath(Node: TTreeNode): TVariantArray;
759 var aParent: TTreeNode;
760 i: integer;
761 begin
762 if not assigned(Node) or not (Node is TIBTreeNode) then
763 SetLength(Result,0)
764 else
765 begin
766 {Count length of Path}
767 i := 1;
768 aParent := Node.Parent;
769 while (aParent <> nil) do
770 begin
771 Inc(i);
772 aParent := aParent.Parent
773 end;
774
775 {Save Path}
776 Setlength(Result,i);
777 while i > 0 do
778 begin
779 Dec(i);
780 Result[i] := TIBTreeNode(Node).KeyValue;
781 Node := Node.Parent
782 end;
783 end;
784 end;
785
786 { TIBTreeViewDatalink }
787
788 procedure TIBTreeViewDatalink.ActiveChanged;
789 begin
790 FOwner.ActiveChanged(self)
791 end;
792
793 procedure TIBTreeViewDatalink.DataSetChanged;
794 begin
795 FOwner.DataSetChanged(self)
796 end;
797
798 procedure TIBTreeViewDatalink.RecordChanged(Field: TField);
799 begin
800 FOwner.RecordChanged(self,Field);
801 end;
802
803 procedure TIBTreeViewDatalink.UpdateData;
804 begin
805 FOwner.UpdateData(self)
806 end;
807
808 constructor TIBTreeViewDatalink.Create(AOwner: TIBTreeView);
809 begin
810 inherited Create;
811 FOwner := AOwner
812 end;
813
814 end.