fpjsonreport.pp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. {
  2. This file is part of the Free Component Library.
  3. Copyright (c) 2017 Michael Van Canneyt, member of the Free Pascal development team
  4. TFPReport descendent that stores it's design in a JSON structure.
  5. Can be used in an IDE
  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. unit fpjsonreport;
  13. {$mode objfpc}{$H+}
  14. interface
  15. uses
  16. Classes, SysUtils, fpreport, fpjson, fpreportstreamer, fpreportdata;
  17. Type
  18. { TFPJSONReport }
  19. TReadReportJSONEvent = Procedure(Sender : TObject; JSON : TJSONObject) of object;
  20. TWriteReportJSONEvent = Procedure(Sender : TObject; JSON : TJSONObject) of object;
  21. TFPJSONReport = class(TFPReport)
  22. private
  23. FDataManager: TFPCustomReportDataManager;
  24. FDesignTimeJSON: TJSONObject;
  25. FLoadErrors: TStrings;
  26. FOnReadJSON: TReadReportJSONEvent;
  27. FOnWriteJSON: TWriteReportJSONEvent;
  28. FDesignDataName : String;
  29. function GetDesignDataName: String;
  30. procedure ReadReportJSON(Reader: TReader);
  31. procedure SetDataManager(AValue: TFPCustomReportDataManager);
  32. procedure SetDesignDataName(AValue: String);
  33. function StoreDesignDataName: Boolean;
  34. procedure WriteReportJSON(Writer: TWriter);
  35. Protected
  36. procedure DoReadJSON(aJSON: TJSONObject);virtual;
  37. procedure DoWriteJSON(aJSON: TJSONObject);virtual;
  38. Procedure DefineProperties(Filer: TFiler); override;
  39. Procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  40. Public
  41. Constructor Create(AOwner : TComponent); override;
  42. destructor Destroy; override;
  43. procedure LoadFromStream(const aStream: TStream);
  44. procedure SaveToStream(const aStream: TStream);
  45. procedure SaveRenderToStream(const aStream: TStream);
  46. Procedure LoadFromJSON(aJSON : TJSONObject); virtual;
  47. Procedure SavetoJSON(aJSON : TJSONObject); virtual;
  48. Procedure SaveRenderToJSON(aJSON : TJSONObject); virtual;
  49. Procedure LoadFromFile(const aFileName : String);
  50. Procedure SaveToFile(const aFileName : String);
  51. procedure SaveRenderToFile(const aFileName: String);
  52. Property LoadErrors : TStrings Read FLoadErrors;
  53. Property DataManager : TFPCustomReportDataManager Read FDataManager Write SetDataManager;
  54. Property DesignDataName : String Read GetDesignDataName Write SetDesignDataName Stored StoreDesignDataName;
  55. Property DesignTimeJSON : TJSONObject Read FDesignTimeJSON;
  56. Property OnReadJSON : TReadReportJSONEvent Read FOnReadJSON Write FOnReadJSON;
  57. Property OnWriteJSON : TWriteReportJSONEvent Read FOnWriteJSON Write FOnWriteJSON;
  58. end;
  59. implementation
  60. Const
  61. DefaultDesignData = 'DesignData';
  62. Resourcestring
  63. SErrInvalidJSONData = 'Invalid JSON Data';
  64. SErrFailedToLoad = 'Failed to load report: %s';
  65. { TFPJSONReport }
  66. procedure TFPJSONReport.ReadReportJSON(Reader: TReader);
  67. Var
  68. S : UnicodeString;
  69. D : TJSONData;
  70. begin
  71. FDesignTimeJSON.Clear;
  72. S:=Reader.ReadUnicodeString;
  73. if (S<>'') then
  74. begin
  75. D:=GetJSON(UTF8Encode(S),True);
  76. if D is TJSONObject then
  77. begin
  78. FreeAndNil(FDesignTimeJSON);
  79. FDesignTimeJSON:=D as TJSONObject
  80. end
  81. else
  82. begin
  83. D.Free;
  84. FDesignTimeJSON:=TJSONObject.Create;
  85. Raise EReportError.CreateFmt(SErrFailedToLoad,[SErrInvalidJSONData]);
  86. end;
  87. end;
  88. end;
  89. procedure TFPJSONReport.SetDataManager(AValue: TFPCustomReportDataManager);
  90. begin
  91. if FDataManager=AValue then Exit;
  92. If Assigned(FDataManager) then
  93. FDataManager.RemoveFreeNotification(Self);
  94. FDataManager:=AValue;
  95. If Assigned(FDataManager) then
  96. FDataManager.FreeNotification(Self);
  97. end;
  98. procedure TFPJSONReport.SetDesignDataName(AValue: String);
  99. begin
  100. if AValue=GetDesignDataName then exit;
  101. FDesignDataName:=aValue;
  102. end;
  103. function TFPJSONReport.StoreDesignDataName: Boolean;
  104. begin
  105. Result:=GetDesignDataName<>DefaultDesignData;
  106. end;
  107. procedure TFPJSONReport.WriteReportJSON(Writer: TWriter);
  108. Var
  109. S : UnicodeString;
  110. begin
  111. S:='';
  112. if (FDesignTimeJSON.Count>0) then
  113. S:=UTF8Decode(FDesignTimeJSON.AsJSON);
  114. Writer.WriteUnicodeString(S);
  115. end;
  116. procedure TFPJSONReport.DefineProperties(Filer: TFiler);
  117. begin
  118. inherited DefineProperties(Filer);
  119. Filer.DefineProperty('ReportJSON',@ReadReportJSON,@WriteReportJSON,Assigned(FDesignTimeJSON) and (FDesignTimeJSON.Count>0));
  120. end;
  121. procedure TFPJSONReport.Notification(AComponent: TComponent; Operation: TOperation);
  122. begin
  123. inherited Notification(AComponent, Operation);
  124. if (Operation=opRemove) and (AComponent=FDataManager) then
  125. FDataManager:=Nil;
  126. end;
  127. constructor TFPJSONReport.Create(AOwner: TComponent);
  128. begin
  129. inherited Create(AOwner);
  130. FDesignTimeJSON:=TJSONObject.Create;
  131. FLoadErrors:=TStringList.Create;
  132. end;
  133. destructor TFPJSONReport.Destroy;
  134. begin
  135. FreeAndNil(FLoadErrors);
  136. FreeAndNil(FDesignTimeJSON);
  137. inherited Destroy;
  138. end;
  139. Function TFPJSONReport.GetDesignDataName : String;
  140. begin
  141. Result:=FDesignDataName;
  142. if (FDesignDataName='') then
  143. Result:=DefaultDesignData;
  144. end;
  145. procedure TFPJSONReport.DoReadJSON(aJSON: TJSONObject);
  146. Var
  147. O : TJSONObject;
  148. begin
  149. FloadErrors.Clear;
  150. if Assigned(FOnReadJSON) then
  151. FOnReadJSON(Self,aJSON);
  152. if Assigned(FDataManager) then
  153. begin
  154. O:=aJSON.get(GetDesignDataName,TJSONObject(Nil));
  155. if Assigned(O) then
  156. begin
  157. FDataManager.LoadFromJSON(O);
  158. FDataManager.ApplyToReport(Self,LoadErrors);
  159. end;
  160. end;
  161. end;
  162. procedure TFPJSONReport.LoadFromJSON(aJSON: TJSONObject);
  163. Var
  164. R : TFPReportJSONStreamer;
  165. N : String;
  166. begin
  167. N:=Name;
  168. DoReadJSON(aJSON);
  169. R:=TFPReportJSONStreamer.Create(Nil);
  170. try
  171. R.OwnsJSON:=False;
  172. R.JSON:=aJSON;
  173. ReadElement(R);
  174. finally
  175. Name:=N;
  176. R.Free;
  177. end;
  178. end;
  179. procedure TFPJSONReport.DoWriteJSON(aJSON: TJSONObject);
  180. Var
  181. O: TJSONObject;
  182. begin
  183. if Assigned(FDataManager) then
  184. begin
  185. O:=TJSONObject.Create();
  186. aJSON.Add(GetDesignDataName,O);
  187. FDataManager.SaveToJSON(O);
  188. end;
  189. if Assigned(FOnWriteJSON) then
  190. FOnWriteJSON(Self,aJSON);
  191. end;
  192. procedure TFPJSONReport.SavetoJSON(aJSON: TJSONObject);
  193. Var
  194. R : TFPReportJSONStreamer;
  195. begin
  196. DoWriteJSON(aJSON);
  197. R:=TFPReportJSONStreamer.Create(Nil);
  198. try
  199. R.OwnsJSON:=False;
  200. R.JSON:=aJSON;
  201. WriteElement(R);
  202. finally
  203. R.Free;
  204. end;
  205. end;
  206. procedure TFPJSONReport.SaveRenderToJSON(aJSON: TJSONObject);
  207. Var
  208. R : TFPReportJSONStreamer;
  209. begin
  210. DoWriteJSON(aJSON);
  211. R:=TFPReportJSONStreamer.Create(Nil);
  212. try
  213. R.OwnsJSON:=False;
  214. R.JSON:=aJSON;
  215. WriteRTElement(R);
  216. finally
  217. R.Free;
  218. end;
  219. end;
  220. procedure TFPJSONReport.LoadFromStream(const aStream : TStream);
  221. Var
  222. D : TJSONData;
  223. begin
  224. D:=GetJSON(aStream);
  225. try
  226. if not (D is TJSONObject) then
  227. Raise EReportError.CreateFmt(SErrFailedToLoad,[SErrInvalidJSONData]);
  228. LoadFromJSON(D as TJSONObject);
  229. finally
  230. D.Free;
  231. end;
  232. end;
  233. procedure TFPJSONReport.SaveToStream(const aStream: TStream);
  234. Var
  235. O : TJSONObject;
  236. S : TJSONStringType;
  237. begin
  238. O:=TJSONObject.Create;
  239. try
  240. SaveToJSON(O);
  241. S:=O.AsJSON;
  242. aStream.WriteBuffer(S[1],Length(S));
  243. finally
  244. O.Free;
  245. end;
  246. end;
  247. procedure TFPJSONReport.SaveRenderToStream(const aStream: TStream);
  248. Var
  249. O : TJSONObject;
  250. S : TJSONStringType;
  251. begin
  252. O:=TJSONObject.Create;
  253. try
  254. SaveRendertoJSON(O);
  255. S:=O.AsJSON;
  256. aStream.WriteBuffer(S[1],Length(S));
  257. finally
  258. O.Free;
  259. end;
  260. end;
  261. procedure TFPJSONReport.LoadFromFile(const aFileName: String);
  262. Var
  263. F : TFileStream;
  264. begin
  265. F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  266. try
  267. LoadFromStream(F);
  268. finally
  269. F.Free;
  270. end;
  271. end;
  272. procedure TFPJSONReport.SaveToFile(const aFileName: String);
  273. Var
  274. F : TFileStream;
  275. begin
  276. F:=TFileStream.Create(aFileName,fmCreate);
  277. try
  278. SaveToStream(F);
  279. finally
  280. F.Free;
  281. end;
  282. end;
  283. procedure TFPJSONReport.SaveRenderToFile(const aFileName: String);
  284. Var
  285. F : TFileStream;
  286. begin
  287. F:=TFileStream.Create(aFileName,fmCreate);
  288. try
  289. SaveRenderToStream(F);
  290. finally
  291. F.Free;
  292. end;
  293. end;
  294. end.