fpreportdata.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2022 by Michael van Canneyt and other members of the
  4. Free Pascal development team
  5. report data
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$IFNDEF FPC_DOTTEDUNITS}
  13. unit fpreportdata;
  14. {$ENDIF FPC_DOTTEDUNITS}
  15. {$mode objfpc}{$H+}
  16. interface
  17. {$IFDEF FPC_DOTTEDUNITS}
  18. uses
  19. System.Classes, System.SysUtils, Data.Db, FpJson.Data, FpReport.Report, FpReport.Data.Db;
  20. {$ELSE FPC_DOTTEDUNITS}
  21. uses
  22. Classes, SysUtils, DB, fpjson, fpreport, fpreportdb;
  23. {$ENDIF FPC_DOTTEDUNITS}
  24. Type
  25. EReportDataError = class(EReportError);
  26. { TFPReportDataHandler }
  27. TFPReportDataHandler = Class(TObject)
  28. Public
  29. Class Procedure RegisterHandler;
  30. Class Procedure UnRegisterHandler;
  31. Class Procedure RegisterConfigClass(aClass : TComponentClass);
  32. // Override this to return a dataset which is owned by AOwner, and configured by AConfig.
  33. // The dataset must not be opened.
  34. Function CreateDataset(AOwner : TComponent; AConfig : TJSONObject) : TDataset; virtual; abstract;
  35. // By default, master-detail is not possible. Let this return 'True' indicate that a dataset allows master-detail.
  36. Class Function AllowMasterDetail : Boolean; virtual;
  37. // This is called to set the master dataset on Detail
  38. Class Procedure SetMasterDataset(ADetail,AMaster : TDataset); virtual;
  39. // Check if the configuration is valid. Return a string that describes the error(s)
  40. // If the return is an empty string, the data designer will not close.
  41. Class Function CheckConfig(AConfig : TJSONObject) : String; virtual;
  42. // Called before and after rendering of a report in the designer.
  43. // Can be used to start/stop transactions
  44. Class Procedure StartRender(ADataset : TDataset); virtual;
  45. Class Procedure EndRender(ADataset : TDataset); virtual;
  46. // Configuration component. This is normally a visual class.
  47. Class Function ConfigFrameClass : TComponentClass; virtual;
  48. Class Function DataType : String; virtual; abstract;
  49. Class Function DataTypeDescription : String; virtual;
  50. end;
  51. TFPReportDataHandlerClass = Class of TFPReportDataHandler;
  52. { TFPReportDataDefinitionItem }
  53. TFPReportDataDefinitionItem = Class(TCollectionItem)
  54. private
  55. FConfig: TJSONObject;
  56. FDataType: String;
  57. FMaster: String;
  58. FName: String;
  59. FReportData: TFPReportDatasetData;
  60. FRunReportDataItem: TFPReportDataItem;
  61. function GetJSONConfig: TJSONStringType;
  62. procedure SetConfig(AValue: TJSONObject);
  63. procedure SetJSONConfig(AValue: TJSONStringType);
  64. procedure SetMaster(AValue: String);
  65. procedure SetName(AValue: String);
  66. Protected
  67. // To hold temporary references
  68. Property RunReportData : TFPReportDatasetData Read FReportData Write FReportData;
  69. Property RunReportDataItem : TFPReportDataItem Read FRunReportDataItem Write FRunReportDataItem;
  70. Public
  71. Constructor Create(ACollection: TCollection); override;
  72. Destructor Destroy; override;
  73. Procedure Assign(Source : TPersistent); override;
  74. Procedure SaveToJSON(O : TJSONObject); virtual;
  75. procedure LoadFromJSON(O: TJSONObject); virtual;
  76. // Clone this
  77. Function Clone(aNewName : String) : TFPReportDataDefinitionItem;
  78. // Create a dataset.
  79. Function CreateDataSet(AOwner : TComponent) : TDataset;
  80. // Check if the configuration is OK.
  81. Function Check : String;
  82. Property Config : TJSONObject Read FConfig Write SetConfig;
  83. Published
  84. property Name : String Read FName Write SetName;
  85. Property DataType : String Read FDataType Write FDataType;
  86. property Master : String Read FMaster Write SetMaster;
  87. Property JSONConfig : TJSONStringType Read GetJSONConfig Write SetJSONConfig;
  88. end;
  89. { TFPReportDataDefinitions }
  90. TFPReportDataDefinitions = Class(TCollection)
  91. private
  92. function GetD(Aindex : Integer): TFPReportDataDefinitionItem;
  93. procedure SetD(Aindex : Integer; AValue: TFPReportDataDefinitionItem);
  94. Public
  95. Function IndexOfRunData(aData : TFPReportDatasetData) : integer;
  96. Function IndexOfName(const aName : String): Integer;
  97. Procedure CheckCircularReference(aMasterName : String; aItem : TFPReportDataDefinitionItem);
  98. Function FindDataByName(const aName : String): TFPReportDataDefinitionItem;
  99. Function AddData(const aName : String) : TFPReportDataDefinitionItem;
  100. Procedure SaveToJSON(O : TJSONObject);
  101. Procedure LoadFromJSON(O : TJSONObject);
  102. Property Data [Aindex : Integer] : TFPReportDataDefinitionItem Read GetD Write SetD; default;
  103. end;
  104. { TFPCustomReportDataManager }
  105. TFPCustomReportDataManager = class(TComponent)
  106. private
  107. Class Var
  108. FTypesList : TStrings;
  109. Type
  110. { THDef }
  111. THDef = Class(TObject)
  112. TheClass : TFPReportDataHandlerClass;
  113. TheConfigClass : TComponentClass;
  114. Constructor Create(aClass : TFPReportDataHandlerClass; aConfigClass : TComponentClass);
  115. end;
  116. procedure ClearReportDatasetReference(aDataset: TFPReportDatasetData);
  117. Class Function FindDef(aDataType: String) : THDef;
  118. Class Function GetDef(aDataType: String) : THDef;
  119. Private
  120. FDataParent: TComponent;
  121. FMyParent : TComponent;
  122. FDefinitions: TFPReportDataDefinitions;
  123. FReport: TFPReport;
  124. procedure SetDataParent(AValue: TComponent);
  125. procedure SetDefinitions(AValue: TFPReportDataDefinitions);
  126. procedure SetReport(AValue: TFPReport);
  127. Protected
  128. Class Function TypeList : TStrings;
  129. Class procedure RemoveHandler(aDataType: String);
  130. Class Procedure RegisterHandler(aClass: TFPReportDataHandlerClass); virtual;
  131. Class Procedure UnRegisterHandler(aClass: TFPReportDataHandlerClass); virtual;
  132. Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  133. Function CreateDataDefinitions : TFPReportDataDefinitions; virtual;
  134. Function GetDatasetParent : TComponent;
  135. Property DataDefinitions : TFPReportDataDefinitions Read FDefinitions Write SetDefinitions;
  136. Public
  137. Class Function GetRegisteredTypes(AList : Tstrings) : Integer;
  138. Class Procedure RegisterConfigFrameClass(aTypeName : String; aClass : TComponentClass);
  139. Class Procedure UnRegisterConfigFrameClass(aTypeName : String);
  140. Class Function GetTypeHandlerClass(aTypeName : String) : TFPReportDataHandlerClass;
  141. Class Function GetTypeHandler(aTypeName : String) : TFPReportDataHandler;
  142. Class Function GetConfigFrameClass(aTypeName : String) : TComponentClass;
  143. Constructor Create(AOwner : TComponent); override;
  144. Destructor Destroy; override;
  145. Procedure SaveToJSON(O : TJSONObject);
  146. Procedure LoadFromJSON(O : TJSONObject);
  147. procedure RemoveFromReport(aReport: TFPReport);virtual;
  148. procedure RemoveFromReport;
  149. procedure ApplyToReport(aReport: TFPReport; Errors: TStrings); virtual;
  150. Procedure ApplyToReport(Errors : TStrings);
  151. // call this to start/stop a render, so dataset handlers can do cleanup, refetch data, reset transactions.
  152. Procedure StartRender;
  153. Procedure EndRender;
  154. Property Report : TFPReport Read FReport Write SetReport;
  155. Property DataParent : TComponent Read FDataParent Write SetDataParent;
  156. end;
  157. TFPReportDataManager = Class(TFPCustomReportDataManager)
  158. Public
  159. Property DataDefinitions;
  160. end;
  161. Resourcestring
  162. SErrDuplicateData = 'Duplicate data set name: "%s"';
  163. SErrInvalidDataName = 'Invalid data set name: "%s"';
  164. SErrNeedName = 'Data set needs a name';
  165. SErrNeedDataType = 'Data set needs a type';
  166. SErrInvalidDataType = 'Invalid data type: "%s"';
  167. SErrInvalidJSONConfig = '%s: Invalid JSON Configuration';
  168. SErrUnknownDataType = 'Unknown report data type: %s';
  169. SErrNoMasterDetailSupport = 'No master-detail support for class "%s"';
  170. SErrOpeningDataset = 'Error opening data "%s" : Exception %s with message %s';
  171. SErrInvalidDatasourceName = 'Invalid data source name : "%s"';
  172. SErrCircularReference = 'Invalid master data source "%s", circular references not allowed.';
  173. implementation
  174. Const
  175. DatasetNamePrefix = '__DS__';
  176. { TFPCustomReportDataManager }
  177. procedure TFPCustomReportDataManager.SetDefinitions(AValue: TFPReportDataDefinitions);
  178. begin
  179. if FDefinitions=AValue then Exit;
  180. FDefinitions.Assign(AValue);
  181. end;
  182. procedure TFPCustomReportDataManager.SetDataParent(AValue: TComponent);
  183. begin
  184. if FDataParent=AValue then Exit;
  185. If Assigned(FDataParent) then
  186. FDataParent.RemoveFreeNotification(Self);
  187. FDataParent:=AValue;
  188. If Assigned(FDataParent) then
  189. FDataParent.FreeNotification(Self);
  190. FreeAndNil(FMyParent);
  191. end;
  192. class function TFPCustomReportDataManager.FindDef(aDataType: String): THDef;
  193. var
  194. I : Integer;
  195. begin
  196. I:=TypeList.IndexOf(aDataType);
  197. if (I<>-1) then
  198. Result:=TypeList.Objects[i] as THDef
  199. else
  200. Result:=Nil;
  201. end;
  202. class function TFPCustomReportDataManager.GetDef(aDataType: String): THDef;
  203. begin
  204. Result:=FindDef(aDataType);
  205. if Result=Nil then
  206. Raise EReportDataError.CreateFmt(SErrUnknownDataType,[aDataType]);
  207. end;
  208. procedure TFPCustomReportDataManager.SetReport(AValue: TFPReport);
  209. begin
  210. if FReport=AValue then Exit;
  211. If Assigned(FReport) then
  212. FReport.RemoveFreeNotification(Self);
  213. FReport:=AValue;
  214. If Assigned(FReport) then
  215. FReport.FreeNotification(Self);
  216. end;
  217. class procedure TFPCustomReportDataManager.RegisterHandler(aClass: TFPReportDataHandlerClass);
  218. Var
  219. N : String;
  220. C : TComponentClass;
  221. begin
  222. N:=aClass.DataType;
  223. RemoveHandler(N);
  224. C:=aClass.ConfigFrameClass;
  225. TypeList.AddObject(N, THDef.Create(aClass,C));
  226. end;
  227. class procedure TFPCustomReportDataManager.RemoveHandler(aDataType : String);
  228. Var
  229. I : Integer;
  230. O : TObject;
  231. begin
  232. I:=TypeList.IndexOf(aDataType);
  233. if (I<>-1) then
  234. begin
  235. O:=TypeList.Objects[i];
  236. TypeList.Delete(I);
  237. O.Free;
  238. end;
  239. end;
  240. class procedure TFPCustomReportDataManager.UnRegisterHandler(aClass: TFPReportDataHandlerClass);
  241. begin
  242. RemoveHandler(aClass.DataType);
  243. end;
  244. procedure TFPCustomReportDataManager.ClearReportDatasetReference(aDataset : TFPReportDatasetData);
  245. Var
  246. I : Integer;
  247. begin
  248. if Assigned(FDefinitions) then
  249. begin
  250. I:=FDefinitions.IndexOfRunData(aDataset);
  251. if (I<>-1) then
  252. FDefinitions[i].RunReportData:=nil;
  253. end;
  254. end;
  255. procedure TFPCustomReportDataManager.Notification(AComponent: TComponent; Operation: TOperation);
  256. begin
  257. inherited Notification(AComponent, Operation);
  258. if Operation=opRemove then
  259. begin
  260. if AComponent=FDataParent then
  261. FDataParent:=Nil
  262. else if AComponent=FReport then
  263. FReport:=Nil
  264. else if (aComponent is TFPReportDatasetData) then
  265. ClearReportDatasetReference(aComponent as TFPReportDatasetData);
  266. end;
  267. end;
  268. Class function TFPCustomReportDataManager.TypeList: TStrings;
  269. Var
  270. SL : TStringList;
  271. begin
  272. If (FTypesList=nil) then
  273. begin
  274. SL:=TStringList.Create;
  275. SL.Sorted:=True;
  276. SL.Duplicates:=dupError;
  277. SL.OwnsObjects:=True;
  278. FTypesList:=SL;
  279. end;
  280. Result:=FTypesList;
  281. end;
  282. function TFPCustomReportDataManager.CreateDataDefinitions: TFPReportDataDefinitions;
  283. begin
  284. Result:=TFPReportDataDefinitions.Create(TFPReportDataDefinitionItem);
  285. end;
  286. function TFPCustomReportDataManager.GetDatasetParent: TComponent;
  287. begin
  288. Result:=FDataParent;
  289. if Result=Nil then
  290. begin
  291. If (FMyParent=Nil) then
  292. FMyParent:=TComponent.Create(Nil);
  293. Result:=FMyParent;
  294. end;
  295. end;
  296. constructor TFPCustomReportDataManager.Create(AOwner: TComponent);
  297. begin
  298. inherited Create(AOwner);
  299. FDefinitions:=CreateDataDefinitions;
  300. end;
  301. destructor TFPCustomReportDataManager.Destroy;
  302. begin
  303. FreeAndNil(FDefinitions);
  304. FreeAndNil(FMyParent);
  305. inherited Destroy;
  306. end;
  307. procedure TFPCustomReportDataManager.SaveToJSON(O: TJSONObject);
  308. begin
  309. DataDefinitions.SaveToJSON(O);
  310. end;
  311. procedure TFPCustomReportDataManager.LoadFromJSON(O: TJSONObject);
  312. begin
  313. DataDefinitions.LoadFromJSON(O);
  314. end;
  315. procedure TFPCustomReportDataManager.RemoveFromReport(aReport: TFPReport);
  316. Var
  317. DD : TFPReportDataDefinitionItem;
  318. RD : TFPReportDatasetData;
  319. D : TDataset;
  320. I : Integer;
  321. begin
  322. aReport.SaveDataToNames;
  323. For I:=0 to DataDefinitions.Count-1 do
  324. begin
  325. DD:=DataDefinitions[i];
  326. RD:=DD.RunReportData;
  327. if (RD<>Nil) then
  328. if (aReport.ReportData.IndexOfReportData(RD)<>-1) then
  329. begin
  330. D:=RD.Dataset;
  331. FreeAndNil(D);
  332. FreeAndNil(RD); // Should nil due to freenotification...
  333. DD.RunReportData:=Nil;
  334. end;
  335. end;
  336. end;
  337. procedure TFPCustomReportDataManager.RemoveFromReport;
  338. begin
  339. RemoveFromReport(FReport);
  340. end;
  341. procedure TFPCustomReportDataManager.ApplyToReport(Errors: TStrings);
  342. begin
  343. ApplyToReport(FReport,Errors);
  344. end;
  345. procedure TFPCustomReportDataManager.StartRender;
  346. Var
  347. I : integer;
  348. D : TFPReportDataDefinitionItem;
  349. H : TFPReportDataHandlerClass;
  350. begin
  351. // Create all datasets
  352. For I:=0 to DataDefinitions.Count-1 do
  353. begin
  354. D:=DataDefinitions[i];
  355. if Assigned(D.RunReportData) then
  356. begin
  357. H:=TFPCustomReportDataManager.GetTypeHandlerClass(D.DataType);
  358. H.StartRender(D.RunReportData.DataSet);
  359. end;
  360. end;
  361. end;
  362. procedure TFPCustomReportDataManager.EndRender;
  363. Var
  364. I : integer;
  365. D : TFPReportDataDefinitionItem;
  366. H : TFPReportDataHandlerClass;
  367. begin
  368. // Create all datasets
  369. For I:=0 to DataDefinitions.Count-1 do
  370. begin
  371. D:=DataDefinitions[i];
  372. if Assigned(D.RunReportData) then
  373. begin
  374. H:=TFPCustomReportDataManager.GetTypeHandlerClass(D.DataType);
  375. H.EndRender(D.RunReportData.DataSet);
  376. end;
  377. end;
  378. end;
  379. procedure TFPCustomReportDataManager.ApplyToReport(aReport : TFPReport; Errors: TStrings);
  380. Var
  381. I : Integer;
  382. MasterD,DesignD : TFPReportDataDefinitionItem;
  383. DatasetD : TFPReportDatasetData;
  384. H : TFPReportDataHandlerClass;
  385. L : TFPList;
  386. P : TComponent;
  387. DDS,MDS : TDataset;
  388. begin
  389. P:=GetDatasetParent;
  390. aReport.ReportData.Clear;
  391. // Create all datasets
  392. For I:=0 to DataDefinitions.Count-1 do
  393. begin
  394. DesignD:=DataDefinitions[i];
  395. DatasetD:=TFPReportDatasetData.Create(P);
  396. DesignD.RunReportData:=DatasetD;
  397. DatasetD.FreeNotification(Self);
  398. DatasetD.Dataset:=DesignD.CreateDataSet(P);
  399. Try
  400. DatasetD.InitFieldDefs;
  401. except
  402. On E : Exception do
  403. If Assigned(Errors) then
  404. Errors.Add(Format(SErrOpeningDataset, [DesignD.Name, E.ClassName, E.Message]))
  405. else
  406. Raise;
  407. end;
  408. DatasetD.Name:=DesignD.Name;
  409. DatasetD.Dataset.Name:=DatasetNamePrefix+DesignD.Name;
  410. DatasetD.StartDesigning; // set designing flag, or OI will not show reference to it.
  411. DesignD.RunReportDataItem:=aReport.ReportData.AddReportData(DatasetD);
  412. end;
  413. // Set master-detail relations
  414. For I:=0 to DataDefinitions.Count-1 do
  415. begin
  416. DesignD:=DataDefinitions[i];
  417. if (DesignD.Master<>'') then
  418. begin
  419. H:=TFPCustomReportDataManager.GetTypeHandlerClass(DesignD.DataType);
  420. MasterD:=DataDefinitions.FindDataByName(DesignD.Master);
  421. DDS:=(DesignD.RunReportDataItem.Data as TFPReportDatasetData).DataSet;
  422. MDS:=(MasterD.RunReportDataItem.Data as TFPReportDatasetData).DataSet;
  423. H.SetMasterDataset(DDS,MDS);
  424. end;
  425. end;
  426. end;
  427. class function TFPCustomReportDataManager.GetRegisteredTypes(AList: Tstrings): Integer;
  428. begin
  429. // Don't use assign or addstrings, it will copy the THRefs too, possibly leading to errors
  430. AList.Text:=TypeList.Text;
  431. Result:=AList.Count;
  432. end;
  433. class procedure TFPCustomReportDataManager.RegisterConfigFrameClass(aTypeName: String; aClass: TComponentClass);
  434. Var
  435. H : THDef;
  436. begin
  437. H:=GetDef(aTypeName);
  438. H.TheConfigClass:=aClass;
  439. end;
  440. class procedure TFPCustomReportDataManager.UnRegisterConfigFrameClass(aTypeName: String);
  441. Var
  442. H : THDef;
  443. begin
  444. H:=FindDef(aTypeName);
  445. if Assigned(H) then
  446. H.TheConfigClass:=Nil;
  447. end;
  448. class function TFPCustomReportDataManager.GetTypeHandlerClass(aTypeName: String): TFPReportDataHandlerClass;
  449. Var
  450. H : THDef;
  451. begin
  452. H:=GetDef(aTypeName);
  453. Result:=H.TheClass;
  454. end;
  455. class function TFPCustomReportDataManager.GetTypeHandler(aTypeName: String): TFPReportDataHandler;
  456. begin
  457. Result:=GetTypeHandlerClass(aTypeName).Create;
  458. end;
  459. class function TFPCustomReportDataManager.GetConfigFrameClass(aTypeName: String): TComponentClass;
  460. Var
  461. H : THDef;
  462. begin
  463. H:=GetDef(aTypeName);
  464. Result:=H.TheConfigClass;
  465. end;
  466. { THDef }
  467. constructor TFPCustomReportDataManager.THDef.Create(aClass: TFPReportDataHandlerClass; aConfigClass : TComponentClass);
  468. begin
  469. TheClass:=AClass;
  470. TheConfigClass:=aConfigClass;
  471. end;
  472. { TFPReportDataDefinitions }
  473. function TFPReportDataDefinitions.GetD(Aindex : Integer): TFPReportDataDefinitionItem;
  474. begin
  475. Result:=Items[Aindex] as TFPReportDataDefinitionItem;
  476. end;
  477. procedure TFPReportDataDefinitions.SetD(Aindex : Integer; AValue: TFPReportDataDefinitionItem);
  478. begin
  479. Items[Aindex]:=AValue;
  480. end;
  481. function TFPReportDataDefinitions.IndexOfRunData(aData: TFPReportDatasetData): integer;
  482. begin
  483. Result:=Count-1;
  484. While (Result>=0) and (GetD(Result).RunReportData<>aData) do
  485. Dec(Result);
  486. end;
  487. function TFPReportDataDefinitions.IndexOfName(const aName: String): Integer;
  488. begin
  489. Result:=Count-1;
  490. While (Result>=0) and (CompareText(AName,GetD(Result).Name)<>0) do
  491. Dec(Result);
  492. end;
  493. procedure TFPReportDataDefinitions.CheckCircularReference(aMasterName: String; aItem: TFPReportDataDefinitionItem);
  494. Var
  495. DD : TFPReportDataDefinitionItem;
  496. begin
  497. While (aMasterName<>'') do
  498. begin
  499. DD:=FindDataByName(aMasterName);
  500. if (DD=Nil) then
  501. raise EReportDataError.CreateFmt(SErrInvalidDatasourceName, [aMasterName]);
  502. If (DD=aItem) then
  503. raise EReportDataError.CreateFmt(SErrCircularReference, [aMasterName]);
  504. aMasterName:=DD.Master;
  505. end;
  506. end;
  507. function TFPReportDataDefinitions.FindDataByName(const aName: String): TFPReportDataDefinitionItem;
  508. var
  509. I : Integer;
  510. begin
  511. I:=indexOfname(aName);
  512. if I=-1 then
  513. Result:=Nil
  514. else
  515. Result:=GetD(I);
  516. end;
  517. function TFPReportDataDefinitions.AddData(const aName: String): TFPReportDataDefinitionItem;
  518. begin
  519. if (IndexOfName(aName)<>-1) then
  520. raise EReportDataError.CreateFmt(SErrDuplicateData, [aName]);
  521. Result:=add as TFPReportDataDefinitionItem;
  522. Result.Name:=aName;
  523. end;
  524. procedure TFPReportDataDefinitions.SaveToJSON(O: TJSONObject);
  525. Var
  526. A : TJSONArray;
  527. DS : TJSONObject;
  528. I : Integer;
  529. begin
  530. A:=TJSONArray.Create;
  531. O.Add('datasets',a);
  532. For I:=0 to Count-1 do
  533. begin
  534. DS:=TJSONObject.Create;
  535. A.Add(DS);
  536. Data[i].SaveToJSON(DS);
  537. end;
  538. end;
  539. procedure TFPReportDataDefinitions.LoadFromJSON(O: TJSONObject);
  540. Var
  541. A : TJSONArray;
  542. DS : TFPReportDataDefinitionItem;
  543. I : Integer;
  544. begin
  545. Clear;
  546. A:=O.Get('datasets',TJSONArray(Nil));
  547. if Assigned(A) then
  548. For I:=0 to A.Count-1 do
  549. if A.Types[i]=jtObject then
  550. begin
  551. DS:=Add as TFPReportDataDefinitionItem;
  552. DS.LoadFromJSON(A.Objects[i]);
  553. end;
  554. end;
  555. class procedure TFPReportDataHandler.RegisterHandler;
  556. begin
  557. TFPCustomReportDataManager.RegisterHandler(Self);
  558. end;
  559. class procedure TFPReportDataHandler.UnRegisterHandler;
  560. begin
  561. TFPCustomReportDataManager.UnRegisterHandler(Self);
  562. end;
  563. class procedure TFPReportDataHandler.RegisterConfigClass(aClass: TComponentClass);
  564. begin
  565. TFPCustomReportDataManager.RegisterConfigFrameClass(DataType,aClass);
  566. end;
  567. class function TFPReportDataHandler.AllowMasterDetail: Boolean;
  568. begin
  569. Result:=False;
  570. end;
  571. Class procedure TFPReportDataHandler.SetMasterDataset(ADetail, AMaster: TDataset);
  572. begin
  573. Raise EReportDataError.CreateFmt(SErrNoMasterDetailSupport,[ADetail.ClassName]);
  574. end;
  575. class function TFPReportDataHandler.CheckConfig(AConfig: TJSONObject): String;
  576. begin
  577. Result:='';
  578. end;
  579. class procedure TFPReportDataHandler.StartRender(ADataset: TDataset);
  580. begin
  581. // Do nothing
  582. end;
  583. class procedure TFPReportDataHandler.EndRender(ADataset: TDataset);
  584. begin
  585. // Do nothing
  586. end;
  587. class function TFPReportDataHandler.ConfigFrameClass: TComponentClass;
  588. begin
  589. Result:=Nil;
  590. end;
  591. class function TFPReportDataHandler.DataTypeDescription: String;
  592. begin
  593. Result:=DataType
  594. end;
  595. { TFPReportDataDefinitionItem }
  596. procedure TFPReportDataDefinitionItem.SetConfig(AValue: TJSONObject);
  597. begin
  598. if FConfig=AValue then Exit;
  599. FreeAndNil(FConfig);
  600. FConfig:=AValue.Clone as TJSONObject;
  601. end;
  602. function TFPReportDataDefinitionItem.GetJSONConfig: TJSONStringType;
  603. begin
  604. Result:=FConfig.AsJSON;
  605. end;
  606. procedure TFPReportDataDefinitionItem.SetJSONConfig(AValue: TJSONStringType);
  607. Var
  608. D : TJSONData;
  609. begin
  610. D:=GetJSON(aValue);
  611. if D is TJSONObject then
  612. begin
  613. FreeAndNil(FConfig);
  614. FConfig:=D as TJSONObject;
  615. end
  616. else
  617. begin
  618. FreeAndNil(D);
  619. Raise EReportDataError.CreateFmt(SErrInvalidJSONConfig,[Name]);
  620. end;
  621. end;
  622. procedure TFPReportDataDefinitionItem.SetMaster(AValue: String);
  623. begin
  624. if FMaster=AValue then Exit;
  625. FMaster:=AValue;
  626. end;
  627. procedure TFPReportDataDefinitionItem.SetName(AValue: String);
  628. begin
  629. if FName=AValue then Exit;
  630. {$IF FPC_FULLVERSION < 30002}
  631. if Not IsValidIdent(aValue) then
  632. {$ELSE}
  633. if Not IsValidIdent(aValue,True,true) then
  634. {$ENDIF}
  635. raise EReportDataError.CreateFmt(SErrInvalidDataName, [aValue]);
  636. if (Collection is TFPReportVariables) then
  637. If ((Collection as TFPReportVariables).FindVariable(AValue)<>Nil) then
  638. raise EReportDataError.CreateFmt(SErrDuplicateData, [aValue]);
  639. FName:=AValue;
  640. end;
  641. procedure TFPReportDataDefinitionItem.Assign(Source: TPersistent);
  642. Var
  643. D : TFPReportDataDefinitionItem;
  644. begin
  645. if (Source is TFPReportDataDefinitionItem) then
  646. begin
  647. D:=Source as TFPReportDataDefinitionItem;
  648. Config:=D.Config;
  649. Name:=D.Name;
  650. DataType:=D.DataType;
  651. Master:=D.Master;
  652. end
  653. else
  654. inherited Assign(Source);
  655. end;
  656. procedure TFPReportDataDefinitionItem.SaveToJSON(O: TJSONObject);
  657. begin
  658. O.Add('name',Name);
  659. O.Add('type',DataType);
  660. O.Add('config',Config.Clone);
  661. O.Add('master',Master);
  662. end;
  663. procedure TFPReportDataDefinitionItem.LoadFromJSON(O: TJSONObject);
  664. Var
  665. C : TJSONObject;
  666. begin
  667. Name:=O.Get('name',Name);
  668. DataType:=O.Get('type',DataType);
  669. C:=O.Get('config',TJSONObject(Nil));
  670. if Assigned(C) then
  671. Config:=C;
  672. Master:=O.Get('master','');
  673. end;
  674. function TFPReportDataDefinitionItem.Clone(aNewName: String): TFPReportDataDefinitionItem;
  675. begin
  676. Result:=Collection.Add as TFPReportDataDefinitionItem;
  677. Result.Assign(Self);
  678. Result.Name:=aNewName;
  679. end;
  680. function TFPReportDataDefinitionItem.CreateDataSet(AOwner: TComponent): TDataset;
  681. Var
  682. H : TFPReportDataHandler;
  683. begin
  684. H:=TFPCustomReportDataManager.GetTypeHandler(DataType);
  685. try
  686. Result:=H.CreateDataset(AOwner,Config);
  687. finally
  688. H.Free;
  689. end;
  690. end;
  691. function TFPReportDataDefinitionItem.Check: String;
  692. Var
  693. H : TFPReportDataHandler;
  694. begin
  695. If (Name='') then
  696. Result:=SErrNeedName
  697. else if (DataType='') then
  698. Result:=SErrNeedDataType
  699. else
  700. begin
  701. H:=TFPCustomReportDataManager.GetTypeHandler(DataType);
  702. try
  703. if H=Nil then
  704. Result:=Format(SErrInvalidDataType,[DataType])
  705. else
  706. Result:=H.CheckConfig(Config);
  707. Finally
  708. H.Free;
  709. end;
  710. end;
  711. end;
  712. constructor TFPReportDataDefinitionItem.Create(ACollection: TCollection);
  713. begin
  714. inherited Create(ACollection);
  715. FConfig:=TJSONObject.Create;
  716. end;
  717. destructor TFPReportDataDefinitionItem.Destroy;
  718. begin
  719. FreeAndNil(FConfig);
  720. inherited Destroy;
  721. end;
  722. Finalization
  723. FreeAndNil(TFPCustomReportDataManager.FTypesList);
  724. end.