15 |
|
* |
16 |
|
* The Initial Developer of the Original Code is Tony Whyman. |
17 |
|
* |
18 |
< |
* The Original Code is (C) 2011 Tony Whyman, MWA Software |
18 |
> |
* The Original Code is (C) 2015 Tony Whyman, MWA Software |
19 |
|
* (http://www.mwasoftware.co.uk). |
20 |
|
* |
21 |
|
* All Rights Reserved. |
31 |
|
|
32 |
|
uses |
33 |
|
Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, ComCtrls, |
34 |
< |
DB, IBSQLParser; |
34 |
> |
DB, IBSQLParser, IBCustomDataSet; |
35 |
|
|
36 |
|
type |
37 |
|
{ |
52 |
|
FOwner: TIBTreeView; |
53 |
|
protected |
54 |
|
procedure ActiveChanged; override; |
55 |
– |
procedure DataEvent(Event: TDataEvent; Info: Ptrint); override; |
55 |
|
procedure DataSetChanged; override; |
56 |
|
procedure RecordChanged(Field: TField); override; |
57 |
|
procedure UpdateData; override; |
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; |
86 |
|
private |
87 |
|
{ Private declarations } |
88 |
|
FDataLink: TIBTreeViewDatalink; |
89 |
+ |
FIBTreeViewControlLink: TIBTreeViewControlLink; |
90 |
|
FHasChildField: string; |
91 |
+ |
FImageIndexField: string; |
92 |
|
FKeyField: string; |
93 |
+ |
FSelectedIndexField: string; |
94 |
|
FTextField: string; |
95 |
|
FParentField: string; |
96 |
|
FExpandNode: TTreeNode; |
108 |
|
function GetDataSource: TDataSource; |
109 |
|
function GetRelationNameQualifier: string; |
110 |
|
function GetSelectedKeyValue: variant; |
111 |
+ |
procedure IBControlLinkChanged; |
112 |
|
procedure NodeMoved(Node: TTreeNode); |
113 |
|
procedure NodeUpdated(Node: TTreeNode); |
114 |
|
procedure RecordChanged(Sender: TObject; Field: TField); |
115 |
|
procedure SetHasChildField(AValue: string); |
116 |
+ |
procedure SetImageIndexField(AValue: string); |
117 |
|
procedure SetKeyField(AValue: string); |
118 |
+ |
procedure SetSelectedIndexField(AValue: string); |
119 |
|
procedure SetTextField(AValue: string); |
120 |
|
procedure SetDataSource(AValue: TDataSource); |
121 |
|
procedure SetParentField(AValue: string); |
139 |
|
{ Public declarations } |
140 |
|
constructor Create(TheComponent: TComponent); override; |
141 |
|
destructor Destroy; override; |
142 |
< |
function FindNode(KeyValuePath: array of variant; SelectNode: boolean): TIBTreeNode; overload; |
142 |
> |
function FindNode(KeyValuePath: TVariantArray; SelectNode: boolean): TIBTreeNode; overload; |
143 |
|
function FindNode(KeyValue: variant): TIBTreeNode; overload; |
144 |
|
function GetNodePath(Node: TTreeNode): TVariantArray; |
145 |
|
property DataSet: TDataSet read GetDataSet; |
171 |
|
property Images; |
172 |
|
property Indent; |
173 |
|
property HasChildField: string read FHasChildField write SetHasChildField; |
174 |
+ |
property ImageIndexField: string read FImageIndexField write SetImageIndexField; |
175 |
+ |
property SelectedIndexField: string read FSelectedIndexField write SetSelectedIndexField; |
176 |
|
property KeyField: string read FKeyField write SetKeyField; |
177 |
|
property MultiSelect; |
178 |
|
property MultiSelectStyle; |
252 |
|
|
253 |
|
implementation |
254 |
|
|
255 |
< |
uses IBQuery,IBCustomDataSet, Variants; |
255 |
> |
uses IBQuery,Variants; |
256 |
|
|
257 |
|
function StrIntListToVar(s: string): TVariantArray; |
258 |
|
var i, idx: integer; |
288 |
|
raise Exception.Create('Ordinal Type Expected when converting to integer string'); |
289 |
|
end; |
290 |
|
|
291 |
+ |
{ TIBTreeViewControlLink } |
292 |
+ |
|
293 |
+ |
constructor TIBTreeViewControlLink.Create(AOwner: TIBTreeView); |
294 |
+ |
begin |
295 |
+ |
inherited Create; |
296 |
+ |
FOwner := AOwner; |
297 |
+ |
end; |
298 |
+ |
|
299 |
+ |
procedure TIBTreeViewControlLink.UpdateParams(Sender: TObject); |
300 |
+ |
begin |
301 |
+ |
FOwner.UpdateParams(self,TIBParserDataSet(Sender).Parser) |
302 |
+ |
end; |
303 |
+ |
|
304 |
+ |
procedure TIBTreeViewControlLink.UpdateSQL(Sender: TObject); |
305 |
+ |
begin |
306 |
+ |
FOwner.UpdateSQL(self,TIBParserDataSet(Sender).Parser) |
307 |
+ |
end; |
308 |
+ |
|
309 |
|
{ TIBTreeNode } |
310 |
|
|
311 |
+ |
constructor TIBTreeNode.Create(AnOwner: TTreeNodes); |
312 |
+ |
begin |
313 |
+ |
inherited Create(AnOwner); |
314 |
+ |
FKeyValue := NULL; |
315 |
+ |
end; |
316 |
+ |
|
317 |
|
procedure TIBTreeNode.DeleteAll; |
318 |
|
var Node, NextNode: TTreeNode; |
319 |
|
begin |
331 |
|
{ TIBTreeView } |
332 |
|
|
333 |
|
procedure TIBTreeView.ActiveChanged(Sender: TObject); |
290 |
– |
var AtTopLevel: boolean; |
334 |
|
begin |
335 |
|
if (csDesigning in ComponentState) then Exit; |
336 |
+ |
IBControlLinkChanged; |
337 |
|
if assigned(DataSet) and not DataSet.Active then |
338 |
|
begin |
339 |
|
if not assigned(FExpandNode) and not assigned(FUpdateNode) then {must really be closing} |
341 |
|
end |
342 |
|
else |
343 |
|
begin |
300 |
– |
AtTopLevel := Items.TopLvlCount = 0; |
344 |
|
AddNodes; |
345 |
|
if not FLocatingNode and (Selected = nil) and (Items.TopLvlCount > 0) then |
346 |
|
begin |
364 |
|
DataSet.First; |
365 |
|
while not DataSet.EOF do |
366 |
|
begin |
367 |
< |
Node := Items.AddChild(FExpandNode,DataSet.FieldByName(TextField).AsString); |
368 |
< |
TIBTreeNode(Node).FKeyValue := DataSet.FieldByName(KeyField).AsVariant; |
369 |
< |
Node.HasChildren := (HasChildField = '') or (DataSet.FieldByName(HasChildField).AsInteger <> 0); |
370 |
< |
Inc(ChildCount); |
367 |
> |
if (FExpandNode = nil) or (TIBTreeNode(FExpandNode).KeyValue <> DataSet.FieldByName(KeyField).AsVariant) then |
368 |
> |
begin |
369 |
> |
Node := Items.AddChild(FExpandNode,DataSet.FieldByName(TextField).AsString); |
370 |
> |
Node.HasChildren := (HasChildField = '') or (DataSet.FieldByName(HasChildField).AsInteger <> 0); |
371 |
> |
Inc(ChildCount); |
372 |
> |
end; |
373 |
|
DataSet.Next |
374 |
|
end; |
375 |
|
finally |
383 |
|
|
384 |
|
procedure TIBTreeView.DataSetChanged(Sender: TObject); |
385 |
|
begin |
386 |
< |
// Reinitialise |
386 |
> |
// Do nothing; |
387 |
|
end; |
388 |
|
|
389 |
|
function TIBTreeView.GetDataSet: TDataSet; |
436 |
|
var Node: TIBTreeNode; |
437 |
|
Destination: TIBTreeNode; |
438 |
|
begin |
439 |
+ |
if DataSet.State = dsInsert then Exit; |
440 |
+ |
|
441 |
|
if assigned(Field) and (Field.FieldName = TextField) then |
442 |
|
begin |
443 |
|
Node := FindNode(DataSet.FieldByName(KeyField).AsVariant); |
452 |
|
end; |
453 |
|
end |
454 |
|
else |
455 |
+ |
if assigned(Field) and (Field.FieldName = ImageIndexField) then |
456 |
+ |
begin |
457 |
+ |
Node := FindNode(DataSet.FieldByName(KeyField).AsVariant); |
458 |
+ |
if assigned(Node) then |
459 |
+ |
begin |
460 |
+ |
FUpdating := true; |
461 |
+ |
try |
462 |
+ |
Node.ImageIndex := Field.AsInteger |
463 |
+ |
finally |
464 |
+ |
FUpdating := false |
465 |
+ |
end; |
466 |
+ |
end; |
467 |
+ |
end |
468 |
+ |
else |
469 |
|
if assigned(Field) and (Field.FieldName = ParentField) then |
470 |
|
begin |
471 |
|
Node := FindNode(DataSet.FieldByName(KeyField).AsVariant); |
476 |
|
else |
477 |
|
Destination := FindNode(DataSet.FieldByName(ParentField).AsVariant); |
478 |
|
|
479 |
< |
if Destination = Node.Parent then Exit; |
479 |
> |
if (Destination = nil) or (Destination = Node.Parent) then Exit; |
480 |
|
|
481 |
|
FUpdating := true; |
482 |
|
try |
495 |
|
Reinitialise |
496 |
|
end; |
497 |
|
|
498 |
+ |
procedure TIBTreeView.SetImageIndexField(AValue: string); |
499 |
+ |
begin |
500 |
+ |
if FImageIndexField = AValue then Exit; |
501 |
+ |
FImageIndexField := AValue; |
502 |
+ |
Reinitialise |
503 |
+ |
end; |
504 |
+ |
|
505 |
|
procedure TIBTreeView.SetKeyField(AValue: string); |
506 |
|
begin |
507 |
|
if FKeyField = AValue then Exit; |
509 |
|
Reinitialise |
510 |
|
end; |
511 |
|
|
512 |
+ |
procedure TIBTreeView.SetSelectedIndexField(AValue: string); |
513 |
+ |
begin |
514 |
+ |
if FSelectedIndexField = AValue then Exit; |
515 |
+ |
FSelectedIndexField := AValue; |
516 |
+ |
Reinitialise; |
517 |
+ |
end; |
518 |
+ |
|
519 |
|
procedure TIBTreeView.SetTextField(AValue: string); |
520 |
|
begin |
521 |
|
if FTextField = AValue then Exit; |
525 |
|
|
526 |
|
procedure TIBTreeView.SetDataSource(AValue: TDataSource); |
527 |
|
begin |
528 |
< |
FDataLink.DataSource := AValue |
528 |
> |
FDataLink.DataSource := AValue; |
529 |
> |
IBControlLinkChanged; |
530 |
|
end; |
531 |
|
|
532 |
|
procedure TIBTreeView.SetParentField(AValue: string); |
542 |
|
if Result then |
543 |
|
begin |
544 |
|
if DataSet.Active and (DataSet.RecordCount > 0) |
545 |
< |
and (Node.KeyValue = DataSet.FieldByName(KeyField).AsVariant) then Exit; |
545 |
> |
and DataSet.Locate(KeyField,Node.KeyValue,[]) then Exit; |
546 |
|
|
547 |
|
FUpdateNode := Node; |
548 |
|
try |
572 |
|
begin |
573 |
|
if not assigned(FExpandNode) and assigned(FUpdateNode) then {Scrolling dataset} |
574 |
|
begin |
575 |
< |
if (Sender as TDataLink).DataSet is TIBQuery then |
576 |
< |
TIBQuery((Sender as TDataLink).DataSet).ParamByName('IBX_KEY_VALUE').Value := |
575 |
> |
if DataSource.DataSet is TIBQuery then |
576 |
> |
TIBQuery(DataSource.DataSet).ParamByName('IBX_KEY_VALUE').Value := |
577 |
|
FUpdateNode.KeyValue |
578 |
|
else |
579 |
< |
if (Sender as TDataLink).DataSet is TIBDataSet then |
580 |
< |
TIBDataSet((Sender as TDataLink).DataSet).ParamByName('IBX_KEY_VALUE').Value := |
579 |
> |
if DataSource.DataSet is TIBDataSet then |
580 |
> |
TIBDataSet(DataSource.DataSet).ParamByName('IBX_KEY_VALUE').Value := |
581 |
|
FUpdateNode.KeyValue |
582 |
|
end |
583 |
|
else |
584 |
|
if assigned(FExpandNode) then |
585 |
|
begin |
586 |
< |
if (Sender as TDataLink).DataSet is TIBQuery then |
587 |
< |
TIBQuery((Sender as TDataLink).DataSet).ParamByName('IBX_PARENT_VALUE').Value := |
586 |
> |
if DataSource.DataSet is TIBQuery then |
587 |
> |
TIBQuery(DataSource.DataSet).ParamByName('IBX_PARENT_VALUE').Value := |
588 |
|
TIBTreeNode(FExpandNode).KeyValue |
589 |
|
else |
590 |
< |
if (Sender as TDataLink).DataSet is TIBDataSet then |
591 |
< |
TIBDataSet((Sender as TDataLink).DataSet).ParamByName('IBX_PARENT_VALUE').Value := |
590 |
> |
if DataSource.DataSet is TIBDataSet then |
591 |
> |
TIBDataSet(DataSource.DataSet).ParamByName('IBX_PARENT_VALUE').Value := |
592 |
|
TIBTreeNode(FExpandNode).KeyValue |
593 |
|
end; |
594 |
|
end; |
603 |
|
Parser.Add2WhereClause(GetRelationNameQualifier + '"' + FParentField + '" is null') |
604 |
|
else |
605 |
|
if assigned(FExpandNode) then |
606 |
+ |
begin |
607 |
|
Parser.Add2WhereClause(GetRelationNameQualifier + '"' + FParentField + '" = :IBX_PARENT_VALUE'); |
608 |
+ |
Parser.Add2WhereClause(GetRelationNameQualifier + '"' + FKeyField + '" = :IBX_PARENT_VALUE',true); |
609 |
+ |
end; |
610 |
|
end; |
611 |
|
|
612 |
|
procedure TIBTreeView.Added(Node: TTreeNode); |
613 |
|
begin |
614 |
< |
if assigned(DataSet) and DataSet.Active and not FNoAddNodeToDataset then |
614 |
> |
if assigned(DataSet) and DataSet.Active then |
615 |
|
begin |
616 |
< |
DataSet.Append; |
616 |
> |
if not FNoAddNodeToDataset then |
617 |
> |
begin |
618 |
> |
DataSet.Append; |
619 |
> |
if (Node.Text = '') and not DataSet.FieldByName(TextField).IsNull then |
620 |
> |
Node.Text := DataSet.FieldByName(TextField).AsString; |
621 |
> |
FModifiedNode := TIBTreeNode(Node); |
622 |
> |
FDataLink.UpdateRecord; |
623 |
> |
end; |
624 |
|
TIBTreeNode(Node).FKeyValue := DataSet.FieldByName(KeyField).AsVariant; |
625 |
< |
if (Node.Text = '') and not DataSet.FieldByName(TextField).IsNull then |
626 |
< |
Node.Text := DataSet.FieldByName(TextField).AsString; |
627 |
< |
FModifiedNode := TIBTreeNode(Node); |
628 |
< |
FDataLink.UpdateRecord |
625 |
> |
if ImageIndexField <> '' then |
626 |
> |
Node.ImageIndex := DataSet.FieldByName(ImageIndexField).AsInteger; |
627 |
> |
if SelectedIndexField <> '' then |
628 |
> |
Node.SelectedIndex := DataSet.FieldByName(SelectedIndexField).AsInteger; |
629 |
|
end; |
630 |
|
inherited Added(Node); |
631 |
|
end; |
675 |
|
FExpandNode := Node; |
676 |
|
DataSet.Active := false; |
677 |
|
DataSet.Active := true; |
678 |
< |
if assigned(Selected) then |
593 |
< |
ScrollToNode(TIBTreeNode(Selected)) |
678 |
> |
Selected := Node; |
679 |
|
end; |
680 |
|
end; |
681 |
|
|
682 |
+ |
procedure TIBTreeView.IBControlLinkChanged; |
683 |
+ |
begin |
684 |
+ |
if assigned(DataSource) and (DataSource.DataSet <> nil) and (DataSource.DataSet is TIBParserDataset) then |
685 |
+ |
FIBTreeViewControllink.IBDataSet := TIBCustomDataSet(DataSource.DataSet) |
686 |
+ |
else |
687 |
+ |
FIBTreeViewControllink.IBDataSet := nil; |
688 |
+ |
end; |
689 |
+ |
|
690 |
|
procedure TIBTreeView.Loaded; |
691 |
|
begin |
692 |
|
inherited Loaded; |
693 |
+ |
IBControlLinkChanged; |
694 |
|
Reinitialise |
695 |
|
end; |
696 |
|
|
712 |
|
begin |
713 |
|
inherited Notification(AComponent, Operation); |
714 |
|
if (Operation = opRemove) and |
715 |
< |
(FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil; |
715 |
> |
(FDataLink <> nil) and (AComponent = DataSource) then |
716 |
> |
DataSource := nil; |
717 |
|
end; |
718 |
|
|
719 |
|
procedure TIBTreeView.Reinitialise; |
727 |
|
begin |
728 |
|
inherited Create(TheComponent); |
729 |
|
FDataLink := TIBTreeViewDatalink.Create(self); |
730 |
+ |
FIBTreeViewControlLink := TIBTreeViewControlLink.Create(self); |
731 |
|
end; |
732 |
|
|
733 |
|
destructor TIBTreeView.Destroy; |
734 |
|
begin |
735 |
|
if assigned(FDataLink) then FDataLink.Free; |
736 |
+ |
if assigned(FIBTreeViewControlLink) then FIBTreeViewControlLink.Free; |
737 |
|
inherited Destroy; |
738 |
|
end; |
739 |
|
|
740 |
< |
function TIBTreeView.FindNode(KeyValuePath: array of variant; |
741 |
< |
SelectNode: boolean): TIBTreeNode; |
740 |
> |
function TIBTreeView.FindNode(KeyValuePath: TVariantArray; SelectNode: boolean |
741 |
> |
): TIBTreeNode; |
742 |
|
var Node: TTreeNode; |
743 |
|
i,j: integer; |
744 |
|
begin |
745 |
|
Result := nil; |
746 |
+ |
if Length(KeyValuePath) = 0 then Exit; |
747 |
+ |
|
748 |
|
FLocatingNode := true; |
749 |
|
try |
750 |
|
for j := 0 to Items.TopLvlCount - 1 do |
754 |
|
Node.Expand(false); |
755 |
|
while assigned(Node) do |
756 |
|
begin |
757 |
< |
if TIBTreeNode(Node).KeyValue = KeyValuePath[i] then |
757 |
> |
if not VarIsNull(TIBTreeNode(Node).KeyValue) and |
758 |
> |
(TIBTreeNode(Node).KeyValue = KeyValuePath[i]) then |
759 |
|
begin |
760 |
|
Inc(i); |
761 |
|
if i = Length(KeyValuePath) then |
833 |
|
FOwner.ActiveChanged(self) |
834 |
|
end; |
835 |
|
|
736 |
– |
procedure TIBTreeViewDatalink.DataEvent(Event: TDataEvent; Info: Ptrint); |
737 |
– |
begin |
738 |
– |
if (Event = deCheckBrowseMode) and (Info = 1) and not DataSet.Active then |
739 |
– |
begin |
740 |
– |
if (DataSet is TIBDataSet) then |
741 |
– |
FOwner.UpdateSQL(self,TIBDataSet(DataSet).Parser) |
742 |
– |
else |
743 |
– |
if (DataSet is TIBQuery) then |
744 |
– |
FOwner.UpdateSQL(self,TIBQuery(DataSet).Parser) |
745 |
– |
end |
746 |
– |
else |
747 |
– |
if (Event = deCheckBrowseMode) and (Info = 2) and not DataSet.Active then |
748 |
– |
begin |
749 |
– |
if (DataSet is TIBDataSet) then |
750 |
– |
FOwner.UpdateParams(self,TIBDataSet(DataSet).Parser) |
751 |
– |
else |
752 |
– |
if (DataSet is TIBQuery) then |
753 |
– |
FOwner.UpdateParams(self,TIBQuery(DataSet).Parser) |
754 |
– |
end |
755 |
– |
else |
756 |
– |
inherited DataEvent(Event, Info); |
757 |
– |
end; |
758 |
– |
|
836 |
|
procedure TIBTreeViewDatalink.DataSetChanged; |
837 |
|
begin |
838 |
|
FOwner.DataSetChanged(self) |