/Source/FR_UTILS.PAS

http://github.com/FastReports/FreeReport · Pascal · 656 lines · 547 code · 60 blank · 49 comment · 59 complexity · 6adcca3113c23e3c3e1759e6a6ba0fc7 MD5 · raw file

  1. {*****************************************}
  2. { }
  3. { FastReport v2.3 }
  4. { Various routines }
  5. { }
  6. { Copyright (c) 1998-99 by Tzyganenko A. }
  7. { }
  8. {*****************************************}
  9. unit FR_Utils;
  10. interface
  11. {$I FR.inc}
  12. uses
  13. SysUtils, Windows, Messages, Classes, Graphics, Controls,
  14. FR_DBRel, Forms, StdCtrls, ClipBrd, Menus, FR_Class;
  15. procedure frReadMemo(Stream: TStream; l: TStrings);
  16. procedure frReadMemo22(Stream: TStream; l: TStrings);
  17. procedure frWriteMemo(Stream: TStream; l: TStrings);
  18. function frReadString(Stream: TStream): String;
  19. function frReadString22(Stream: TStream): String;
  20. procedure SaveToFR3Stream(Report: TfrReport; Stream: TStream);
  21. function StrToXML(const s: String): String;
  22. function frStreamToString(Stream: TStream): String;
  23. {$IFDEF FREEREP2217READ}
  24. function frReadString2217(Stream: TStream): String;
  25. {$ENDIF}
  26. procedure frWriteString(Stream: TStream; s: String);
  27. procedure frEnableControls(c: Array of TControl; e: Boolean);
  28. function frControlAtPos(Win: TWinControl; p: TPoint): TControl;
  29. function frGetDataSet(ComplexName: String): TfrTDataSet;
  30. procedure frGetDataSetAndField(ComplexName: String;
  31. var DataSet: TfrTDataSet; var Field: TfrTField);
  32. function frGetFontStyle(Style: TFontStyles): Integer;
  33. function frSetFontStyle(Style: Integer): TFontStyles;
  34. function frFindComponent(Owner: TComponent; Name: String): TComponent;
  35. procedure frGetComponents(Owner: TComponent; ClassRef: TClass;
  36. List: TStrings; Skip: TComponent);
  37. function frGetWindowsVersion: String;
  38. implementation
  39. uses FR_DSet, Printers;
  40. function frSetFontStyle(Style: Integer): TFontStyles;
  41. begin
  42. Result := [];
  43. if (Style and $1) <> 0 then Result := Result + [fsItalic];
  44. if (Style and $2) <> 0 then Result := Result + [fsBold];
  45. if (Style and $4) <> 0 then Result := Result + [fsUnderLine];
  46. end;
  47. function frGetFontStyle(Style: TFontStyles): Integer;
  48. begin
  49. Result := 0;
  50. if fsItalic in Style then Result := Result or $1;
  51. if fsBold in Style then Result := Result or $2;
  52. if fsUnderline in Style then Result := Result or $4;
  53. end;
  54. procedure RemoveQuotes(var s: String);
  55. begin
  56. if (s[1] = '"') and (s[Length(s)] = '"') then
  57. s := Copy(s, 2, Length(s) - 2);
  58. end;
  59. procedure frReadMemo(Stream: TStream; l: TStrings);
  60. var
  61. s: String;
  62. b: Byte;
  63. n: Word;
  64. begin
  65. l.Clear;
  66. Stream.Read(n, 2);
  67. if n > 0 then
  68. repeat
  69. Stream.Read(n, 2);
  70. SetLength(s, n);
  71. Stream.Read(s[1], n);
  72. l.Add(s);
  73. Stream.Read(b, 1);
  74. until b = 0
  75. else
  76. Stream.Read(b, 1);
  77. end;
  78. procedure frWriteMemo(Stream: TStream; l: TStrings);
  79. var
  80. s: String;
  81. i: Integer;
  82. n: Word;
  83. b: Byte;
  84. begin
  85. n := l.Count;
  86. Stream.Write(n, 2);
  87. for i := 0 to l.Count - 1 do
  88. begin
  89. s := l[i];
  90. n := Length(s);
  91. Stream.Write(n, 2);
  92. Stream.Write(s[1], n);
  93. b := 13;
  94. if i <> l.Count - 1 then Stream.Write(b, 1);
  95. end;
  96. b := 0;
  97. Stream.Write(b, 1);
  98. end;
  99. function frReadString(Stream: TStream): String;
  100. var
  101. s: String;
  102. n: Word;
  103. b: Byte;
  104. begin
  105. Stream.Read(n, 2);
  106. SetLength(s, n);
  107. Stream.Read(s[1], n);
  108. Stream.Read(b, 1);
  109. Result := s;
  110. end;
  111. procedure frWriteString(Stream: TStream; s: String);
  112. var
  113. b: Byte;
  114. n: Word;
  115. begin
  116. n := Length(s);
  117. Stream.Write(n, 2);
  118. Stream.Write(s[1], n);
  119. b := 0;
  120. Stream.Write(b, 1);
  121. end;
  122. procedure frReadMemo22(Stream: TStream; l: TStrings);
  123. var
  124. s: String;
  125. i: Integer;
  126. b: Byte;
  127. begin
  128. SetLength(s, 4096);
  129. l.Clear;
  130. i := 1;
  131. repeat
  132. Stream.Read(b,1);
  133. if (b = 13) or (b = 0) then
  134. begin
  135. SetLength(s, i - 1);
  136. if not ((b = 0) and (i = 1)) then l.Add(s);
  137. SetLength(s, 4096);
  138. i := 1;
  139. end
  140. else if b <> 0 then
  141. begin
  142. s[i] := Chr(b);
  143. Inc(i);
  144. if i > 4096 then
  145. SetLength(s, Length(s) + 4096);
  146. end;
  147. until b = 0;
  148. end;
  149. function frReadString22(Stream: TStream): String;
  150. var
  151. s: String;
  152. i: Integer;
  153. b: Byte;
  154. begin
  155. SetLength(s, 4096);
  156. i := 1;
  157. repeat
  158. Stream.Read(b, 1);
  159. if b = 0 then
  160. SetLength(s, i - 1)
  161. else
  162. begin
  163. s[i] := Chr(b);
  164. Inc(i);
  165. if i > 4096 then
  166. SetLength(s, Length(s) + 4096);
  167. end;
  168. until b = 0;
  169. Result := s;
  170. end;
  171. {$IFDEF FREEREP2217READ}
  172. function frReadString2217(Stream: TStream): String;
  173. var
  174. I: Integer;
  175. begin
  176. Stream.ReadBuffer(I, SizeOf(I));
  177. SetLength(Result, I);
  178. Stream.ReadBuffer(PChar(Result)^, I);
  179. end;
  180. {$ENDIF}
  181. type
  182. THackWinControl = class(TWinControl)
  183. end;
  184. procedure frEnableControls(c: Array of TControl; e: Boolean);
  185. const
  186. Clr1: Array[Boolean] of TColor = (clGrayText,clWindowText);
  187. Clr2: Array[Boolean] of TColor = (clBtnFace,clWindow);
  188. var
  189. i: Integer;
  190. begin
  191. for i := Low(c) to High(c) do
  192. if c[i] is TLabel then
  193. with c[i] as TLabel do
  194. begin
  195. Font.Color := Clr1[e];
  196. Enabled := e;
  197. end
  198. else if c[i] is TWinControl then
  199. with THackWinControl(c[i]) do
  200. begin
  201. Color := Clr2[e];
  202. Enabled := e;
  203. end;
  204. end;
  205. function frControlAtPos(Win: TWinControl; p: TPoint): TControl;
  206. var
  207. i: Integer;
  208. c: TControl;
  209. p1: TPoint;
  210. begin
  211. Result := nil;
  212. with Win do
  213. begin
  214. for i := ControlCount - 1 downto 0 do
  215. begin
  216. c := Controls[i];
  217. if c.Visible and PtInRect(Rect(c.Left, c.Top, c.Left + c.Width, c.Top + c.Height), p) then
  218. if (c is TWinControl) and (csAcceptsControls in c.ControlStyle) and
  219. (TWinControl(c).ControlCount > 0) then
  220. begin
  221. p1 := p;
  222. Dec(p1.X, c.Left); Dec(p1.Y, c.Top);
  223. c := frControlAtPos(TWinControl(c), p1);
  224. if c <> nil then
  225. begin
  226. Result := c;
  227. Exit;
  228. end;
  229. end
  230. else
  231. begin
  232. Result := c;
  233. Exit;
  234. end;
  235. end;
  236. end;
  237. end;
  238. function frGetDataSet(ComplexName: String): TfrTDataSet;
  239. begin
  240. Result := TfrTDataSet(frFindComponent(CurReport.Owner, ComplexName));
  241. end;
  242. procedure frGetDataSetAndField(ComplexName: String; var DataSet: TfrTDataSet;
  243. var Field: TfrTField);
  244. var
  245. n: Integer;
  246. f: TComponent;
  247. s1, s2, s3: String;
  248. begin
  249. Field := nil;
  250. f := CurReport.Owner;
  251. n := Pos('.', ComplexName);
  252. if n <> 0 then
  253. begin
  254. s1 := Copy(ComplexName, 1, n - 1); // table name
  255. s2 := Copy(ComplexName, n + 1, 255); // field name
  256. if Pos('.', s2) <> 0 then // module name present
  257. begin
  258. s3 := Copy(s2, Pos('.', s2) + 1, 255);
  259. s2 := Copy(s2, 1, Pos('.', s2) - 1);
  260. f := FindGlobalComponent(s1);
  261. if f <> nil then
  262. begin
  263. DataSet := TfrTDataSet(f.FindComponent(s2));
  264. RemoveQuotes(s3);
  265. if DataSet <> nil then
  266. Field := TfrTField(DataSet.FindField(s3));
  267. end;
  268. end
  269. else
  270. begin
  271. DataSet := TfrTDataSet(frFindComponent(f, s1));
  272. RemoveQuotes(s2);
  273. if DataSet <> nil then
  274. Field := TfrTField(DataSet.FindField(s2));
  275. end;
  276. end
  277. else if DataSet <> nil then
  278. begin
  279. RemoveQuotes(ComplexName);
  280. Field := TfrTField(DataSet.FindField(ComplexName));
  281. end;
  282. end;
  283. function frFindComponent(Owner: TComponent; Name: String): TComponent;
  284. var
  285. n: Integer;
  286. s1, s2: String;
  287. begin
  288. Result := nil;
  289. n := Pos('.', Name);
  290. try
  291. if n = 0 then
  292. Result := Owner.FindComponent(Name)
  293. else
  294. begin
  295. s1 := Copy(Name, 1, n - 1); // module name
  296. s2 := Copy(Name, n + 1, 255); // component name
  297. Owner := FindGlobalComponent(s1);
  298. if Owner <> nil then
  299. Result := Owner.FindComponent(s2);
  300. end;
  301. except
  302. on Exception do
  303. raise EClassNotFound.Create('Îòñóòñòâóåò ' + Name);
  304. end;
  305. end;
  306. procedure frGetComponents(Owner: TComponent; ClassRef: TClass;
  307. List: TStrings; Skip: TComponent);
  308. var
  309. i: Integer;
  310. procedure EnumComponents(f: TComponent);
  311. var
  312. i: Integer;
  313. c: TComponent;
  314. begin
  315. for i := 0 to f.ComponentCount - 1 do
  316. begin
  317. c := f.Components[i];
  318. if (c <> Skip) and (c is ClassRef) then
  319. if f = Owner then
  320. List.Add(c.Name) else
  321. List.Add(f.Name + '.' + c.Name);
  322. end;
  323. end;
  324. begin
  325. List.Clear;
  326. for i := 0 to Screen.FormCount - 1 do
  327. EnumComponents(Screen.Forms[i]);
  328. for i := 0 to Screen.DataModuleCount - 1 do
  329. EnumComponents(Screen.DataModules[i]);
  330. end;
  331. function frGetWindowsVersion: String;
  332. var Ver: TOsVersionInfo;
  333. begin
  334. Ver.dwOSVersionInfoSize := SizeOf(Ver);
  335. GetVersionEx(Ver);
  336. with Ver do begin
  337. case dwPlatformId of
  338. VER_PLATFORM_WIN32s: Result := '32s';
  339. VER_PLATFORM_WIN32_WINDOWS:
  340. begin
  341. dwBuildNumber := dwBuildNumber and $0000FFFF;
  342. if (dwMajorVersion > 4) or ((dwMajorVersion = 4) and
  343. (dwMinorVersion >= 10)) then
  344. Result := '98' else
  345. Result := '95';
  346. end;
  347. VER_PLATFORM_WIN32_NT: Result := 'NT';
  348. end;
  349. end;
  350. end;
  351. procedure SaveToFR3Stream(Report: TfrReport; Stream: TStream);
  352. const
  353. fr01cm = 3.77953; // 96 / 25.4
  354. frKx = 96 / (93 / 1.015); // convert from 2.4 units to 3.0 units
  355. procedure WriteStr(const s: String);
  356. begin
  357. Stream.Write(s[1], Length(s));
  358. end;
  359. procedure WriteLn(const s: String);
  360. begin
  361. WriteStr(s + #13#10);
  362. end;
  363. function EncodePwd(const s: String): String;
  364. var
  365. i: Integer;
  366. begin
  367. Result := '';
  368. for i := 1 to Length(s) do
  369. Result := Result + Chr(Ord(s[i]) - 10);
  370. end;
  371. procedure WriteReportProp;
  372. procedure WriteScript;
  373. var
  374. i, j: Integer;
  375. Page: TfrPage;
  376. v: TfrView;
  377. Script: TStringList;
  378. procedure AddScript(const vName: String; vScript: TStrings);
  379. var
  380. i: Integer;
  381. begin
  382. if vScript.Count <> 0 then
  383. begin
  384. Script.Add('procedure ' + vName + 'OnBeforePrint(Sender: TfrxComponent);');
  385. Script.Add('begin');
  386. Script.Add(' with ' + vName + ', Engine do');
  387. Script.Add(' begin');
  388. if vScript[0] <> 'begin' then
  389. Script.Add(vScript[0]);
  390. for i := 1 to vScript.Count - 2 do
  391. Script.Add(vScript[i]);
  392. if vScript[0] <> 'begin' then
  393. begin
  394. if vScript.Count <> 1 then
  395. Script.Add(vScript[vScript.Count - 1]);
  396. Script.Add(' end');
  397. Script.Add('end;');
  398. end
  399. else
  400. begin
  401. Script.Add(' end');
  402. Script.Add(vScript[vScript.Count - 1] + ';');
  403. end;
  404. Script.Add('');
  405. end;
  406. end;
  407. begin
  408. Script := TStringList.Create;
  409. for i := 0 to Report.Pages.Count - 1 do
  410. begin
  411. Page := Report.Pages[i];
  412. // AddScript('Page' + IntToStr(i + 1), Page.Script);
  413. for j := 0 to Page.Objects.Count - 1 do
  414. begin
  415. v := Page.Objects[j];
  416. AddScript(v.Name, v.Script);
  417. end;
  418. end;
  419. Script.Add('begin');
  420. Script.Add('');
  421. Script.Add('end.');
  422. WriteStr(StrToXML(Script.Text) + '" ');
  423. Script.Free;
  424. end;
  425. procedure WriteVariables;
  426. var
  427. i: Integer;
  428. wr: TWriter;
  429. ms: TMemoryStream;
  430. v: TValueType;
  431. varName, varValue: String;
  432. dsList: TStringList;
  433. begin
  434. ms := TMemoryStream.Create;
  435. wr := TWriter.Create(ms, 4096);
  436. dsList := TStringList.Create;
  437. frGetComponents(Report.Owner, TfrDataset, dsList, nil);
  438. v := vaCollection;
  439. wr.WriteStr('Datasets');
  440. wr.Write(v, SizeOf(v));
  441. for i := 0 to dsList.Count - 1 do
  442. begin
  443. // varName := TfrDataset(dsList.Objects[i]).Name;
  444. varName := dsList.Strings[i];
  445. wr.WriteListBegin;
  446. wr.WriteStr('DataSet');
  447. v := vaNil;
  448. wr.Write(v, SizeOf(v));
  449. wr.WriteStr('DataSetName');
  450. wr.WriteString(varName);
  451. wr.WriteListEnd;
  452. end;
  453. wr.WriteListEnd;
  454. wr.WriteStr('Variables');
  455. wr.Write(v, SizeOf(v));
  456. for i := 0 to Report.Variables.Count - 1 do
  457. begin
  458. varName := Report.Variables.Names[i];
  459. varValue := Report.Variables.Values[varName];
  460. { ds := nil;
  461. fld := '';
  462. frGetDatasetAndField(varValue, ds, fld);
  463. if (ds <> nil) and (fld <> '') then
  464. begin
  465. dsFound := nil;
  466. for j := 0 to dsList.Count - 1 do
  467. if TObject(dsList.Objects[j]) is TfrDBDataSet then
  468. if TfrDBDataset(dsList.Objects[j]).GetDataSet = ds then
  469. begin
  470. dsFound := TfrDataset(dsList.Objects[j]);
  471. break;
  472. end;
  473. if dsFound <> nil then
  474. begin
  475. s := dsFound.Name;
  476. if Pos('_', s) = 1 then
  477. s := Copy(s, 2, 255);
  478. varValue := '<' + s + '."' + fld + '">';
  479. end;
  480. end;
  481. }
  482. wr.WriteListBegin;
  483. wr.WriteStr('Name');
  484. wr.WriteString(varName);
  485. wr.WriteStr('Value');
  486. wr.WriteString(varValue);
  487. wr.WriteListEnd;
  488. end;
  489. wr.WriteListEnd;
  490. wr.Free;
  491. WriteStr('Propdata="' + frStreamToString(ms) + '"');
  492. ms.Free;
  493. dsList.Free;
  494. end;
  495. begin
  496. WriteStr('<TfrxReport ScriptLanguage="PascalScript" ScriptText.text="');
  497. WriteScript;
  498. WriteVariables;
  499. // WriteStr(' ReportOptions.Name="' + {StrToXML(Report.ReportName)}' ' +
  500. // '" ReportOptions.Author="' + {StrToXML(Report.ReportAutor)}' ' +
  501. // '" ReportOptions.Description.text="' + {StrToXML(Report.ReportComment)}' ' +
  502. // '" ReportOptions.CreateDate="' + {FloatToStr(Report.ReportCreateDate)}' ' +
  503. // '" ReportOptions.LastChange="' + {FloatToStr(Report.ReportLastChange)}' ' +
  504. // '" ReportOptions.VersionMajor="' + {StrToXML(Report.ReportVersionMajor)}' ' +
  505. // '" ReportOptions.VersionMinor="' + {StrToXML(Report.ReportVersionMinor)}' ' +
  506. // '" ReportOptions.VersionRelease="' + {StrToXML(Report.ReportVersionRelease)}' ' +
  507. // '" ReportOptions.VersionBuild="' + {StrToXML(Report.ReportVersionBuild)}' ' +
  508. // '" ReportOptions.Password="' + {StrToXML(EncodePwd(Report.ReportPassword))}''+ '"');
  509. WriteLn('>');
  510. end;
  511. procedure WritePages;
  512. var
  513. i, j, ofx, savex: Integer;
  514. Page: TfrPage;
  515. v: TfrView;
  516. procedure WritePageProp(Page: TfrPage; const PageName: String);
  517. var
  518. s: String;
  519. begin
  520. ofx := 0;
  521. if Page.pgOr = poPortrait then
  522. s := 'poPortrait' else
  523. s := 'poLandscape';
  524. WriteStr('<TfrxReportPage Name="' + PageName + '" ');
  525. WriteStr('Orientation="' + s +
  526. '" PaperWidth="' + IntToStr(Round(Page.prnInfo.PgW / fr01cm * frKx)) +
  527. '" PaperHeight="' + IntToStr(Round(Page.prnInfo.PgH / fr01cm * frKx)) +
  528. '" PaperSize="' + IntToStr(Page.pgSize) + '" ');
  529. WriteStr('LeftMargin="' + IntToStr(Round(Page.LeftMargin / fr01cm * frKx)) +
  530. '" RightMargin="' + IntToStr(Round((Page.prnInfo.PgW - Page.RightMargin) / fr01cm * frKx)) +
  531. '" TopMargin="' + IntToStr(Round(Page.TopMargin / fr01cm * frKx)) +
  532. '" BottomMargin="' + IntToStr(Round((Page.prnInfo.PgH - Page.BottomMargin) / fr01cm * frKx)) +
  533. '" Columns="' + IntToStr(Page.ColCount) +
  534. '" ColumnWidth="' + IntToStr(Page.ColWidth) + '"');
  535. if Page.PrintToPrevPage then
  536. WriteStr(' PrintOnPreviousPage="True"');
  537. // if Page.Script.Count > 0 then
  538. // WriteStr(' OnBeforePrint="' + PageName + 'OnBeforePrint"');
  539. ofx := -Page.LeftMargin;
  540. if Page.Objects.Count = 0 then
  541. WriteLn('/>') else
  542. WriteLn('>');
  543. end;
  544. begin
  545. for i := 0 to Report.Pages.Count - 1 do
  546. begin
  547. Page := Report.Pages[i];
  548. WritePageProp(Page, 'Page' + IntToStr(i + 1));
  549. for j := 0 to Page.Objects.Count - 1 do
  550. begin
  551. v := Page.Objects[j];
  552. savex := v.x;
  553. v.x := v.x + ofx;
  554. v.SaveToFR3Stream(Stream);
  555. v.x := savex;
  556. WriteLn('/>');
  557. end;
  558. if Page.Objects.Count <> 0 then
  559. WriteLn('</TfrxReportPage>')
  560. end;
  561. end;
  562. begin
  563. WriteLn('<?xml version="1.0" encoding="utf-8"?>');
  564. WriteReportProp;
  565. WritePages;
  566. WriteLn('</TfrxReport>');
  567. end;
  568. function StrToXML(const s: String): String;
  569. const
  570. SpecChars = ['<', '>', '"', #10, #13];
  571. var
  572. i: Integer;
  573. procedure ReplaceChars(var s: String; i: Integer);
  574. begin
  575. Insert('#' + IntToStr(Ord(s[i])) + ';', s, i + 1);
  576. s[i] := '&';
  577. end;
  578. begin
  579. Result := s;
  580. for i := Length(s) downto 1 do
  581. if s[i] in SpecChars then
  582. ReplaceChars(Result, i);
  583. end;
  584. function frStreamToString(Stream: TStream): String;
  585. var
  586. b: Byte;
  587. begin
  588. Result := '';
  589. Stream.Position := 0;
  590. while Stream.Position < Stream.Size do
  591. begin
  592. Stream.Read(b, 1);
  593. Result := Result + IntToHex(b, 2);
  594. end;
  595. end;
  596. end.