unit uutlGraph; { Package: Utils Prefix: utl - UTiLs Beschreibung: diese Unit implementiert einen generischen Graphen } {$mode objfpc}{$H+} interface uses Classes, SysUtils, contnrs, uutlCommon; type TutlGraph = class; TutlGraphNodeData = class(TObject) public constructor Create; virtual; end; TutlGraphNodeDataClass = class of TutlGraphNodeData; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlGraphNode = class; TutlGraphNodeClass = class of TutlGraphNode; TutlGraphNode = class(TutlInterfaceNoRefCount) private type TNodeEnumerator = class(TObject) private fOwner: TutlGraphNode; fPos: Integer; function GetCurrent: TutlGraphNode; public property Current: TutlGraphNode read GetCurrent; function MoveNext: Boolean; constructor Create(const aOwner: TutlGraphNode); end; protected fParent: TutlGraphNode; fOwner: TutlGraph; fData: TutlGraphNodeData; fItems: TObjectList; class function GetDataClass: TutlGraphNodeDataClass; virtual; function GetCount: Integer; virtual; function GetItems(const aIndex: Integer): TutlGraphNode; virtual; function AttachNode(const aNode: TutlGraphNode): Boolean; virtual; function DetachNode(const aNode: TutlGraphNode): Boolean; virtual; public property Parent: TutlGraphNode read fParent; property Owner: TutlGraph read fOwner; property Data: TutlGraphNodeData read fData; property Count: Integer read GetCount; property Items[const aIndex: Integer]: TutlGraphNode read GetItems; default; function AddItem: TutlGraphNode; function IndexOf(const aItem: TutlGraphNode): Integer; procedure DelItem(const aIndex: Integer); procedure Clear; function IsParent(const aNode: TutlGraphNode): Boolean; function Move(const aParent: TutlGraphNode): Boolean; function GetEnumerator: TNodeEnumerator; constructor Create(const aParent: TutlGraphNode; const aOwner: TutlGraph); destructor Destroy; override; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlGraph = class(TutlInterfaceNoRefCount) protected fRootNode: TutlGraphNode; class function GetItemClass: TutlGraphNodeClass; virtual; public property RootNode: TutlGraphNode read fRootNode; constructor Create; destructor Destroy; override; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// generic TutlGenericGraphNode = class(TutlGraphNode) private type TGenericNodeEnumerator = class(TObject) private fOwner: TutlGraphNode; fPos: Integer; function GetCurrent: GNode; public property Current: GNode read GetCurrent; function MoveNext: Boolean; constructor Create(const aOwner: TutlGraphNode); end; private function GetParent: GNode; function GetOwner: GOwner; function GetData: GData; function GetItemsGeneric(const aIndex: Integer): GNode; public property Parent: GNode read GetParent; property Owner: GOwner read GetOwner; property Data: GData read GetData; property Items[const aIndex: Integer]: GNode read GetItemsGeneric; default; function AddItem: GNode; function IndexOf(const aItem: GNode): Integer; function IsParent(const aNode: GNode): Boolean; function Move(const aParent: GNode): Boolean; function GetEnumerator: TGenericNodeEnumerator; constructor Create(const aParent: GNode; const aOwner: GOwner); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// generic TutlGenericGraph = class(TutlGraph) private function GetRootNode: T; public property RootNode: T read GetRootNode; end; implementation //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlGraphNodeData///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlGraphNodeData.Create; begin inherited Create; //nothing to do here end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlGraphNode.TNodeEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.TNodeEnumerator.GetCurrent: TutlGraphNode; begin result := fOwner.Items[fPos]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.TNodeEnumerator.MoveNext: Boolean; begin inc(fPos); result := (fPos < fOwner.Count); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlGraphNode.TNodeEnumerator.Create(const aOwner: TutlGraphNode); begin inherited Create; fPos := -1; fOwner := aOwner; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlGraphNode///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class function TutlGraphNode.GetDataClass: TutlGraphNodeDataClass; begin result := TutlGraphNodeData; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.GetCount: Integer; begin result := fItems.Count; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.GetItems(const aIndex: Integer): TutlGraphNode; begin if (aIndex >= 0) and (aIndex < Count) then result := (fItems[aIndex] as TutlGraphNode) else raise Exception.Create(Format('index (%d) is out of Range (%d - %d)', [aIndex, 0, Count-1])); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.AttachNode(const aNode: TutlGraphNode): Boolean; begin result := true; fItems.Add(aNode); aNode.fParent := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.DetachNode(const aNode: TutlGraphNode): Boolean; var i: Integer; begin result := false; i := fItems.IndexOf(aNode); if (i < 0) then exit; try fItems.OwnsObjects := false; fItems.Delete(i); aNode.fParent := nil; finally fItems.OwnsObjects := true; end; result := true; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.AddItem: TutlGraphNode; begin if Assigned(Owner) then result := Owner.GetItemClass().Create(self, Owner) else result := TutlGraphNode.Create(self, Owner); fItems.Add(result); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.IndexOf(const aItem: TutlGraphNode): Integer; begin result := fItems.IndexOf(aItem); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlGraphNode.DelItem(const aIndex: Integer); begin if (aIndex >= 0) and (aIndex < Count) then begin fItems.Delete(aIndex); end else raise Exception.Create(Format('index (%d) is out of Range (%d - %d)', [aIndex, 0, Count-1])); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlGraphNode.Clear; begin fItems.Clear; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.IsParent(const aNode: TutlGraphNode): Boolean; var n: TutlGraphNode; begin n := self; result := true; while Assigned(n.Parent) do begin if (aNode = n.Parent) then exit; n := n.Parent; end; result := false; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.Move(const aParent: TutlGraphNode): Boolean; var oldParent: TutlGraphNode; begin result := false; if (aParent.IsParent(self)) then exit; oldParent := Parent; if Assigned(oldParent) and not oldParent.DetachNode(self) then exit; if not aParent.AttachNode(self) then begin if Assigned(oldParent) then oldParent.AttachNode(self); exit; end; result := true; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGraphNode.GetEnumerator: TNodeEnumerator; begin result := TNodeEnumerator.Create(self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlGraphNode.Create(const aParent: TutlGraphNode; const aOwner: TutlGraph); begin inherited Create; fParent := aParent; fOwner := aOwner; fData := GetDataClass().Create(); fItems := TObjectList.create(true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TutlGraphNode.Destroy; begin FreeAndNil(fData); FreeAndNil(fItems); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlGraph///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class function TutlGraph.GetItemClass: TutlGraphNodeClass; begin result := TutlGraphNode; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlGraph.Create; begin inherited Create; fRootNode := GetItemClass().Create(nil, self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TutlGraph.Destroy; begin FreeAndNil(fRootNode); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlGenericGraphNode.TGenericNodeEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.TGenericNodeEnumerator.GetCurrent: GNode; begin result := GNode(fOwner.Items[fPos]); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.TGenericNodeEnumerator.MoveNext: Boolean; begin inc(fPos); result := (fPos < fOwner.Count); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlGenericGraphNode.TGenericNodeEnumerator.Create(const aOwner: TutlGraphNode); begin inherited Create; fPos := -1; fOwner := aOwner; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlGenericGraphNode////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.GetParent: GNode; begin result := GNode(fParent); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.GetOwner: GOwner; begin result := GOwner(fOwner); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.GetData: GData; begin result := GData(fData); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.GetItemsGeneric(const aIndex: Integer): GNode; begin result := GNode(inherited GetItems(aIndex)); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.AddItem: GNode; begin result := GNode(inherited AddItem); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.IndexOf(const aItem: GNode): Integer; begin result := inherited IndexOf(aItem); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.IsParent(const aNode: GNode): Boolean; begin result := inherited IsParent(aNode); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.Move(const aParent: GNode): Boolean; begin result := inherited Move(aParent); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraphNode.GetEnumerator: TGenericNodeEnumerator; begin result := TGenericNodeEnumerator.Create(self); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TutlGenericGraphNode.Create(const aParent: GNode; const aOwner: GOwner); begin inherited Create(TutlGraphNode(aParent), TutlGraph(aOwner)); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlGenericGraph////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlGenericGraph.GetRootNode: T; begin result := (fRootNode as T); end; end.