fpdatasetform.pp 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289
  1. {
  2. $Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit fpdatasetform;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, fphtml, htmldefs, htmlwriter, db, htmlelements;
  16. type
  17. THTMLDatasetFormProducer = class;
  18. TFormFieldItem = class;
  19. TFormButtonItem = class;
  20. TFieldCellEvent = procedure (Sender:THTMLDatasetFormProducer; FieldDef:TFormFieldItem;
  21. IsLabel:boolean; Cell : THTMLCustomelement) of object;
  22. TButtonEvent = procedure (Sender:THTMLDatasetFormProducer; ButtonDef:TFormButtonItem;
  23. Button : THTMLAttrsElement) of object;
  24. TProducerEvent = procedure (Sender:THTMLDatasetFormProducer; FieldDef:TFormFieldItem;
  25. Producer:THTMLContentProducer) of object;
  26. THTMLElementEvent = procedure (Sender:THTMLDatasetFormProducer; element : THTMLCustomElement) of object;
  27. TFieldCheckEvent = procedure (aField:TField; var check:boolean) of object;
  28. TFieldItemEvent = procedure (Sender:TFormFieldItem; var aValue : string) of object;
  29. TFormInputType = (fittext,fitpassword,fitcheckbox,fitradio,fitfile,fithidden,
  30. fitproducer,fittextarea,fitrecordselection,fitlabel);
  31. { TTablePosition }
  32. TTablePosition = class (TPersistent)
  33. private
  34. FAlignHor: THTMLalign;
  35. FAlignVer: THTMLvalign;
  36. FColSpan: integer;
  37. FLeft: integer;
  38. FRowSpan: integer;
  39. FTop: integer;
  40. protected
  41. procedure AssignTo(Dest: TPersistent); override;
  42. public
  43. constructor create;
  44. published
  45. property Left : integer read FLeft write FLeft;
  46. property Top : integer read FTop write FTop;
  47. property ColSpan : integer read FColSpan write FColSpan default 1;
  48. property RowSpan : integer read FRowSpan write FRowSpan default 1;
  49. property AlignVertical : THTMLvalign read FAlignVer write FAlignVer default vaEmpty;
  50. property AlignHorizontal : THTMLalign read FAlignHor write FAlignHor default alEmpty;
  51. end;
  52. { TFormFieldItem }
  53. TFormFieldItem = class (TCollectionItem)
  54. private
  55. FAction: string;
  56. FField: TField;
  57. FFieldName: string;
  58. FInputType: TFormInputType;
  59. FLabelCaption: string;
  60. FLabelAbove : boolean;
  61. FLabelPos: TTablePosition;
  62. FProducer: THTMLContentProducer;
  63. FValuePos: TTablePosition;
  64. FName : String;
  65. FOnGetValue: TFieldItemEvent;
  66. FOnGetLabel: TFieldItemEvent;
  67. FOnGetAction: TFieldItemEvent;
  68. procedure SetLabelPos(const AValue: TTablePosition);
  69. procedure SetValuePos(const AValue: TTablePosition);
  70. protected
  71. procedure AssignTo(Dest: TPersistent); override;
  72. Function GetDisplayName : String; override;
  73. Procedure SetDisplayName(AValue : String);
  74. public
  75. constructor Create(ACollection: TCollection); override;
  76. destructor Destroy; override;
  77. function getValue : String; virtual;
  78. function getLabel : String; virtual;
  79. function getAction : String; virtual;
  80. property Field : TField read FField;
  81. published
  82. Property Name : String Read GetDisplayName Write SetDisplayName;
  83. property Fieldname : string read FFieldName write FFieldname;
  84. // the field to show/edit
  85. property LabelCaption : string read FLabelCaption write FLabelCaption;
  86. // the text to show for the control
  87. property LabelPos : TTablePosition read FLabelPos write SetLabelPos;
  88. // place of the label in the table-grid
  89. property LabelAbove : boolean read FLabelAbove write FLabelAbove default false;
  90. // if not SeparateLabel then place a <BR> between label and edit/value
  91. property ValuePos : TTablePosition read FValuePos write SetValuePos;
  92. // place of the value in the table-grid
  93. { only when editting: }
  94. property InputType : TFormInputType read FInputType write FInputType default fittext;
  95. // the type of form control to use
  96. property Producer : THTMLContentProducer read FProducer write FProducer;
  97. // the producer to include when generating the value
  98. { only when showing: }
  99. property Action : string read FAction write FAction;
  100. // the link to include in the value
  101. property OnGetValue : TFieldItemEvent read FOnGetValue write FOnGetValue;
  102. property OnGetLabel : TFieldItemEvent read FOnGetLabel write FOnGetLabel;
  103. property OnGetAction : TFieldItemEvent read FOnGetAction write FOnGetAction;
  104. end;
  105. { TFormFieldCollection }
  106. TFormFieldCollection = class (TCollection)
  107. private
  108. function GetItem(index : integer): TFormFieldItem;
  109. procedure SetItem(index : integer; const AValue: TFormFieldItem);
  110. public
  111. constructor create;
  112. function AddField (afieldname, acaption : string) : TFormFieldItem;
  113. Function FindItem(AName : String): TFormFieldItem;
  114. Function IndexofItem(AName : String) : Integer;
  115. property Items [index : integer] : TFormFieldItem read GetItem write SetItem;
  116. end;
  117. TFormButtonType = (fbtSubmit, fbtReset, fbtPushbutton, fbtInputSubmit,fbtInputReset,fbtInputPushButton);
  118. TImagePlace = (ipOnly, ipBefore, ipAfter, ipUnder, ipAbove);
  119. { TFormButtonItem }
  120. TFormButtonItem = class (TCollectionItem)
  121. private
  122. FButtonType: TFormButtonType;
  123. FCaption: string;
  124. FImage: string;
  125. FName: string;
  126. FImagePlace: TImagePlace;
  127. FValue: string;
  128. protected
  129. procedure AssignTo(Dest: TPersistent); override;
  130. public
  131. constructor create (ACollection : TCollection); override;
  132. published
  133. property Name : string read FName write FName;
  134. property Value : string read FValue write FValue;
  135. property Caption : string read FCaption write FCaption;
  136. // Text on button, or as hint with image
  137. property Image : string read FImage write FImage;
  138. // Image to show on the button
  139. property ImagePlace : TImagePlace read FImagePlace write FImagePlace;
  140. // where the image is placed regarding from the caption.
  141. // if ipOnly; the caption is placed in the alternate text of the image (hint)
  142. property ButtonType : TFormButtonType read FButtonType write FButtonType default fbtPushButton;
  143. // Where the button is used for
  144. end;
  145. { TFormButtonCollection }
  146. TFormButtonCollection = class (TCollection)
  147. private
  148. function GetItem(index : integer): TFormButtonItem;
  149. procedure SetItem(index : integer; const AValue: TFormButtonItem);
  150. public
  151. constructor create;
  152. function AddButton (aname, avalue, acaption : string) : TFormButtonItem;
  153. function AddButton (aname, acaption : string) : TFormButtonItem;
  154. function AddButton (acaption : string) : TFormButtonItem;
  155. property Items [index : integer] : TFormButtonItem read GetItem write SetItem;
  156. end;
  157. TCellType = (ctEmpty, ctInput, ctLabel, ctProducer, ctSpanned);
  158. { TTableCell }
  159. TTableCell = class (TCollectionItem)
  160. private
  161. FAlignHor: THTMLalign;
  162. FAlignVer: THTMLvalign;
  163. FCaption: string;
  164. FCellType: TCellType;
  165. FChecked: boolean;
  166. FDisabled: boolean;
  167. FColSpan: integer;
  168. FEndRow: boolean;
  169. FFormField: TFormFieldItem;
  170. FIncludeBreak: boolean;
  171. FInputType: TFormInputType;
  172. FIsLabel: boolean;
  173. FLink: string;
  174. FMaxLength: integer;
  175. FName: string;
  176. FProducer: THTMLContentProducer;
  177. FRowSpan: integer;
  178. FSize: integer;
  179. FSpanned: boolean;
  180. FValue: string;
  181. procedure WriteLabel(aWriter: THTMLWriter);
  182. public
  183. function WriteContent (aWriter : THTMLWriter) : THTMLCustomElement;
  184. function WriteHeader (aWriter : THTMLWriter) : THTMLCustomElement;
  185. property FormField : TFormFieldItem read FFormField write FFormField;
  186. // field definition that origintated this cell
  187. property IsLabel : boolean read FIsLabel write FIsLabel;
  188. // Label or Value ?
  189. property Caption : string read FCaption write FCaption;
  190. // label to place with the edit/value if not separateLabel
  191. property IncludeBreak : boolean read FIncludeBreak write FIncludeBreak;
  192. // place <br> between label and edit/value if label is included in cell
  193. property CellType : TCellType read FCellType write FCellType;
  194. { Cell properties: }
  195. property ColSpan : integer read FColSpan write FColSpan;
  196. property RowSpan : integer read FRowSpan write FRowSpan;
  197. property AlignVertical : THTMLvalign read FAlignVer write FAlignVer default vaEmpty;
  198. property AlignHorizontal : THTMLalign read FAlignHor write FAlignHor default alEmpty;
  199. property Value : string read FValue write FValue;
  200. // Contains the text for labels, or the value for input, or unused for producer and empty
  201. { properties to correctly generate the rows and the table ends }
  202. property EndOfRow : boolean read FEndRow write FEndRow;
  203. property SpannedOut : boolean read FSpanned write FSpanned;
  204. { only for input: }
  205. property Name : string read FName write FName;
  206. // name of the control
  207. property InputType : TFormInputType read FInputType write FInputType;
  208. // type of the input element
  209. property Size : integer read FSize write FSize;
  210. // size of text input element
  211. property MaxLength : integer read FMaxLength write FMaxLength;
  212. // MaxLength of text input element
  213. property Checked : boolean read FChecked write FChecked;
  214. // checked or not for radio,checkbox
  215. property Disabled : boolean read FDisabled write FDisabled;
  216. // disabled or not for radio,checkbox
  217. { only for labels: }
  218. property Link : string read FLink write FLink;
  219. // link to place around the text
  220. { only for producers: }
  221. property Producer : THTMLContentProducer read FProducer write FProducer;
  222. // producer to include
  223. end;
  224. { TTableDef }
  225. TTableDef = class (TCollection)
  226. private
  227. fCols, fRows : integer;
  228. function GetCell(x, y : integer): TTableCell;
  229. function GetItem(index: integer): TTableCell;
  230. public
  231. Constructor Create (acols, arows : integer);
  232. function CopyTablePosition (position : TTablePosition) : TTableCell;
  233. property Cells [x,y : integer] : TTableCell read GetCell; default;
  234. property items [index:integer] : TTableCell read GetItem;
  235. end;
  236. TButtonVerPosition = (bvpTop, bvpBottom);
  237. TButtonVerPositionSet = set of TButtonVerPosition;
  238. TButtonHorPosition = (bhpLeft, bhpCenter, bhpJustify, bhpRight);
  239. TFormMethod = (fmNone, fmGet, fmPost);
  240. { THTMLDatasetFormProducer }
  241. THTMLDatasetFormProducer = class (THTMLContentProducer)
  242. private
  243. FOnInitializeProducer : TProducerEvent;
  244. FOnFieldChecked : TFieldCheckEvent;
  245. FAfterTBodyCreate,
  246. FAfterTableCreate : THTMLElementEvent;
  247. FAfterButtonCreate: TButtonEvent;
  248. FAfterCellCreate: TFieldCellEvent;
  249. Fbuttonrow: TFormButtonCollection;
  250. FButtonsHor: TButtonHorPosition;
  251. FButtonsVer: TButtonVerPositionSet;
  252. FControls: TFormFieldCollection;
  253. FDatasource: TDatasource;
  254. FFormAction: string;
  255. FFormMethod: TFormMethod;
  256. FIncludeHeader: boolean;
  257. FSeparateLabel: boolean;
  258. FTableCols: integer;
  259. FTableRows: integer;
  260. FTableDef : TTableDef;
  261. FPage: integer;
  262. FRecordsPerPage: integer;
  263. procedure SetIncludeHeader(const AValue: boolean);
  264. procedure SetSeparateLabel(const AValue: boolean);
  265. procedure WriteButtons (aWriter : THTMLWriter);
  266. procedure WriteTableDef (aWriter : THTMLWriter);
  267. procedure WriteHeaderTableDef (aWriter : THTMLWriter);
  268. procedure CorrectCellSpans;
  269. procedure SearchControlFields;
  270. protected
  271. function WriteContent (aWriter : THTMLWriter) : THTMLCustomElement; override;
  272. procedure FillTableDef (IsHeader:boolean); virtual;
  273. procedure ControlToTableDef (aControldef : TFormFieldItem; IsHeader:boolean); virtual; abstract;
  274. function StartForm (aWriter : THTMLWriter) : THTMLCustomElement; virtual;
  275. procedure EndForm (aWriter : THTMLWriter); virtual;
  276. property TableDef : TTableDef read FTableDef;
  277. function SingleRecord : boolean; dynamic;
  278. // generate form for 1 record or for the selected pages
  279. property RecordsPerPage : integer read FRecordsPerPage write FRecordsPerPage default 20;
  280. // number of records to show
  281. property Page : integer read FPage write FPage default -1;
  282. // page to show. -1 shows all records. zero based
  283. property IncludeHeader : boolean read FIncludeHeader write SetIncludeHeader;
  284. // create a header cell for each control
  285. public
  286. constructor create (aOwner : TComponent); override;
  287. destructor destroy; override;
  288. published
  289. property FormAction : string read FFormAction write FFormAction;
  290. // action of the form (link), if not given; don't use a form element
  291. property FormMethod : TFormMethod read FFormMethod write FFormMethod;
  292. // method of the form, Get or Post
  293. Property DataSource : TDataSource read FDataSource write FDataSource;
  294. // the data to use
  295. property Controls : TFormFieldCollection read FControls write FControls;
  296. // configuration of the fields and how to generate the html
  297. property SeparateLabel : boolean read FSeparateLabel write SetSeparateLabel;
  298. // place label and value/edit in same table cell
  299. property buttonrow : TFormButtonCollection read Fbuttonrow write Fbuttonrow;
  300. // buttons to place in the form
  301. property TableCols : integer read FTableCols write FTableCols default 2;
  302. // number columns in the grid for 1 record
  303. property TableRows : integer read FTableRows write FTableRows;
  304. // number of rows in the grid for 1 record
  305. property ButtonsHorizontal : TButtonHorPosition read FButtonsHor write FButtonsHor default bhpleft;
  306. // where to place the buttons horizontally
  307. property ButtonsVertical : TButtonVerPositionSet read FButtonsVer write FButtonsVer default [bvpTop,bvpBottom];
  308. // where to place the buttons vertically
  309. property OnInitializeProducer : TProducerEvent read FOnInitializeProducer write FOnInitializeProducer;
  310. // Called before the producer creates it's HTML code
  311. property AfterCellCreate : TFieldCellEvent read FAfterCellCreate write FAfterCellCreate;
  312. // Called after each creation of a cell in the table makeup in the form
  313. property AfterButtonCreate : TButtonEvent read FAfterButtonCreate write FAfterButtonCreate;
  314. // Called after each creation of a button
  315. property AfterTableCreate : THTMLElementEvent read FAfterTableCreate write FAfterTableCreate;
  316. // Called after the creation of the table
  317. property AfterTBodyCreate : THTMLElementEvent read FAfterTBodyCreate write FAfterTBodyCreate;
  318. // Called after finishing the tbody of each record
  319. property OnFieldChecked : TFieldCheckEvent read FOnFieldChecked write FOnFieldChecked;
  320. // return if the field is true or false if the false string differs from '0','false','-'
  321. end;
  322. { THTMLDatasetFormEditProducer }
  323. THTMLDatasetFormEditProducer = class (THTMLDatasetFormProducer)
  324. procedure ControlToTableDef (aControldef : TFormFieldItem; IsHeader:boolean); override;
  325. end;
  326. { THTMLDatasetFormShowProducer }
  327. THTMLDatasetFormShowProducer = class (THTMLDatasetFormProducer)
  328. protected
  329. procedure ControlToTableDef (aControldef : TFormFieldItem; IsHeader:boolean); override;
  330. end;
  331. { THTMLDatasetFormGridProducer }
  332. THTMLDatasetFormGridProducer = class (THTMLDatasetFormProducer)
  333. protected
  334. procedure ControlToTableDef (aControldef : TFormFieldItem; IsHeader:boolean); override;
  335. function SingleRecord : boolean; override;
  336. public
  337. constructor Create (aOwner : TComponent); override;
  338. published
  339. property RecordsPerPage;
  340. property Page;
  341. property IncludeHeader;
  342. end;
  343. implementation
  344. { TTableDef }
  345. function TTableDef.GetItem(index: integer): TTableCell;
  346. begin
  347. result := TTableCell (inherited items[index]);
  348. end;
  349. function TTableDef.GetCell(x, y : integer): TTableCell;
  350. var r : integer;
  351. begin
  352. r := x + (y * fcols);
  353. result := getItem (r);
  354. end;
  355. constructor TTableDef.Create(acols, arows: integer);
  356. var r, t : integer;
  357. begin
  358. inherited create (TTableCell);
  359. fRows := aRows;
  360. fCols := aCols;
  361. for r := 1 to aRows do
  362. begin
  363. for t := 1 to aCols-1 do
  364. Add;
  365. TTableCell(Add).EndOfRow := True;
  366. end;
  367. end;
  368. function TTableDef.CopyTablePosition(position: TTablePosition): TTableCell;
  369. begin
  370. result := Cells[position.left,position.top];
  371. with result do
  372. begin
  373. AlignHorizontal := position.AlignHorizontal;
  374. AlignVertical := position.FAlignVer;
  375. ColSpan := position.ColSpan;
  376. RowSpan := position.RowSpan;
  377. end;
  378. end;
  379. { TTablePosition }
  380. procedure TTablePosition.AssignTo(Dest: TPersistent);
  381. begin
  382. inherited AssignTo(Dest);
  383. if dest is TTablePosition then
  384. with TTablePosition(Dest) do
  385. begin
  386. FTop := self.FTop;
  387. FLeft := self.FLeft;
  388. FColSpan := self.FColSpan;
  389. FRowSpan := self.FRowSpan;
  390. FAlignVer := self.FAlignVer;
  391. FalignHor := self.FAlignHor;
  392. end;
  393. end;
  394. constructor TTablePosition.create;
  395. begin
  396. inherited create;
  397. FColSpan := 1;
  398. FRowSpan := 1;
  399. FAlignVer := vaEmpty;
  400. FAlignHor := alEmpty;
  401. end;
  402. { TFormFieldItem }
  403. procedure TFormFieldItem.SetLabelPos(const AValue: TTablePosition);
  404. begin
  405. FLabelPos.assign(AValue);
  406. end;
  407. procedure TFormFieldItem.SetValuePos(const AValue: TTablePosition);
  408. begin
  409. FValuePos.assign(AValue);
  410. end;
  411. procedure TFormFieldItem.AssignTo(Dest: TPersistent);
  412. begin
  413. inherited AssignTo(Dest);
  414. if dest is TFormFieldItem then
  415. with TFormFIeldItem(Dest) do
  416. begin
  417. FAction := self.FAction;
  418. FFieldName := self.FFieldName;
  419. FInputType := self.FInputType;
  420. FLabelCaption := self.FLabelCaption;
  421. FLabelPos.assign (self.FLabelPos);
  422. FProducer := self.FProducer;
  423. FValuePos.assign(self.FValuePos);
  424. end;
  425. end;
  426. function TFormFieldItem.GetDisplayName: String;
  427. begin
  428. If (FName='') then
  429. FName:=ClassName+IntToStr(self.Index);
  430. Result:=FName;
  431. end;
  432. procedure TFormFieldItem.SetDisplayName(AValue: String);
  433. begin
  434. Inherited;
  435. FName:=AValue;
  436. end;
  437. constructor TFormFieldItem.Create(ACollection: TCollection);
  438. begin
  439. inherited Create(ACollection);
  440. FLabelPos := TTablePosition.Create;
  441. FValuePos := TTablePosition.Create;
  442. end;
  443. destructor TFormFieldItem.Destroy;
  444. begin
  445. FLabelPos.Free;
  446. FValuePos.Free;
  447. inherited Destroy;
  448. end;
  449. function TFormFieldItem.getValue: String;
  450. begin
  451. if inputType in [fitcheckbox,fitradio] then
  452. Result := 'T'
  453. else
  454. Result := FField.Text;
  455. if assigned (FOnGetValue) then
  456. onGetValue(self,Result);
  457. end;
  458. function TFormFieldItem.getLabel: String;
  459. begin
  460. Result := LabelCaption;
  461. if assigned(FOnGetLabel) then
  462. onGetLabel(Self,Result);
  463. end;
  464. function TFormFieldItem.getAction: String;
  465. begin
  466. Result := Format(Action,[FField.asstring]);
  467. if assigned(FOnGetAction) then
  468. onGetAction(Self,Result);
  469. end;
  470. { TFormFieldCollection }
  471. function TFormFieldCollection.GetItem(index : integer): TFormFieldItem;
  472. begin
  473. result := TFormFieldItem(inherited items[index]);
  474. end;
  475. procedure TFormFieldCollection.SetItem(index : integer;
  476. const AValue: TFormFieldItem);
  477. begin
  478. inherited items[index] := AValue;
  479. end;
  480. constructor TFormFieldCollection.create;
  481. begin
  482. inherited create (TFormFieldItem);
  483. end;
  484. function TFormFieldCollection.AddField(afieldname, acaption: string): TFormFieldItem;
  485. begin
  486. result := TFormFieldItem (Add);
  487. result.fieldname := afieldname;
  488. result.labelcaption := acaption;
  489. end;
  490. function TFormFieldCollection.FindItem(AName: String): TFormFieldItem;
  491. Var
  492. I : Integer;
  493. begin
  494. I:=IndexofItem(AName);
  495. If (I=-1) then
  496. Result:=Nil
  497. else
  498. Result:=Items[I];
  499. end;
  500. function TFormFieldCollection.IndexofItem(AName: String): Integer;
  501. begin
  502. Result:=Count-1;
  503. While (Result>=0) and (CompareText(Items[Result].Name,AName)<>0) do
  504. Dec(Result);
  505. end;
  506. { TFormButtonItem }
  507. procedure TFormButtonItem.AssignTo(Dest: TPersistent);
  508. begin
  509. inherited AssignTo(Dest);
  510. if dest is TFormButtonItem then
  511. with TFormButtonItem(Dest) do
  512. begin
  513. FButtonType := self.FButtonType;
  514. FCaption := self.FCaption;
  515. FImage := self.FImage;
  516. FImagePlace := self.FImagePlace;
  517. FName := self.FName;
  518. FValue := self.FValue;
  519. end;
  520. end;
  521. constructor TFormButtonItem.create(ACollection: TCollection);
  522. begin
  523. inherited create(ACollection);
  524. ButtonType := fbtPushButton;
  525. end;
  526. { TFormButtonCollection }
  527. function TFormButtonCollection.GetItem(index: integer): TFormButtonItem;
  528. begin
  529. result := TFormButtonItem(inherited items[index]);
  530. end;
  531. procedure TFormButtonCollection.SetItem(index: integer;
  532. const AValue: TFormButtonItem);
  533. begin
  534. inherited items[index] := AValue;
  535. end;
  536. constructor TFormButtonCollection.create;
  537. begin
  538. inherited create (TFormButtonItem);
  539. end;
  540. function TFormButtonCollection.AddButton(aname, avalue, acaption: string): TFormButtonItem;
  541. begin
  542. result := TFormButtonItem(Add);
  543. with result do
  544. begin
  545. name := aname;
  546. value := avalue;
  547. caption := acaption;
  548. end;
  549. end;
  550. function TFormButtonCollection.AddButton(aname, acaption: string): TFormButtonItem;
  551. begin
  552. result := AddButton (aName, aCaption, acaption);
  553. end;
  554. function TFormButtonCollection.AddButton(acaption: string): TFormButtonItem;
  555. begin
  556. result := AddButton (acaption, acaption, acaption);
  557. end;
  558. { THTMLDatasetFormProducer }
  559. procedure THTMLDatasetFormProducer.WriteButtons(aWriter: THTMLWriter);
  560. procedure WriteButton (aButton : TFormButtonItem);
  561. const ButtonTypes : array[TFormButtontype] of THTMLbuttontype = (btsubmit,btreset,btbutton,btreset,btreset,btreset);
  562. const InputTypes : array[TFormButtontype] of THTMLinputtype = (itreset,itreset,itreset,itsubmit,itreset,itbutton);
  563. var b : THTML_Button;
  564. ib: THTML_input;
  565. begin
  566. with aWriter do
  567. if aButton.ButtonType in [fbtInputPushButton,fbtInputReset,fbtInputSubmit] then
  568. begin
  569. ib := input;
  570. with ib do
  571. begin
  572. Name := aButton.name;
  573. Value := aButton.value;
  574. TheType := InputTypes[aButton.ButtonType];
  575. if assigned (FAfterButtonCreate) then
  576. FAfterButtonCreate (self, aButton, ib);
  577. end;
  578. end
  579. else
  580. begin
  581. b := Startbutton;
  582. with b do
  583. begin
  584. Name := aButton.name;
  585. Value := aButton.value;
  586. TheType := ButtonTypes[aButton.ButtonType];
  587. if aButton.Image = '' then
  588. Text (aButton.Caption)
  589. else
  590. begin
  591. if aButton.ImagePlace in [ipAfter, ipUnder] then
  592. begin
  593. Text (aButton.Caption);
  594. if aButton.ImagePlace = ipUnder then
  595. linebreak;
  596. end;
  597. with image do
  598. begin
  599. src := aButton.image;
  600. if aButton.ImagePlace = ipOnly then
  601. alt := aButton.Caption;
  602. end;
  603. if aButton.ImagePlace in [ipBefore, ipAbove] then
  604. begin
  605. if aButton.ImagePlace = ipAbove then
  606. linebreak;
  607. Text (aButton.Caption);
  608. end;
  609. end;
  610. if assigned (FAfterButtonCreate) then
  611. FAfterButtonCreate (self, aButton, b);
  612. Endbutton;
  613. end;
  614. end;
  615. end;
  616. const ButHorAlign : array[TButtonHorPosition] of THTMLalign = (alleft,alcenter,aljustify,alright);
  617. var r : integer;
  618. begin
  619. with aWriter do
  620. begin
  621. StartTableRow;
  622. with StartTableCell do
  623. begin
  624. ColSpan := inttostr(FTableCols);
  625. align := ButHorAlign[ButtonsHorizontal];
  626. end;
  627. for r := 0 to buttonrow.count-1 do
  628. WriteButton (buttonrow.Items[r]);
  629. EndTableCell;
  630. EndTableRow;
  631. end;
  632. end;
  633. procedure THTMLDatasetFormProducer.SetSeparateLabel(const AValue: boolean);
  634. begin
  635. if AValue <> FSeparateLabel then
  636. begin
  637. FSeparateLabel := AValue;
  638. if AValue then
  639. FIncludeHeader := false;
  640. end;
  641. end;
  642. procedure THTMLDatasetFormProducer.SetIncludeHeader(const AValue: boolean);
  643. begin
  644. if FIncludeHeader <> AValue then
  645. begin
  646. FIncludeHeader := AValue;
  647. if AValue then
  648. SeparateLabel := false;
  649. end;
  650. end;
  651. procedure THTMLDatasetFormProducer.WriteTableDef(aWriter: THTMLWriter);
  652. var r : integer;
  653. c : THTMLCustomelement;
  654. begin
  655. c := aWriter.Starttablebody;
  656. if assigned (FAfterTBodyCreate) then
  657. FAfterTBodyCreate (self, c);
  658. aWriter.StartTableRow;
  659. with tabledef do
  660. begin
  661. for r := 0 to count-1 do
  662. with TTableCell (Items[r]) do
  663. begin
  664. if CellType <> ctSpanned then
  665. begin
  666. if (CellType = ctProducer) and assigned (FOnInitializeProducer) then
  667. FOnInitializeProducer (self, FFormField, Producer);
  668. c := WriteContent(aWriter);
  669. if assigned (FAfterCellCreate) then
  670. FAfterCellCreate(self, Items[r].FormField, IsLabel, c);
  671. end;
  672. if EndOfRow then
  673. begin
  674. aWriter.EndTableRow;
  675. aWriter.StartTableRow;
  676. end;
  677. end;
  678. end;
  679. aWriter.EndTableRow;
  680. aWriter.Endtablebody;
  681. end;
  682. procedure THTMLDatasetFormProducer.WriteHeaderTableDef(aWriter: THTMLWriter);
  683. var r : integer;
  684. c : THTMLCustomelement;
  685. begin
  686. aWriter.Starttablehead;
  687. aWriter.StartTableRow;
  688. with tabledef do
  689. begin
  690. for r := 0 to count-1 do
  691. with TTableCell (Items[r]) do
  692. begin
  693. c := WriteHeader(aWriter);
  694. if assigned (FAfterCellCreate) then
  695. FAfterCellCreate(self, Items[r].FormField, true, c);
  696. if EndOfRow then
  697. begin
  698. aWriter.EndTableRow;
  699. aWriter.StartTableRow;
  700. end;
  701. end;
  702. end;
  703. aWriter.EndTableRow;
  704. aWriter.Endtablehead;
  705. end;
  706. procedure THTMLDatasetFormProducer.CorrectCellSpans;
  707. var r, s, t : integer;
  708. c : TTableCell;
  709. ReachedEnd : boolean;
  710. begin
  711. for r := 0 to TableDef.count-1 do
  712. with TableDef.items[r] do
  713. if CellType <> ctSpanned then
  714. begin
  715. // CollSpan marking other cells as spanned
  716. s := 1;
  717. c := TableDef.Items[r];
  718. while (s < ColSpan) and not c.EndOfRow do
  719. begin
  720. c := TableDef.Items[r+s];
  721. c.celltype := ctSpanned;
  722. inc (s);
  723. end;
  724. // the same for rowsapn
  725. s := 1;
  726. t := r + (s*tablecols);
  727. while (s < rowspan) and (t < TableDef.count) do
  728. begin
  729. TableDef.items[t].CellType := ctSpanned;
  730. inc (s);
  731. inc (t, tablecols);
  732. end;
  733. end;
  734. end;
  735. procedure THTMLDatasetFormProducer.SearchControlFields;
  736. var r : integer;
  737. begin
  738. for r := 0 to FControls.count-1 do
  739. with FControls.items[r] do
  740. FField := datasource.dataset.FindField(FFieldname);
  741. end;
  742. function THTMLDatasetFormProducer.StartForm(aWriter: THTMLWriter) : THTMLCustomElement;
  743. const MethodAttribute : array[TFormMethod] of string = ('','GET','POST');
  744. var t : THTMLCustomElement;
  745. begin
  746. if Self.FormMethod <> fmNone then
  747. begin
  748. result := aWriter.Startform;
  749. with THTML_Form(result) do
  750. begin
  751. method := MethodAttribute[self.FormMethod];
  752. action := FormAction;
  753. end;
  754. t := aWriter.Starttable;
  755. end
  756. else
  757. begin
  758. t := aWriter.Starttable;
  759. result := t;
  760. end;
  761. if assigned (FAfterTableCreate) then
  762. FAfterTableCreate (self, t);
  763. end;
  764. procedure THTMLDatasetFormProducer.EndForm(aWriter: THTMLWriter);
  765. begin
  766. with aWriter do
  767. begin
  768. EndTable;
  769. if self.FormMethod <> fmNone then
  770. Endform;
  771. end;
  772. end;
  773. function THTMLDatasetFormProducer.WriteContent(aWriter: THTMLWriter): THTMLCustomElement;
  774. var r : integer;
  775. begin
  776. if assigned (datasource) and assigned(datasource.dataset) then
  777. begin
  778. Ftabledef := TTableDef.Create (TableCols, TableRows);
  779. try
  780. SearchControlFields;
  781. result := StartForm (aWriter);
  782. if bvpTop in ButtonsVertical then
  783. WriteButtons (aWriter);
  784. if SingleRecord then
  785. begin
  786. FillTableDef (false);
  787. CorrectCellSpans;
  788. WriteTableDef (aWriter);
  789. end
  790. else
  791. with datasource.dataset do
  792. begin
  793. if FIncludeHeader then
  794. begin
  795. FillTableDef (true);
  796. CorrectCellSpans;
  797. WriteHeaderTableDef (aWriter);
  798. end;
  799. if Page < 0 then
  800. first
  801. else
  802. RecNo := ((Page-1) * RecordsPerPage) + 1; // zero based? yes: + 1 has to be deleted
  803. r := 0;
  804. while not eof and (r < RecordsPerPage) do
  805. begin
  806. FillTableDef (false);
  807. CorrectCellSpans;
  808. WriteTableDef (aWriter);
  809. Next;
  810. inc (r);
  811. end;
  812. end;
  813. if bvpBottom in ButtonsVertical then
  814. WriteButtons (aWriter);
  815. EndForm (aWriter)
  816. finally
  817. tabledef.Free;
  818. end;
  819. end;
  820. end;
  821. procedure THTMLDatasetFormProducer.FillTableDef (IsHeader:boolean);
  822. var r : integer;
  823. begin
  824. for r := 0 to Controls.Count-1 do
  825. ControlToTableDef (Controls.items[r], IsHeader);
  826. end;
  827. function THTMLDatasetFormProducer.SingleRecord: boolean;
  828. begin
  829. result := true;
  830. end;
  831. constructor THTMLDatasetFormProducer.create(aOwner: TComponent);
  832. begin
  833. inherited create(aOwner);
  834. FTableCols := 2;
  835. FButtonsHor := bhpLeft;
  836. FButtonsVer := [bvpTop, bvpBottom];
  837. Fbuttonrow := TFormButtonCollection.create;
  838. FControls := TFormFieldCollection.Create;
  839. end;
  840. destructor THTMLDatasetFormProducer.destroy;
  841. begin
  842. Fbuttonrow.Free;
  843. FControls.Free;
  844. inherited destroy;
  845. end;
  846. { THTMLDatasetFormEditProducer }
  847. procedure THTMLDatasetFormEditProducer.ControlToTableDef (aControldef : TFormFieldItem; IsHeader:boolean);
  848. procedure PlaceFieldValue;
  849. var check : boolean;
  850. begin
  851. with TableDef.CopyTablePosition(aControlDef.ValuePos) do
  852. begin
  853. FormField := aControldef;
  854. case aControlDef.inputtype of
  855. fitlabel,
  856. fittext,
  857. fitpassword,
  858. fitcheckbox,
  859. fitradio,
  860. fitfile,
  861. fithidden,
  862. fittextarea :
  863. begin
  864. CellType := ctInput;
  865. InputType := aControlDef.InputType;
  866. Name := aControlDef.Field.FieldName;
  867. Size := aControlDef.Field.DisplayWidth;
  868. MaxLength := aControldef.Field.Size;
  869. if aControlDef.inputType in [fitcheckbox,fitradio] then
  870. begin
  871. with aControlDef.Field do
  872. Check := asBoolean;
  873. if assigned (FOnFieldChecked) then
  874. FOnFieldChecked (aControlDef.Field, check);
  875. Checked := check;
  876. end;
  877. end;
  878. fitproducer :
  879. begin
  880. CellType := ctProducer;
  881. Producer := aControlDef.Producer;
  882. end;
  883. fitrecordselection : ;
  884. end;
  885. IsLabel := false;
  886. Value := aControlDef.getValue;
  887. if not FSeparateLabel and not FIncludeHeader then
  888. begin
  889. Caption := aControldef.getLabel;
  890. IncludeBreak := aControldef.LabelAbove;
  891. end;
  892. end;
  893. end;
  894. procedure PlaceLabel;
  895. begin
  896. with TableDef.CopyTablePosition(aControlDef.LabelPos) do
  897. begin
  898. CellType := ctLabel;
  899. IsLabel := true;
  900. Value := aControldef.getLabel;
  901. end;
  902. end;
  903. begin
  904. if assigned (aControlDef.FField) then
  905. PlaceFieldValue;
  906. if FSeparateLabel and (aControlDef.getLabel <> '') then
  907. PlaceLabel;
  908. end;
  909. { THTMLDatasetFormShowProducer }
  910. (**** TTableCell *****
  911. property IsLabel : boolean read FIsLabel write FIsLabel;
  912. // Label or Value ?
  913. property CellType : TCellType read FCellType write FCellType;
  914. ctEmpty, ctInput, ctLabel, ctProducer, ctSpanned
  915. { Cell properties: }
  916. property ColSpan : integer read FColSpan write FColSpan;
  917. property RowSpan : integer read FRowSpan write FRowSpan;
  918. property AlignVertical : THTMLvalign read FAlignVer write FAlignVer default vaEmpty;
  919. property AlignHorizontal : THTMLalign read FAlignHor write FAlignHor default alEmpty;
  920. property Value : string read FValue write FValue;
  921. // Contains the text for labels, or the value for input, or unused for producer and empty
  922. { only for input: }
  923. property Name : string read FName write FName;
  924. // name of the control
  925. property InputType : TFormInputType read FInputType write FInputType;
  926. // type of the input element
  927. property Size : integer read FSize write FSize;
  928. // size of text input element
  929. property MaxLength : integer read FMaxLength write FMaxLength;
  930. // MaxLength of text input element
  931. property Checked : boolean read FChecked write FChecked;
  932. // checked or not for radio,checkbox
  933. { only for labels: }
  934. property Link : string read FLink write FLink;
  935. // link to place around the text
  936. { only for producers: }
  937. property Producer : THTMLContentProducer read FProducer write FProducer;
  938. // producer to include
  939. ***** TFormFieldItem *****
  940. property Fieldname : string read FFieldName write FFieldname;
  941. property Field : TField
  942. // the field to show/edit
  943. property LabelCaption : string read FLabelCaption write FLabelCaption;
  944. // the text to show for the control
  945. property InputType : TFormInputType read FInputType write FInputType default fittext;
  946. // the type of form control to use
  947. (fittext,fitpassword,fitcheckbox,fitradio,fitfile,fithidden,fitproducer,fittextarea,fitrecordselection)
  948. property Producer : THTMLContentProducer read FProducer write FProducer;
  949. // the producer to include when generating the value
  950. property Action : string read FAction write FAction;
  951. // when showing the link to include in the value
  952. property LabelPos : TTablePosition read FLabelPos write SetLabelPos;
  953. // place of the label in the table-grid
  954. property ValuePos : TTablePosition read FValuePos write SetValuePos;
  955. // place of the value in the table-grid *)
  956. procedure THTMLDatasetFormShowProducer.ControlToTableDef (aControldef : TFormFieldItem; IsHeader:boolean);
  957. procedure PlaceFieldValue;
  958. begin
  959. with TableDef.CopyTablePosition(aControlDef.ValuePos) do
  960. begin
  961. CellType := ctLabel;
  962. IsLabel := false;
  963. Value := aControlDef.getValue;
  964. if not FSeparateLabel and not FIncludeHeader then
  965. begin
  966. Caption := aControldef.getLabel;
  967. IncludeBreak := aControldef.LabelAbove;
  968. end;
  969. end;
  970. end;
  971. procedure PlaceLabel;
  972. begin
  973. with TableDef.CopyTablePosition(aControlDef.LabelPos) do
  974. begin
  975. CellType := ctLabel;
  976. IsLabel := true;
  977. Value := aControldef.getLabel;
  978. end;
  979. end;
  980. begin
  981. if assigned (aControlDef.FField) then
  982. PlaceFieldValue;
  983. if FSeparateLabel and (aControlDef.getLabel <> '') then
  984. PlaceLabel;
  985. end;
  986. { THTMLDatasetFormGridProducer }
  987. procedure THTMLDatasetFormGridProducer.ControlToTableDef (aControldef : TFormFieldItem; IsHeader:boolean);
  988. procedure PlaceFieldValue;
  989. var check : boolean;
  990. begin
  991. with TableDef.CopyTablePosition(aControlDef.ValuePos) do
  992. begin
  993. if aControldef.InputType = fitcheckbox then
  994. begin
  995. CellType := ctInput;
  996. InputType := aControldef.InputType;
  997. Disabled := True;
  998. with aControlDef.Field do
  999. Check := asBoolean;
  1000. if assigned (FOnFieldChecked) then
  1001. FOnFieldChecked (aControlDef.Field, check);
  1002. Checked := check;
  1003. end
  1004. else
  1005. CellType := ctLabel;
  1006. IsLabel := false;
  1007. Value := aControlDef.getValue;
  1008. Link := aControldef.getAction;
  1009. if not FSeparateLabel and not FIncludeHeader then
  1010. begin
  1011. Caption := aControldef.getLabel;
  1012. IncludeBreak := aControldef.LabelAbove;
  1013. end;
  1014. end;
  1015. end;
  1016. procedure PlaceLabel;
  1017. begin
  1018. with TableDef.CopyTablePosition(aControlDef.LabelPos) do
  1019. begin
  1020. CellType := ctLabel;
  1021. IsLabel := true;
  1022. Value := aControldef.getLabel;
  1023. end;
  1024. end;
  1025. begin
  1026. if assigned (aControlDef.FField) and not IsHeader then
  1027. PlaceFieldValue;
  1028. if (IsHeader or FSeparateLabel) and (aControlDef.getLabel <> '') then
  1029. PlaceLabel;
  1030. end;
  1031. function THTMLDatasetFormGridProducer.SingleRecord: boolean;
  1032. begin
  1033. Result := false;
  1034. end;
  1035. constructor THTMLDatasetFormGridProducer.Create(aOwner: TComponent);
  1036. begin
  1037. inherited create(aOwner);
  1038. RecordsPerPage := 20;
  1039. Page := -1;
  1040. end;
  1041. { TTableCell }
  1042. procedure TTableCell.WriteLabel(aWriter: THTMLWriter);
  1043. var HasLink : boolean;
  1044. begin
  1045. HasLink := (Link <> '');
  1046. if HasLink then
  1047. aWriter.Anchor(Value).href := Link
  1048. else
  1049. aWriter.Text (Value);
  1050. end;
  1051. function TTableCell.WriteContent(aWriter: THTMLWriter) : THTMLCustomElement;
  1052. procedure WriteTextArea;
  1053. begin
  1054. aWriter.textarea(value).name := Name;
  1055. end;
  1056. procedure WriteInput;
  1057. var s, m : string;
  1058. begin
  1059. if size > 0 then
  1060. s := inttostr(size)
  1061. else
  1062. s := '';
  1063. if MaxLength > 0 then
  1064. m := inttostr(MaxLength)
  1065. else
  1066. m := '';
  1067. case InputType of
  1068. fittext :
  1069. with aWriter.FormText (Name, Value) do
  1070. begin
  1071. Size := s;
  1072. MaxLength := m;
  1073. end;
  1074. fitpassword :
  1075. with aWriter.FormPasswd (Name) do
  1076. begin
  1077. if self.Value <> '' then
  1078. Value := self.value;
  1079. Size := s;
  1080. MaxLength := m;
  1081. end;
  1082. fitcheckbox, fitrecordselection :
  1083. aWriter.FormCheckbox (Name, Value, checked).disabled := Disabled;
  1084. fitradio :
  1085. aWriter.FormRadio(Name, Value, checked);
  1086. fitfile :
  1087. aWriter.FormFile(Name, Value);
  1088. fithidden :
  1089. aWriter.FormHidden (Name, Value);
  1090. fitlabel :
  1091. aWriter.Text (Value);
  1092. end;
  1093. end;
  1094. procedure WriteProducer;
  1095. begin
  1096. with Producer do
  1097. begin
  1098. ParentElement := aWriter.CurrentElement;
  1099. HTMLDocument := aWriter.Document;
  1100. WriteContent (aWriter);
  1101. end;
  1102. end;
  1103. var c : THTML_td;
  1104. begin
  1105. if CellType <> ctSpanned then
  1106. with aWriter do
  1107. begin
  1108. c := Starttablecell;
  1109. with c do
  1110. begin
  1111. if self.ColSpan > 1 then
  1112. colspan := IntToStr(self.Colspan);
  1113. if self.RowSpan > 1 then
  1114. Rowspan := IntToStr(self.Rowspan);
  1115. align := AlignHorizontal;
  1116. valign := AlignVertical;
  1117. end;
  1118. if Self.Caption <> '' then
  1119. begin
  1120. span(self.caption);
  1121. if IncludeBreak then
  1122. linebreak;
  1123. end;
  1124. case CellType of
  1125. ctEmpty : ;
  1126. ctInput :
  1127. if InputType = fittextarea then
  1128. WriteTextArea
  1129. else
  1130. WriteInput;
  1131. ctLabel : WriteLabel(aWriter);
  1132. ctProducer : WriteProducer;
  1133. end;
  1134. Endtablecell;
  1135. result := c;
  1136. end
  1137. else
  1138. result := nil;
  1139. end;
  1140. function TTableCell.WriteHeader(aWriter: THTMLWriter) : THTMLCustomElement;
  1141. var c : THTML_th;
  1142. s : string;
  1143. begin
  1144. with aWriter do
  1145. begin
  1146. c := Starttableheadcell;
  1147. with c do
  1148. begin
  1149. if self.ColSpan > 1 then
  1150. ColSpan := IntToStr(self.Colspan);
  1151. if self.RowSpan > 1 then
  1152. RowSpan := IntToStr(self.Rowspan);
  1153. align := AlignHorizontal;
  1154. valign := AlignVertical;
  1155. end;
  1156. case CellType of
  1157. ctEmpty : ;
  1158. ctLabel : WriteLabel(aWriter);
  1159. // ctProducer : WriteProducer;
  1160. end;
  1161. Endtableheadcell;
  1162. result := c;
  1163. end;
  1164. end;
  1165. end.