您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

414 行
17 KiB

  1. unit uutlGraph;
  2. { Package: Utils
  3. Prefix: utl - UTiLs
  4. Beschreibung: diese Unit implementiert einen generischen Graphen }
  5. {$mode objfpc}{$H+}
  6. interface
  7. uses
  8. Classes, SysUtils, contnrs, uutlCommon;
  9. type
  10. TutlGraph = class;
  11. TutlGraphNodeData = class(TObject)
  12. public
  13. constructor Create; virtual;
  14. end;
  15. TutlGraphNodeDataClass = class of TutlGraphNodeData;
  16. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. TutlGraphNode = class;
  18. TutlGraphNodeClass = class of TutlGraphNode;
  19. TutlGraphNode = class(TutlInterfaceNoRefCount)
  20. private type
  21. TNodeEnumerator = class(TObject)
  22. private
  23. fOwner: TutlGraphNode;
  24. fPos: Integer;
  25. function GetCurrent: TutlGraphNode;
  26. public
  27. property Current: TutlGraphNode read GetCurrent;
  28. function MoveNext: Boolean;
  29. constructor Create(const aOwner: TutlGraphNode);
  30. end;
  31. protected
  32. fParent: TutlGraphNode;
  33. fOwner: TutlGraph;
  34. fData: TutlGraphNodeData;
  35. fItems: TObjectList;
  36. class function GetDataClass: TutlGraphNodeDataClass; virtual;
  37. function GetCount: Integer; virtual;
  38. function GetItems(const aIndex: Integer): TutlGraphNode; virtual;
  39. function AttachNode(const aNode: TutlGraphNode): Boolean; virtual;
  40. function DetachNode(const aNode: TutlGraphNode): Boolean; virtual;
  41. public
  42. property Parent: TutlGraphNode read fParent;
  43. property Owner: TutlGraph read fOwner;
  44. property Data: TutlGraphNodeData read fData;
  45. property Count: Integer read GetCount;
  46. property Items[const aIndex: Integer]: TutlGraphNode read GetItems; default;
  47. function AddItem: TutlGraphNode;
  48. function IndexOf(const aItem: TutlGraphNode): Integer;
  49. procedure DelItem(const aIndex: Integer);
  50. procedure Clear;
  51. function IsParent(const aNode: TutlGraphNode): Boolean;
  52. function Move(const aParent: TutlGraphNode): Boolean;
  53. function GetEnumerator: TNodeEnumerator;
  54. constructor Create(const aParent: TutlGraphNode; const aOwner: TutlGraph);
  55. destructor Destroy; override;
  56. end;
  57. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  58. TutlGraph = class(TutlInterfaceNoRefCount)
  59. protected
  60. fRootNode: TutlGraphNode;
  61. class function GetItemClass: TutlGraphNodeClass; virtual;
  62. public
  63. property RootNode: TutlGraphNode read fRootNode;
  64. constructor Create;
  65. destructor Destroy; override;
  66. end;
  67. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  68. generic TutlGenericGraphNode<GData: TutlGraphNodeData; GNode, GOwner> = class(TutlGraphNode)
  69. private type
  70. TGenericNodeEnumerator = class(TObject)
  71. private
  72. fOwner: TutlGraphNode;
  73. fPos: Integer;
  74. function GetCurrent: GNode;
  75. public
  76. property Current: GNode read GetCurrent;
  77. function MoveNext: Boolean;
  78. constructor Create(const aOwner: TutlGraphNode);
  79. end;
  80. private
  81. function GetParent: GNode;
  82. function GetOwner: GOwner;
  83. function GetData: GData;
  84. function GetItemsGeneric(const aIndex: Integer): GNode;
  85. public
  86. property Parent: GNode read GetParent;
  87. property Owner: GOwner read GetOwner;
  88. property Data: GData read GetData;
  89. property Items[const aIndex: Integer]: GNode read GetItemsGeneric; default;
  90. function AddItem: GNode;
  91. function IndexOf(const aItem: GNode): Integer;
  92. function IsParent(const aNode: GNode): Boolean;
  93. function Move(const aParent: GNode): Boolean;
  94. function GetEnumerator: TGenericNodeEnumerator;
  95. constructor Create(const aParent: GNode; const aOwner: GOwner);
  96. end;
  97. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  98. generic TutlGenericGraph<T: TutlGraphNode> = class(TutlGraph)
  99. private
  100. function GetRootNode: T;
  101. public
  102. property RootNode: T read GetRootNode;
  103. end;
  104. implementation
  105. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  106. //TutlGraphNodeData/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  107. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  108. constructor TutlGraphNodeData.Create;
  109. begin
  110. inherited Create;
  111. //nothing to do here
  112. end;
  113. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  114. //TutlGraphNode.TNodeEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  115. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  116. function TutlGraphNode.TNodeEnumerator.GetCurrent: TutlGraphNode;
  117. begin
  118. result := fOwner.Items[fPos];
  119. end;
  120. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  121. function TutlGraphNode.TNodeEnumerator.MoveNext: Boolean;
  122. begin
  123. inc(fPos);
  124. result := (fPos < fOwner.Count);
  125. end;
  126. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  127. constructor TutlGraphNode.TNodeEnumerator.Create(const aOwner: TutlGraphNode);
  128. begin
  129. inherited Create;
  130. fPos := -1;
  131. fOwner := aOwner;
  132. end;
  133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  134. //TutlGraphNode/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  136. class function TutlGraphNode.GetDataClass: TutlGraphNodeDataClass;
  137. begin
  138. result := TutlGraphNodeData;
  139. end;
  140. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  141. function TutlGraphNode.GetCount: Integer;
  142. begin
  143. result := fItems.Count;
  144. end;
  145. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  146. function TutlGraphNode.GetItems(const aIndex: Integer): TutlGraphNode;
  147. begin
  148. if (aIndex >= 0) and (aIndex < Count) then
  149. result := (fItems[aIndex] as TutlGraphNode)
  150. else
  151. raise Exception.Create(Format('index (%d) is out of Range (%d - %d)', [aIndex, 0, Count-1]));
  152. end;
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. function TutlGraphNode.AttachNode(const aNode: TutlGraphNode): Boolean;
  155. begin
  156. result := true;
  157. fItems.Add(aNode);
  158. aNode.fParent := self;
  159. end;
  160. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  161. function TutlGraphNode.DetachNode(const aNode: TutlGraphNode): Boolean;
  162. var
  163. i: Integer;
  164. begin
  165. result := false;
  166. i := fItems.IndexOf(aNode);
  167. if (i < 0) then
  168. exit;
  169. try
  170. fItems.OwnsObjects := false;
  171. fItems.Delete(i);
  172. aNode.fParent := nil;
  173. finally
  174. fItems.OwnsObjects := true;
  175. end;
  176. result := true;
  177. end;
  178. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  179. function TutlGraphNode.AddItem: TutlGraphNode;
  180. begin
  181. if Assigned(Owner) then
  182. result := Owner.GetItemClass().Create(self, Owner)
  183. else
  184. result := TutlGraphNode.Create(self, Owner);
  185. fItems.Add(result);
  186. end;
  187. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  188. function TutlGraphNode.IndexOf(const aItem: TutlGraphNode): Integer;
  189. begin
  190. result := fItems.IndexOf(aItem);
  191. end;
  192. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  193. procedure TutlGraphNode.DelItem(const aIndex: Integer);
  194. begin
  195. if (aIndex >= 0) and (aIndex < Count) then begin
  196. fItems.Delete(aIndex);
  197. end else
  198. raise Exception.Create(Format('index (%d) is out of Range (%d - %d)', [aIndex, 0, Count-1]));
  199. end;
  200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  201. procedure TutlGraphNode.Clear;
  202. begin
  203. fItems.Clear;
  204. end;
  205. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  206. function TutlGraphNode.IsParent(const aNode: TutlGraphNode): Boolean;
  207. var
  208. n: TutlGraphNode;
  209. begin
  210. n := self;
  211. result := true;
  212. while Assigned(n.Parent) do begin
  213. if (aNode = n.Parent) then
  214. exit;
  215. n := n.Parent;
  216. end;
  217. result := false;
  218. end;
  219. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  220. function TutlGraphNode.Move(const aParent: TutlGraphNode): Boolean;
  221. var
  222. oldParent: TutlGraphNode;
  223. begin
  224. result := false;
  225. if (aParent.IsParent(self)) then
  226. exit;
  227. oldParent := Parent;
  228. if Assigned(oldParent) and not oldParent.DetachNode(self) then
  229. exit;
  230. if not aParent.AttachNode(self) then begin
  231. if Assigned(oldParent) then
  232. oldParent.AttachNode(self);
  233. exit;
  234. end;
  235. result := true;
  236. end;
  237. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  238. function TutlGraphNode.GetEnumerator: TNodeEnumerator;
  239. begin
  240. result := TNodeEnumerator.Create(self);
  241. end;
  242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243. constructor TutlGraphNode.Create(const aParent: TutlGraphNode; const aOwner: TutlGraph);
  244. begin
  245. inherited Create;
  246. fParent := aParent;
  247. fOwner := aOwner;
  248. fData := GetDataClass().Create();
  249. fItems := TObjectList.create(true);
  250. end;
  251. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  252. destructor TutlGraphNode.Destroy;
  253. begin
  254. FreeAndNil(fData);
  255. FreeAndNil(fItems);
  256. inherited Destroy;
  257. end;
  258. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  259. //TutlGraph/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  260. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  261. class function TutlGraph.GetItemClass: TutlGraphNodeClass;
  262. begin
  263. result := TutlGraphNode;
  264. end;
  265. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  266. constructor TutlGraph.Create;
  267. begin
  268. inherited Create;
  269. fRootNode := GetItemClass().Create(nil, self);
  270. end;
  271. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. destructor TutlGraph.Destroy;
  273. begin
  274. FreeAndNil(fRootNode);
  275. inherited Destroy;
  276. end;
  277. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  278. //TutlGenericGraphNode.TGenericNodeEnumerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  279. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  280. function TutlGenericGraphNode.TGenericNodeEnumerator.GetCurrent: GNode;
  281. begin
  282. result := GNode(fOwner.Items[fPos]);
  283. end;
  284. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  285. function TutlGenericGraphNode.TGenericNodeEnumerator.MoveNext: Boolean;
  286. begin
  287. inc(fPos);
  288. result := (fPos < fOwner.Count);
  289. end;
  290. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  291. constructor TutlGenericGraphNode.TGenericNodeEnumerator.Create(const aOwner: TutlGraphNode);
  292. begin
  293. inherited Create;
  294. fPos := -1;
  295. fOwner := aOwner;
  296. end;
  297. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  298. //TutlGenericGraphNode//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. function TutlGenericGraphNode.GetParent: GNode;
  301. begin
  302. result := GNode(fParent);
  303. end;
  304. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  305. function TutlGenericGraphNode.GetOwner: GOwner;
  306. begin
  307. result := GOwner(fOwner);
  308. end;
  309. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  310. function TutlGenericGraphNode.GetData: GData;
  311. begin
  312. result := GData(fData);
  313. end;
  314. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  315. function TutlGenericGraphNode.GetItemsGeneric(const aIndex: Integer): GNode;
  316. begin
  317. result := GNode(inherited GetItems(aIndex));
  318. end;
  319. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  320. function TutlGenericGraphNode.AddItem: GNode;
  321. begin
  322. result := GNode(inherited AddItem);
  323. end;
  324. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  325. function TutlGenericGraphNode.IndexOf(const aItem: GNode): Integer;
  326. begin
  327. result := inherited IndexOf(aItem);
  328. end;
  329. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  330. function TutlGenericGraphNode.IsParent(const aNode: GNode): Boolean;
  331. begin
  332. result := inherited IsParent(aNode);
  333. end;
  334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  335. function TutlGenericGraphNode.Move(const aParent: GNode): Boolean;
  336. begin
  337. result := inherited Move(aParent);
  338. end;
  339. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  340. function TutlGenericGraphNode.GetEnumerator: TGenericNodeEnumerator;
  341. begin
  342. result := TGenericNodeEnumerator.Create(self);
  343. end;
  344. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  345. constructor TutlGenericGraphNode.Create(const aParent: GNode; const aOwner: GOwner);
  346. begin
  347. inherited Create(TutlGraphNode(aParent), TutlGraph(aOwner));
  348. end;
  349. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  350. //TutlGenericGraph//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  351. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  352. function TutlGenericGraph.GetRootNode: T;
  353. begin
  354. result := (fRootNode as T);
  355. end;
  356. end.