home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Runimage / Delphi50 / Source / Internet / DBWEB.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-08-11  |  37.3 KB  |  1,365 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {       Database Web server application components      }
  6. {                                                       }
  7. {       Copyright (c) 1997,99 Inprise Corporation       }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit DBWeb;
  12.  
  13. interface
  14.  
  15. uses Windows, SysUtils, Classes, SyncObjs, HTTPApp, DB, DBTables;
  16.  
  17. type
  18.  
  19.   TDSTableProducer = class;
  20.  
  21. { TDSTableProducerEditor }
  22.  
  23.   TDSTableProducerEditor = class
  24.   private
  25.     FDSTableProducer: TDSTableProducer;
  26.     function GetDataSource: TDataSource;
  27.     procedure SetDataSource(DataSource: TDataSource);
  28.   public
  29.     constructor Create(DSTableProducer: TDSTableProducer);
  30.     destructor Destroy; override;
  31.     procedure Changed; virtual;
  32.     procedure PostChange; virtual;
  33.     property DSTableProducer: TDSTableProducer read FDSTableProducer;
  34.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  35.   end;
  36.  
  37. { THTTPDataLink }
  38.  
  39.   THTTPDataLink = class(TDataLink)
  40.   private
  41.     FDSTableProducer: TDSTableProducer;
  42.     FFieldCount: Integer;
  43.     FFieldMapSize: Integer;
  44.     FFieldMap: Pointer;
  45.     FModified: Boolean;
  46.     FSparseMap: Boolean;
  47.     function GetDefaultFields: Boolean;
  48.     function GetFields(I: Integer): TField;
  49.   protected
  50.     procedure ActiveChanged; override;
  51.     procedure DataSetChanged; override;
  52.     procedure DataSetScrolled(Distance: Integer); override;
  53.     procedure FocusControl(Field: TFieldRef); override;
  54.     procedure EditingChanged; override;
  55.     procedure LayoutChanged; override;
  56.     procedure RecordChanged(Field: TField); override;
  57.     procedure UpdateData; override;
  58.     function  GetMappedIndex(ColIndex: Integer): Integer;
  59.   public
  60.     constructor Create(DSTableProducer: TDSTableProducer);
  61.     destructor Destroy; override;
  62.     function AddMapping(const FieldName: string): Boolean;
  63.     procedure ClearMapping;
  64.     procedure Modified;
  65.     procedure Reset;
  66.     property DefaultFields: Boolean read GetDefaultFields;
  67.     property FieldCount: Integer read FFieldCount;
  68.     property Fields[I: Integer]: TField read GetFields;
  69.     property SparseMap: Boolean read FSparseMap write FSparseMap;
  70.   end;
  71.  
  72. { THTMLTableColumn }
  73.  
  74.   THTMLTableColumn = class(TCollectionItem)
  75.   private
  76.     FField: TField;
  77.     FFieldName: string;
  78.     FAlign: THTMLAlign;
  79.     FBgColor: THTMLBgColor;
  80.     FCustom: string;
  81.     FVAlign: THTMLVAlign;
  82.     FTitle: THTMLTableHeaderAttributes;
  83.     function GetField: TField;
  84.     function GetTableProducer: TDSTableProducer;
  85.     procedure SetAlign(Value: THTMLAlign);
  86.     procedure SetBgColor(const Value: THTMLBgColor);
  87.     procedure SetCustom(const Value: string);
  88.     procedure SetField(Value: TField);
  89.     procedure SetFieldName(const Value: string);
  90.     procedure SetTitle(Value: THTMLTableHeaderAttributes);
  91.     procedure SetVAlign(Value: THTMLVAlign);
  92.     procedure TitleChanged(Sender: TObject);
  93.   protected
  94.     function GeTDSTableProducer: TDSTableProducer;
  95.     function GetDisplayName: string; override;
  96.   public
  97.     constructor Create(Collection: TCollection); override;
  98.     destructor Destroy; override;
  99.     procedure AssignTo(Dest: TPersistent); override;
  100.     procedure RestoreDefaults;
  101.     procedure Update;
  102.     property Field: TField read GetField write SetField;
  103.     property DSTableProducer: TDSTableProducer read GetTableProducer;
  104.   published
  105.     property Align: THTMLAlign read FAlign write SetAlign default haDefault;
  106.     property BgColor: THTMLBgColor read FBgColor write SetBgColor;
  107.     property Custom: string read FCustom write SetCustom;
  108.     property FieldName: string read FFieldName write SetFieldName;
  109.     property Title: THTMLTableHeaderAttributes read FTitle write SetTitle;
  110.     property VAlign: THTMLVAlign read FVAlign write SetVAlign default haVDefault;
  111.   end;
  112.  
  113.   THTMLTableColumnClass = class of THTMLTableColumn;
  114.  
  115. { THTMLTableColumns }
  116.  
  117.   THTMLColumnState = (csDefault, csCustom);
  118.  
  119.   THTMLTableColumns = class(TCollection)
  120.   private
  121.     FDSTableProducer: TDSTableProducer;
  122.     function GetColumn(Index: Integer): THTMLTableColumn;
  123.     function GetState: THTMLColumnState;
  124.     procedure SetColumn(Index: Integer; Value: THTMLTableColumn);
  125.     procedure SetState(Value: THTMLColumnState);
  126.   protected
  127.     function GetAttrCount: Integer; override;
  128.     function GetAttr(Index: Integer): string; override;
  129.     function GetItemAttr(Index, ItemIndex: Integer): string; override;
  130.     function GetOwner: TPersistent; override;
  131.     procedure Update(Item: TCollectionItem); override;
  132.   public
  133.     constructor Create(DSTableProducer: TDSTableProducer;
  134.       ColumnClass: THTMLTableColumnClass);
  135.     function  Add: THTMLTableColumn;
  136.     procedure RestoreDefaults;
  137.     procedure RebuildColumns;
  138.     property State: THTMLColumnState read GetState write SetState;
  139.     property DSTableProducer: TDSTableProducer read FDSTableProducer;
  140.     property Items[Index: Integer]: THTMLTableColumn read GetColumn write SetColumn; default;
  141.   end;
  142.  
  143. { TDSTableProducer }
  144.  
  145.   THTMLCaptionAlignment = (caDefault, caTop, caBottom);
  146.  
  147.   TCreateContentEvent = procedure (Sender: TObject; var Continue: Boolean) of object;
  148.   THTMLGetTableCaptionEvent = procedure (Sender: TObject; var Caption: string;
  149.     var Alignment: THTMLCaptionAlignment) of object;
  150.   THTMLFormatCellEvent = procedure (Sender: TObject; CellRow, CellColumn: Integer;
  151.     var BgColor: THTMLBgColor; var Align: THTMLAlign; var VAlign: THTMLVAlign;
  152.     var CustomAttrs, CellData: string) of object;
  153.   THTMLDataSetEmpty = procedure (Sender: TObject; var Continue: Boolean) of object;
  154.  
  155.   TDSTableProducer = class(TCustomContentProducer)
  156.   private
  157.     FCaption: string;
  158.     FCaptionAlignment: THTMLCaptionAlignment;
  159.     FDataLink: THTTPDataLink;
  160.     FInternalDataSource: TDataSource;
  161.     FEditor: TDSTableProducerEditor;
  162.     FColumns: THTMLTableColumns;
  163.     FHeader: TStrings;
  164.     FFooter: TStrings;
  165.     FMaxRows: Integer;
  166.     FModified: Boolean;
  167.     FLayoutLock: Integer;
  168.     FUpdateLock: Integer;
  169.     FRowAttributes: THTMLTableRowAttributes;
  170.     FTableAttributes: THTMLTableAttributes;
  171.     FOnCreateContent: TCreateContentEvent;
  172.     FOnFormatCell: THTMLFormatCellEvent;
  173.     FOnGetTableCaption: THTMLGetTableCaptionEvent;
  174.     procedure AttributeChanged(Sender: TObject);
  175.     procedure Changed;
  176.     procedure InternalLayout;
  177.     procedure SetCaption(const Value: string);
  178.     procedure SetCaptionAlignment(Value: THTMLCaptionAlignment);
  179.     procedure SetFooter(Value: TStrings);
  180.     procedure SetHeader(Value: TStrings);
  181.     procedure SetMaxRows(Value: Integer);
  182.     procedure SetRowAttributes(Value: THTMLTableRowAttributes);
  183.     procedure SetTableAttributes(Value: THTMLTableAttributes);
  184.   protected
  185.     function AcquireLayoutLock: Boolean;
  186.     procedure BeginLayout;
  187.     function ColumnHeader: string; dynamic;
  188.     procedure DefineFieldMap;
  189.     function DoCreateContent: Boolean;
  190.     procedure DoFormatCell(CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
  191.       var Align: THTMLAlign; var VAlign: THTMLVAlign;
  192.       var CustomAttrs, CellData: string); dynamic;
  193.     procedure DoGetCaption(var TableCaption: string;
  194.       var CaptionAlign: THTMLCaptionAlignment); dynamic;
  195.     procedure EndLayout;
  196.     function FormatCell(CellRow, CellColumn: Integer; CellData: string;
  197.       const Tag: string; const BgColor: THTMLBgColor; Align: THTMLAlign;
  198.       VAlign: THTMLVAlign; const Custom: string): string; dynamic;
  199.     function GetDataSet: TDataSet; virtual; abstract;
  200.     function GetDataSource: TDataSource;
  201.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  202.     procedure LayoutChanged;
  203.     procedure LinkActive(Value: Boolean);
  204.     function RowHeader: string; dynamic;
  205.     procedure SetColumns(Value: THTMLTableColumns);
  206.     procedure SetDataSet(ADataSet: TDataSet); virtual; abstract;
  207.     procedure SetDataSource(Value: TDataSource);
  208.     function StoreColumns: Boolean;
  209.     function TableHeader: string; dynamic;
  210.     function TableCaption: string; dynamic;
  211.     property DataLink: THTTPDataLink read FDataLink;
  212.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  213.     property InternalDataSource: TDataSource read FInTernalDataSource;
  214.     property OnCreateContent: TCreateContentEvent read FOnCreateContent
  215.       write FOnCreateContent;
  216.     property OnFormatCell: THTMLFormatCellEvent read FOnFormatCell
  217.       write FOnFormatCell;
  218.     property OnGetTableCaption: THTMLGetTableCaptionEvent
  219.       read FOnGetTableCaption write FOnGetTableCaption;
  220.   public
  221.     constructor Create(AOwner: TComponent); override;
  222.     destructor Destroy; override;
  223.     procedure BeginUpdate;
  224.     procedure EndUpdate;
  225.     property Caption: string read FCaption write SetCaption;
  226.     property CaptionAlignment: THTMLCaptionAlignment read FCaptionAlignment
  227.       write SetCaptionAlignment default caDefault;
  228.     property Columns: THTMLTableColumns read FColumns write SetColumns stored StoreColumns;
  229.     property DataSet: TDataSet read GetDataSet write SetDataSet;
  230.     property Editor: TDSTableProducerEditor read FEditor write FEditor;
  231.     property Footer: TStrings read FFooter write SetFooter;
  232.     property Header: TStrings read FHeader write SetHeader;
  233.     property MaxRows: Integer read FMaxRows write SetMaxRows default 20;
  234.     property RowAttributes: THTMLTableRowAttributes read FRowAttributes
  235.       write SetRowAttributes;
  236.     property TableAttributes: THTMLTableAttributes read FTableAttributes
  237.       write SetTableAttributes;
  238.   end;
  239.  
  240. { TQueryTableProducer }
  241.  
  242.   TQueryTableProducer = class(TDSTableProducer)
  243.   private
  244.     FQuery: TQuery;
  245.     procedure SetQuery(AQuery: TQuery);
  246.   protected
  247.     function GetDataSet: TDataSet; override;
  248.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  249.     procedure SetDataSet(ADataSet: TDataSet); override;
  250.   public
  251.     function Content: string; override;
  252.   published
  253.     property Caption;
  254.     property CaptionAlignment;
  255.     property Columns;
  256.     property Footer;
  257.     property Header;
  258.     property MaxRows;
  259.     property Query: TQuery read FQuery write SetQuery;
  260.     property RowAttributes;
  261.     property TableAttributes;
  262.     property OnCreateContent;
  263.     property OnFormatCell;
  264.     property OnGetTableCaption;
  265.   end;
  266.  
  267. { TDataSetTableProducer }
  268.  
  269.   TDataSetTableProducer = class(TDSTableProducer)
  270.   private
  271.     FDataSet: TDataSet;
  272.   protected
  273.     function GetDataSet: TDataSet; override;
  274.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  275.     procedure SetDataSet(ADataSet: TDataSet); override;
  276.   public
  277.     function Content: string; override;
  278.   published
  279.     property Caption;
  280.     property CaptionAlignment;
  281.     property Columns;
  282.     property Footer;
  283.     property Header;
  284.     property MaxRows;
  285.     property DataSet;
  286.     property RowAttributes;
  287.     property TableAttributes;
  288.     property OnCreateContent;
  289.     property OnFormatCell;
  290.     property OnGetTableCaption;
  291.   end;
  292.  
  293. function HtmlTable(DataSet: TDataSet; DataSetHandler: TDSTableProducer;
  294.   MaxRows: Integer): string;
  295.  
  296. implementation
  297.  
  298. uses
  299.   WebConst;
  300.  
  301. { Error reporting }
  302.  
  303. procedure TableError(const S: string);
  304. begin
  305.   raise Exception.Create(S);
  306. end;
  307.  
  308. { DSTableProducerEditor }
  309.  
  310. constructor TDSTableProducerEditor.Create(DSTableProducer: TDSTableProducer);
  311. begin
  312.   inherited Create;
  313.   RPR;
  314.   FDSTableProducer := DSTableProducer;
  315.   FDSTableProducer.Editor := Self;
  316. end;
  317.  
  318. destructor TDSTableProducerEditor.Destroy;
  319. begin
  320.   if FDSTableProducer <> nil then FDSTableProducer.Editor := nil;
  321.   inherited Destroy;
  322. end;
  323.  
  324. procedure TDSTableProducerEditor.Changed;
  325. begin
  326. end;
  327.  
  328. procedure TDSTableProducerEditor.PostChange;
  329. begin
  330. end;
  331.  
  332. function TDSTableProducerEditor.GetDataSource;
  333. begin
  334.   if Assigned(FDSTableProducer) then
  335.     Result := FDSTableProducer.DataSource
  336.   else Result := nil;
  337. end;
  338.  
  339. procedure TDSTableProducerEditor.SetDataSource(DataSource: TDataSource);
  340. begin
  341.   if Assigned(FDSTableProducer) then
  342.     FDSTableProducer.DataSource := DataSource;
  343. end;
  344.  
  345. { THTMLTableColumn }
  346.  
  347. constructor THTMLTableColumn.Create(Collection: TCollection);
  348. var
  349.   DataSetHandler: TDSTableProducer;
  350. begin
  351.   DataSetHandler := nil;
  352.   if (Collection <> nil) and (Collection is THTMLTableColumns) then
  353.     DataSetHandler := THTMLTableColumns(Collection).DSTableProducer;
  354.   if DataSetHandler <> nil then
  355.     DataSetHandler.BeginLayout;
  356.   try
  357.     inherited Create(Collection);
  358.     FTitle := THTMLTableHeaderAttributes.Create(nil);
  359.     FTitle.OnChange := TitleChanged;
  360.   finally
  361.     if DataSetHandler <> nil then
  362.       DataSetHandler.EndLayout;
  363.   end;
  364. end;
  365.  
  366. destructor THTMLTableColumn.Destroy;
  367. begin
  368.   FTitle.Free;
  369.   inherited Destroy;
  370. end;
  371.  
  372. procedure THTMLTableColumn.AssignTo(Dest: TPersistent);
  373. begin
  374.   if Dest is THTMLTableColumn then
  375.   begin
  376.     if Assigned(Collection) then Collection.BeginUpdate;
  377.     try
  378.       with THTMLTableColumn(Dest) do
  379.       begin
  380.         FieldName := Self.FieldName;
  381.         Align := Self.Align;
  382.         BgColor := Self.BgColor;
  383.         VAlign := Self.VAlign;
  384.         Title := Self.Title;
  385.       end;
  386.     finally
  387.       if Assigned(Collection) then Collection.EndUpdate;
  388.     end;
  389.   end else inherited AssignTo(Dest);
  390. end;
  391.  
  392. function THTMLTableColumn.GetField: TField;
  393. var
  394.   HTTPDSHandler: TDSTableProducer;
  395. begin
  396.   HTTPDSHandler := GetDSTableProducer;
  397.   if (FField = nil) and (FFieldName <> '') and Assigned(HTTPDsHandler) and
  398.     Assigned(HTTPDSHandler.DataLink.DataSet) then
  399.   with HTTPDSHandler.Datalink.Dataset do
  400.     if Active or (not DefaultFields) then
  401.       SetField(FindField(FieldName));
  402.   Result := FField;
  403. end;
  404.  
  405. function THTMLTableColumn.GetTableProducer: TDSTableProducer;
  406. begin
  407.   if Assigned(Collection) and (Collection is THTMLTableColumns) then
  408.     Result := THTMLTableColumns(Collection).DSTableProducer
  409.   else
  410.     Result := nil;
  411. end;
  412.  
  413. function THTMLTableColumn.GetDSTableProducer: TDSTableProducer;
  414. begin
  415.   if Assigned(Collection) and (Collection is THTMLTableColumns) then
  416.     Result := THTMLTableColumns(Collection).DSTableProducer
  417.   else Result := nil;
  418. end;
  419.  
  420. function THTMLTableColumn.GetDisplayName: string;
  421. begin
  422.   if FFieldName <> '' then
  423.     Result := FFieldName
  424.   else Result := inherited GetDisplayName;
  425. end;
  426.  
  427. procedure THTMLTableColumn.RestoreDefaults;
  428. begin
  429.   FAlign := haDefault;
  430.   FBgColor := '';
  431.   FCustom := '';
  432.   FVAlign := haVDefault;
  433.   FTitle.RestoreDefaults;
  434. end;
  435.  
  436. procedure THTMLTableColumn.SetAlign(Value: THTMLAlign);
  437. begin
  438.   if Value <> FAlign then
  439.   begin
  440.     FAlign := Value;
  441.     Changed(False);
  442.   end;
  443. end;
  444.  
  445. procedure THTMLTableColumn.SetBgColor(const Value: THTMLBgColor);
  446. begin
  447.   if Value <> FBgColor then
  448.   begin
  449.     FBgColor := Value;
  450.     Changed(False);
  451.   end;
  452. end;
  453.  
  454. procedure THTMLTableColumn.SetCustom(const Value: string);
  455. begin
  456.   if Value <> FCustom then
  457.   begin
  458.     FCustom := Value;
  459.     Changed(False);
  460.   end;
  461. end;
  462.  
  463. procedure THTMLTableColumn.SetField(Value: TField);
  464. begin
  465.   if Value <> FField then
  466.   begin
  467.     FField := Value;
  468.     if Assigned(Value) then
  469.       FFieldName := Value.FieldName;
  470.     Changed(False);
  471.   end;
  472. end;
  473.  
  474. procedure THTMLTableColumn.SetFieldName(const Value: string);
  475. var
  476.   AField: TField;
  477.   DataSetHandler: TDSTableProducer;
  478. begin
  479.   AField := nil;
  480.   DataSetHandler := GetDSTableProducer;
  481.   if Assigned(DataSetHandler) and Assigned(DataSetHandler.DataLink.DataSet) and
  482.     not (csLoading in DataSetHandler.ComponentState) and (Value <> '') then
  483.       AField := DataSetHandler.DataLink.DataSet.FindField(Value); { no exceptions }
  484.   FFieldName := Value;
  485.   SetField(AField);
  486.   Changed(False);
  487. end;
  488.  
  489. procedure THTMLTableColumn.SetTitle(Value: THTMLTableHeaderAttributes);
  490. begin
  491.   FTitle.Assign(Value);
  492. end;
  493.  
  494. procedure THTMLTableColumn.SetVAlign(Value: THTMLVAlign);
  495. begin
  496.   if Value <> FVAlign then
  497.   begin
  498.     FVAlign := Value;
  499.     Changed(False);
  500.   end;
  501. end;
  502.  
  503. procedure THTMLTableColumn.TitleChanged(Sender: TObject);
  504. begin
  505.   Changed(False);
  506. end;
  507.  
  508. procedure THTMLTableColumn.Update;
  509. begin
  510.   GetField;
  511. end;
  512.  
  513. type
  514.   TDefaultHTMLTableColumn = class(THTMLTableColumn)
  515.     constructor Create(Collection: TCollection); override;
  516.   end;
  517.  
  518. { TDefaultHTMLTableColumn }
  519.  
  520. constructor TDefaultHTMLTableColumn.Create(Collection: TCollection);
  521. begin
  522.   inherited Create(Collection);
  523. end;
  524.  
  525. { THTMLTableColumns }
  526.  
  527. constructor THTMLTableColumns.Create(DSTableProducer: TDSTableProducer;
  528.   ColumnClass: THTMLTableColumnClass);
  529. begin
  530.   inherited Create(ColumnClass);
  531.   FDSTableProducer := DSTableProducer;
  532. end;
  533.  
  534. function THTMLTableColumns.Add: THTMLTableColumn;
  535. begin
  536.   Result := THTMLTableColumn(inherited Add);
  537. end;
  538.  
  539. function THTMLTableColumns.GetColumn(Index: Integer): THTMLTableColumn;
  540. begin
  541.   Result := THTMLTableColumn(inherited Items[Index]);
  542. end;
  543.  
  544. function THTMLTableColumns.GetState: THTMLColumnState;
  545. begin
  546.   Result := THTMLColumnState((Count > 0) and not (Items[0] is TDefaultHTMLTableColumn));
  547. end;
  548.  
  549. procedure THTMLTableColumns.RestoreDefaults;
  550. var
  551.   I: Integer;
  552. begin
  553.   BeginUpdate;
  554.   try
  555.     for I := 0 to Count - 1 do
  556.       Items[I].RestoreDefaults;
  557.   finally
  558.     EndUpdate;
  559.   end;
  560. end;
  561.  
  562. procedure THTMLTableColumns.RebuildColumns;
  563. var
  564.   I: Integer;
  565. begin
  566.   Clear;
  567.   if Assigned(FDSTableProducer) and Assigned(FDSTableProducer.DataSource) and
  568.     Assigned(FDSTableProducer.Datasource.Dataset) then
  569.   begin
  570.     FDSTableProducer.BeginLayout;
  571.     try
  572.       with FDSTableProducer.Datasource.Dataset do
  573.         for I := 0 to FieldCount - 1 do
  574.           Add.Field := Fields[I];
  575.     finally
  576.       FDSTableProducer.EndLayout;
  577.     end;
  578.     for I := 0 to Count - 1 do Items[I].Update;
  579.   end;
  580. end;
  581.  
  582. procedure THTMLTableColumns.SetColumn(Index: Integer; Value: THTMLTableColumn);
  583. begin
  584.   Items[Index].Assign(Value);
  585. end;
  586.  
  587. procedure THTMLTableColumns.SetState(Value: THTMLColumnState);
  588. begin
  589.   if Value <> State then
  590.   begin
  591.     if Value = csDefault then
  592.       Clear
  593.     else
  594.       RebuildColumns;
  595.   end;
  596. end;
  597.  
  598. { Design-time support }
  599. function THTMLTableColumns.GetAttrCount: Integer;
  600. begin
  601.   Result := 2;
  602. end;
  603.  
  604. function THTMLTableColumns.GetAttr(Index: Integer): string;
  605. begin
  606.   case Index of
  607.     0: Result := sFieldNameColumn;
  608.     1: Result := sFieldTypeColumn;
  609.   else
  610.     Result := '';
  611.   end;
  612. end;
  613.  
  614. function THTMLTableColumns.GetItemAttr(Index, ItemIndex: Integer): string;
  615. begin
  616.   case Index of
  617.     0: Result := Items[ItemIndex].DisplayName;
  618.     1:
  619.       with Items[ItemIndex] do
  620.       begin
  621.         GetField;
  622.         if Field <> nil then
  623.           Result := Field.ClassName
  624.         else Result := '';
  625.       end;
  626.   else
  627.     Result := '';
  628.   end;
  629. end;
  630.  
  631. function THTMLTableColumns.GetOwner: TPersistent;
  632. begin
  633.   Result := FDSTableProducer;
  634. end;
  635.  
  636. procedure THTMLTableColumns.Update(Item: TCollectionItem);
  637. begin
  638.   if (FDSTableProducer <> nil) and
  639.     not (csLoading in FDSTableProducer.ComponentState) then
  640.     if Item = nil then
  641.       FDSTableProducer.LayoutChanged
  642.     else if FDSTableProducer.Editor <> nil then
  643.       FDSTableProducer.Editor.PostChange;
  644. end;
  645.  
  646. { THTTPDataLink }
  647.  
  648. const
  649.   MaxMapSize = (MaxInt div 2) div SizeOf(Integer);  { 250 million }
  650.  
  651. type
  652.   TIntArray = array[0..MaxMapSize - 1] of Integer;
  653.   PIntArray = ^TIntArray;
  654.  
  655. constructor THTTPDataLink.Create(DSTableProducer: TDSTableProducer);
  656. begin
  657.   inherited Create;
  658.   FDSTableProducer := DSTableProducer;
  659. end;
  660.  
  661. destructor THTTPDataLink.Destroy;
  662. begin
  663.   ClearMapping;
  664.   inherited Destroy;
  665. end;
  666.  
  667. function THTTPDataLink.GetDefaultFields: Boolean;
  668. var
  669.   I: Integer;
  670. begin
  671.   Result := True;
  672.   if DataSet <> nil then Result := DataSet.DefaultFields;
  673.   if Result and SparseMap then
  674.   for I := 0 to FFieldCount - 1 do
  675.     if PIntArray(FFieldMap)^[I] < 0 then
  676.     begin
  677.       Result := False;
  678.       Exit;
  679.     end;
  680. end;
  681.  
  682. function THTTPDataLink.GetFields(I: Integer): TField;
  683. begin
  684.   if (0 <= I) and (I < FFieldCount) and (PIntArray(FFieldMap)^[I] >= 0) then
  685.     Result := DataSet.Fields[PIntArray(FFieldMap)^[I]]
  686.   else
  687.     Result := nil;
  688. end;
  689.  
  690. function THTTPDataLink.AddMapping(const FieldName: string): Boolean;
  691. var
  692.   Field: TField;
  693.   NewSize: Integer;
  694. begin
  695.   Result := True;
  696.   if FFieldCount >= MaxMapSize then TableError(STooManyColumns);
  697.   if SparseMap then
  698.     Field := DataSet.FindField(FieldName)
  699.   else
  700.     Field := DataSet.FieldByName(FieldName);
  701.  
  702.   if FFieldCount = FFieldMapSize then
  703.   begin
  704.     NewSize := FFieldMapSize;
  705.     if NewSize = 0 then
  706.       NewSize := 8
  707.     else
  708.       Inc(NewSize, NewSize);
  709.     if (NewSize < FFieldCount) then
  710.       NewSize := FFieldCount + 1;
  711.     if (NewSize > MaxMapSize) then
  712.       NewSize := MaxMapSize;
  713.     ReallocMem(FFieldMap, NewSize * SizeOf(Integer));
  714.     FFieldMapSize := NewSize;
  715.   end;
  716.   if Assigned(Field) then
  717.   begin
  718.     PIntArray(FFieldMap)^[FFieldCount] := Field.Index;
  719.     Field.FreeNotification(FDSTableProducer);
  720.   end
  721.   else
  722.     PIntArray(FFieldMap)^[FFieldCount] := -1;
  723.   Inc(FFieldCount);
  724. end;
  725.  
  726. procedure THTTPDataLink.ActiveChanged;
  727. begin
  728.   FDSTableProducer.LinkActive(Active);
  729. end;
  730.  
  731. procedure THTTPDataLink.ClearMapping;
  732. begin
  733.   if FFieldMap <> nil then
  734.   begin
  735.     FreeMem(FFieldMap, FFieldMapSize * SizeOf(Integer));
  736.     FFieldMap := nil;
  737.     FFieldMapSize := 0;
  738.     FFieldCount := 0;
  739.   end;
  740. end;
  741.  
  742. procedure THTTPDataLink.Modified;
  743. begin
  744.   FModified := True;
  745. end;
  746.  
  747. procedure THTTPDataLink.DataSetChanged;
  748. begin
  749.   FDSTableProducer.Changed;
  750.   FModified := False;
  751. end;
  752.  
  753. procedure THTTPDataLink.DataSetScrolled(Distance: Integer);
  754. begin
  755. //  FGrid.Scroll(Distance);
  756. end;
  757.  
  758. procedure THTTPDataLink.LayoutChanged;
  759. begin
  760.   FDSTableProducer.LayoutChanged;
  761. end;
  762.  
  763. procedure THTTPDataLink.FocusControl(Field: TFieldRef);
  764. begin
  765. //  Not Needed
  766. end;
  767.  
  768. procedure THTTPDataLink.EditingChanged;
  769. begin
  770. //  Not Needed
  771. end;
  772.  
  773. procedure THTTPDataLink.RecordChanged(Field: TField);
  774. begin
  775. //  Not Needed
  776. end;
  777.  
  778. procedure THTTPDataLink.UpdateData;
  779. begin
  780. //  Not Needed
  781. end;
  782.  
  783. function THTTPDataLink.GetMappedIndex(ColIndex: Integer): Integer;
  784. begin
  785.   if (0 <= ColIndex) and (ColIndex < FFieldCount) then
  786.     Result := PIntArray(FFieldMap)^[ColIndex]
  787.   else
  788.     Result := -1;
  789. end;
  790.  
  791. procedure THTTPDataLink.Reset;
  792. begin
  793.   if FModified then RecordChanged(nil) else Dataset.Cancel;
  794. end;
  795.  
  796. { TDSTableProducer }
  797.  
  798. constructor TDSTableProducer.Create(AOwner: TComponent);
  799. begin
  800.   inherited Create(AOwner);
  801.   FFooter := TStringList.Create;
  802.   FHeader := TStringList.Create;
  803.   FDataLink := THTTPDataLink.Create(Self);
  804.   FInternalDataSource := TDataSource.Create(Self);
  805.   FColumns := THTMLTableColumns.Create(Self, THTMLTableColumn);
  806.   FRowAttributes := THTMLTableRowAttributes.Create(Self);
  807.   FRowAttributes.OnChange := AttributeChanged;
  808.   FTableAttributes := THTMLTableAttributes.Create(Self);
  809.   FTableAttributes.OnChange := AttributeChanged;
  810.   FMaxRows := 20;
  811.   DataSource := FInternalDataSource; // must be the last thing
  812. end;
  813.  
  814. destructor TDSTableProducer.Destroy;
  815. begin
  816.   BeginUpdate;
  817.   DataSource := nil;
  818.   FColumns.Free;
  819.   FColumns := nil;
  820.   FDataLink.Free;
  821.   FDataLink := nil;
  822.   FInternalDataSource.Free;
  823.   FInternalDataSource := nil;
  824.   FRowAttributes.Free;
  825.   FTableAttributes.Free;
  826.   FFooter.Free;
  827.   FHeader.Free;
  828.   inherited Destroy;
  829. end;
  830.  
  831. function TDSTableProducer.AcquireLayoutLock: Boolean;
  832. begin
  833.   Result := (FLayoutLock = 0) and (FUpdateLock = 0);
  834.   if Result then BeginLayout;
  835. end;
  836.  
  837. procedure TDSTableProducer.AttributeChanged(Sender: TObject);
  838. begin
  839.   Changed;
  840. end;
  841.  
  842. procedure TDSTableProducer.BeginLayout;
  843. begin
  844.   BeginUpdate;
  845.   if FLayoutLock = 0 then FColumns.BeginUpdate;
  846.   Inc(FLayoutLock);
  847. end;
  848.  
  849. procedure TDSTableProducer.BeginUpdate;
  850. begin
  851.   Inc(FUpdateLock);
  852. end;
  853.  
  854. procedure TDSTableProducer.Changed;
  855. begin
  856.   if (FUpdateLock = 0) and Assigned(FEditor) then
  857.     FEditor.Changed
  858.   else FModified := True;
  859. end;
  860.  
  861. procedure TDSTableProducer.DefineFieldMap;
  862. var
  863.   I: Integer;
  864. begin
  865.   if FColumns.State = csCustom then
  866.   begin   { Build the column/field map from the column attributes }
  867.     DataLink.SparseMap := True;
  868.     for I := 0 to FColumns.Count - 1 do
  869.       FDataLink.AddMapping(FColumns[I].FieldName);
  870.   end
  871.   else   { Build the column/field map from the field list order }
  872.   begin
  873.     FDataLink.SparseMap := False;
  874.     with Datalink.Dataset do
  875.       for I := 0 to FieldCount - 1 do
  876.         with Fields[I] do Datalink.AddMapping(FieldName);
  877.   end;
  878. end;
  879.  
  880. function TDSTableProducer.DoCreateContent: Boolean;
  881. begin
  882.   Result := True;
  883.   if Assigned(FOnCreateContent) then
  884.     FOnCreateContent(Self, Result);
  885. end;
  886.  
  887. procedure TDSTableProducer.DoFormatCell(CellRow, CellColumn: Integer;
  888.   var BgColor: THTMLBgColor; var Align: THTMLAlign; var VAlign: THTMLVAlign;
  889.   var CustomAttrs, CellData: string);
  890. begin
  891.   if Assigned(FOnFormatCell) then
  892.     FOnFormatCell(Self, CellRow, CellColumn, BgColor, Align, VAlign, CustomAttrs, CellData);
  893. end;
  894.  
  895. procedure TDSTableProducer.DoGetCaption(var TableCaption: string;
  896.   var CaptionAlign: THTMLCaptionAlignment);
  897. begin
  898.   TableCaption := FCaption;
  899.   CaptionAlign := FCaptionAlignment;
  900.   if Assigned(FOnGetTableCaption) then
  901.     FOnGetTableCaption(Self, TableCaption, CaptionAlign);
  902. end;
  903.  
  904. procedure TDSTableProducer.EndLayout;
  905. begin
  906.   if FLayoutLock > 0 then
  907.   begin
  908.     try
  909.       try
  910.         if FLayoutLock = 1 then
  911.           InternalLayout;
  912.       finally
  913.         if FLayoutLock = 1 then
  914.           FColumns.EndUpdate;
  915.       end;
  916.     finally
  917.       Dec(FLayoutLock);
  918.       EndUpdate;
  919.     end;
  920.   end;
  921. end;
  922.  
  923. procedure TDSTableProducer.EndUpdate;
  924. begin
  925.   if (FUpdateLock = 1) and Assigned(FEditor) and (FModified or
  926.     (FInternalDataSource.DataSet = nil) or
  927.     ((FInternalDataSource.DataSet <> nil) and (FInternalDataSource.State = dsInactive))) then
  928.   begin
  929.     FModified := False;
  930.     FEditor.Changed;
  931.   end;
  932.   if FUpdateLock > 0 then
  933.     Dec(FUpdateLock);
  934. end;
  935.  
  936. function TDSTableProducer.GetDataSource: TDataSource;
  937. begin
  938.   Result := FDataLink.DataSource;
  939. end;
  940.  
  941. procedure TDSTableProducer.InternalLayout;
  942. var
  943.   I, J, K: Integer;
  944.   Fld: TField;
  945.   Column: THTMLTableColumn;
  946.   SeenDefColumn: Boolean;
  947.  
  948.   function FieldIsMapped(F: TField): Boolean;
  949.   var
  950.     X: Integer;
  951.   begin
  952.     Result := False;
  953.     if F <> nil then
  954.       for X := 0 to FDatalink.FieldCount - 1 do
  955.         if FDatalink.Fields[X] = F then
  956.         begin
  957.           Result := True;
  958.           Exit;
  959.         end;
  960.   end;
  961.  
  962. begin
  963.   if (csLoading in ComponentState) then Exit;
  964.   SeenDefColumn := False;
  965.   for I := 0 to FColumns.Count - 1 do
  966.   begin
  967.     if (FColumns[I] is TDefaultHTMLTableColumn) then
  968.       SeenDefColumn := True
  969.     else
  970.       if SeenDefColumn then
  971.       begin   { We have both custom and "passthrough columns". Kill the latter }
  972.         for J := FColumns.Count-1 downto 0 do
  973.         begin
  974.           Column := FColumns[J];
  975.           if Column is TDefaultHTMLTableColumn then
  976.             Column.Free;
  977.         end;
  978.         Break;
  979.       end;
  980.   end;
  981.   FDatalink.ClearMapping;
  982.   if FDatalink.Active then DefineFieldMap;
  983.   if FColumns.State = csDefault then
  984.   begin
  985.      { Destroy columns whose fields have been destroyed or are no longer
  986.        in field map }
  987.     if (not FDataLink.Active) and (FDatalink.DefaultFields) then
  988.       FColumns.Clear
  989.     else
  990.       for J := FColumns.Count - 1 downto 0 do
  991.         with FColumns[J] do
  992.           if not Assigned(Field)
  993.             or not FieldIsMapped(Field) then Free;
  994.     I := FDataLink.FieldCount;
  995.     for J := 0 to I - 1 do
  996.     begin
  997.       Fld := FDatalink.Fields[J];
  998.       if Assigned(Fld) then
  999.       begin
  1000.         K := J;
  1001.          { Pointer compare is valid here because the table sets matching
  1002.            column.field properties to nil in response to field object
  1003.            free notifications.  Closing a dataset that has only default
  1004.            field objects will destroy all the fields and set associated
  1005.            column.field props to nil. }
  1006.         while (K < FColumns.Count) and (FColumns[K].Field <> Fld) do
  1007.           Inc(K);
  1008.         if K < FColumns.Count then
  1009.           Column := FColumns[K]
  1010.         else
  1011.         begin
  1012.           Column := TDefaultHTMLTableColumn.Create(FColumns);
  1013.           Column.Field := Fld;
  1014.         end;
  1015.       end
  1016.       else
  1017.         Column := TDefaultHTMLTableColumn.Create(FColumns);
  1018.       Column.Index := J;
  1019.     end;
  1020.   end
  1021.   else
  1022.   begin
  1023.     { Force columns to reaquire fields (in case dataset has changed) }
  1024.     for I := 0 to FColumns.Count - 1 do
  1025.       FColumns[I].Field := nil;
  1026.   end;
  1027. end;
  1028.  
  1029. procedure TDSTableProducer.LayoutChanged;
  1030. begin
  1031.   if AcquireLayoutLock then EndLayout;
  1032. end;
  1033.  
  1034. procedure TDSTableProducer.LinkActive(Value: Boolean);
  1035. begin
  1036.   LayoutChanged;
  1037. end;
  1038.  
  1039. procedure TDSTableProducer.Notification(AComponent: TComponent; Operation: TOperation);
  1040. var
  1041.   I: Integer;
  1042. begin
  1043.   inherited Notification(AComponent, Operation);
  1044.   if (Operation = opRemove) and (FDataLink <> nil) then
  1045.     if (AComponent = DataSource)  then
  1046.       DataSource := nil
  1047.     else if (AComponent is TField) then
  1048.     begin
  1049.       BeginLayout;
  1050.       try
  1051.         for I := 0 to Columns.Count - 1 do
  1052.           with Columns[I] do
  1053.             if Field = AComponent then
  1054.               Field := nil;
  1055.       finally
  1056.         EndLayout;
  1057.       end;
  1058.     end;
  1059. end;
  1060.  
  1061. procedure TDSTableProducer.SetCaption(const Value: string);
  1062. begin
  1063.   FCaption := Value;
  1064.   Changed;
  1065. end;
  1066.  
  1067. procedure TDSTableProducer.SetCaptionAlignment(Value: THTMLCaptionAlignment);
  1068. begin
  1069.   if FCaptionAlignment <> Value then
  1070.   begin
  1071.     FCaptionAlignment := Value;
  1072.     Changed;
  1073.   end;
  1074. end;
  1075.  
  1076. procedure TDSTableProducer.SetColumns(Value: THTMLTableColumns);
  1077. begin
  1078.   Columns.Assign(Value);
  1079. end;
  1080.  
  1081. procedure TDSTableProducer.SetDataSource(Value: TDataSource);
  1082. begin
  1083.   if Value = FDatalink.Datasource then Exit;
  1084.   FDataLink.DataSource := Value;
  1085.   if Value <> nil then Value.FreeNotification(Self);
  1086.   if (Owner <> nil) and not (csLoading in Owner.ComponentState) then
  1087.     LinkActive(FDataLink.Active);
  1088. end;
  1089.  
  1090. procedure TDSTableProducer.SetFooter(Value: TStrings);
  1091. begin
  1092.   FFooter.Assign(Value);
  1093.   Changed;
  1094. end;
  1095.  
  1096. procedure TDSTableProducer.SetHeader(Value: TStrings);
  1097. begin
  1098.   FHeader.Assign(Value);
  1099.   Changed;
  1100. end;
  1101.  
  1102. procedure TDSTableProducer.SetMaxRows(Value: Integer);
  1103. begin
  1104.   if FMaxRows <> Value then
  1105.   begin
  1106.     FMaxRows := Value;
  1107.     Changed;
  1108.   end;
  1109. end;
  1110.  
  1111. procedure TDSTableProducer.SetRowAttributes(Value: THTMLTableRowAttributes);
  1112. begin
  1113.   FRowAttributes.Assign(Value);
  1114. end;
  1115.  
  1116. procedure TDSTableProducer.SetTableAttributes(Value: THTMLTableAttributes);
  1117. begin
  1118.   FTableAttributes.Assign(Value);
  1119. end;
  1120.  
  1121. function TDSTableProducer.StoreColumns: Boolean;
  1122. begin
  1123.   Result := Columns.State = csCustom;
  1124. end;
  1125.  
  1126. const
  1127.   Align: array[THTMLCaptionAlignment] of string =
  1128.     ('>',
  1129.      ' Align="Top">',
  1130.      ' Align="Bottom">');
  1131.   EndRow = '</TR>';
  1132.  
  1133. function TDSTableProducer.FormatCell(CellRow, CellColumn: Integer;
  1134.   CellData: string; const Tag: string; const BgColor: THTMLBgColor;
  1135.   Align: THTMLAlign; VAlign: THTMLVAlign; const Custom: string): string;
  1136. var
  1137.   CellAlign: THTMLAlign;
  1138.   CellVAlign: THTMLVAlign;
  1139.   CellBg: THTMLBgColor;
  1140.   CustomAttrs: string;
  1141. begin
  1142.   Result := Format('<%s', [Tag]);
  1143.   CellBg := BgColor;
  1144.   CellAlign := Align;
  1145.   CellVAlign := VAlign;
  1146.   CustomAttrs := Custom;
  1147.   DoFormatCell(CellRow, CellColumn, CellBg, CellAlign, CellVAlign, CustomAttrs,
  1148.     CellData);
  1149.   Result := Result + HTMLAlign[CellAlign];
  1150.   Result := Result + HTMLVAlign[CellVAlign];
  1151.   if CellBg <> '' then
  1152.     Result := Format('%s BgColor="%s"', [Result, CellBg]);
  1153.   if CustomAttrs <> '' then
  1154.     Result := Format('%s %s', [Result, CustomAttrs]);
  1155.   Result := Result + Format('>%s</%s>', [CellData, Tag]);
  1156. end;
  1157.  
  1158. function TDSTableProducer.RowHeader: string;
  1159. begin
  1160.   Result := '<TR';
  1161.   with RowAttributes do
  1162.   begin
  1163.     Result := Result + HTMLAlign[Align];
  1164.     Result := Result + HTMLVAlign[VAlign];
  1165.     if BgColor <> '' then
  1166.       Result := Format('%s BgColor="%s"', [Result, BgColor]);
  1167.     if Custom <> '' then
  1168.       Result := Format('%s %s', [Result, Custom]);
  1169.   end;
  1170.   Result := Result + '>';
  1171. end;
  1172.  
  1173. function TDSTableProducer.TableCaption: string;
  1174. var
  1175.   ACaption: string;
  1176.   CaptionAlign: THTMLCaptionAlignment;
  1177. begin
  1178.   ACaption := Caption;
  1179.   CaptionAlign := CaptionAlignment;
  1180.   DoGetCaption(ACaption, CaptionAlign);
  1181.   if ACaption <> '' then
  1182.     Result := Format('<Caption %s%s</Caption>', [Align[CaptionAlign], ACaption])
  1183.   else Result := '';
  1184. end;
  1185.  
  1186. function TDSTableProducer.TableHeader: string;
  1187. begin
  1188.   Result := '<Table';
  1189.   with TableAttributes do
  1190.   begin
  1191.     if Width > 0 then
  1192.       Result := Format('%s Width="%d%%"', [Result, Width]);
  1193.     Result := Result + HTMLAlign[Align];
  1194.     if CellSpacing > -1 then
  1195.       Result := Format('%s CellSpacing=%d', [Result, CellSpacing]);
  1196.     if CellPadding > -1 then
  1197.       Result := Format('%s CellPadding=%d', [Result, CellPadding]);
  1198.     if Border > -1 then
  1199.       Result := Format('%s Border=%d', [Result, Border]);
  1200.     if BgColor <> '' then
  1201.       Result := Format('%s BgColor="%s"', [Result, BgColor]);
  1202.     if Custom <> '' then
  1203.       Result := Format('%s %s', [Result, Custom]);
  1204.   end;
  1205.   Result := Result + '>';
  1206. end;
  1207.  
  1208. function TDSTableProducer.ColumnHeader: string;
  1209. var
  1210.   I: Integer;
  1211.   DisplayText: string;
  1212.   Field: TField;
  1213.   Column: THTMLTableColumn;
  1214. begin
  1215.   Result := '';
  1216.   for I := 0 to Columns.Count - 1 do
  1217.   begin
  1218.     Column := Columns[I];
  1219.     Field := Column.Field;
  1220.     if Column.Title.Caption <> '' then
  1221.       DisplayText := Column.Title.Caption
  1222.     else if Field <> nil then
  1223.       DisplayText := Field.DisplayLabel
  1224.     else DisplayText := Column.DisplayName;
  1225.     with Column.Title do
  1226.       Result := Result + FormatCell(0, I, DisplayText, 'TH',
  1227.         BgColor, Align, VAlign, Custom);
  1228.   end;
  1229. end;
  1230.  
  1231. { TQueryTableProducer }
  1232.  
  1233. function TQueryTableProducer.Content: string;
  1234. var
  1235.   Params: TStrings;
  1236.   I: Integer;
  1237.   Name: string;
  1238.   Param: TParam;
  1239. begin
  1240.   Result := '';
  1241.   if FQuery <> nil then
  1242.   begin
  1243.     FQuery.Close;
  1244.     Params := nil;
  1245.     if Dispatcher <> nil then
  1246.       if Dispatcher.Request.MethodType = mtPost then
  1247.         Params := Dispatcher.Request.ContentFields
  1248.       else if Dispatcher.Request.MethodType = mtGet then
  1249.         Params := Dispatcher.Request.QueryFields;
  1250.     if Params <> nil then
  1251.       for I := 0 to Params.Count - 1 do
  1252.       begin
  1253.         Name := Params.Names[I];
  1254.         Param := FQuery.Params.ParamByName(Name);
  1255.         if Param <> nil then
  1256.           Param.Text := Params.Values[Name];
  1257.       end;
  1258.     FQuery.Open;
  1259.     if DoCreateContent then
  1260.       Result := FHeader.Text + HTMLTable(FQuery, Self, FMaxRows) + FFooter.Text;
  1261.   end;
  1262. end;
  1263.  
  1264. function TQueryTableProducer.GetDataSet: TDataSet;
  1265. begin
  1266.   Result := FQuery;
  1267. end;
  1268.  
  1269. procedure TQueryTableProducer.Notification(AComponent: TComponent; Operation: TOperation);
  1270. begin
  1271.   inherited Notification(AComponent, Operation);
  1272.   if (Operation = opRemove) and (AComponent = FQuery) then
  1273.     FQuery := nil;
  1274. end;
  1275.  
  1276. procedure TQueryTableProducer.SetDataSet(ADataSet: TDataSet);
  1277. begin
  1278.   SetQuery(ADataSet as TQuery);
  1279. end;
  1280.  
  1281. procedure TQueryTableProducer.SetQuery(AQuery: TQuery);
  1282. begin
  1283.   if FQuery <> AQuery then
  1284.   begin
  1285.     if AQuery <> nil then AQuery.FreeNotification(Self);
  1286.     FQuery := AQuery;
  1287.     InternalDataSource.DataSet := FQuery;
  1288.   end;
  1289. end;
  1290.  
  1291. { TDataSetTableProducer }
  1292.  
  1293. function TDataSetTableProducer.Content: string;
  1294. begin
  1295.   Result := '';
  1296.   if FDataSet <> nil then
  1297.   begin
  1298.     if FDataSet.Active and (Columns.Count = 0) then LayoutChanged;
  1299.     if DoCreateContent then
  1300.       Result := FHeader.Text + HTMLTable(FDataSet, Self, FMaxRows) + FFooter.Text;
  1301.   end;
  1302. end;
  1303.  
  1304. function TDataSetTableProducer.GetDataSet: TDataSet;
  1305. begin
  1306.   Result := FDataSet;
  1307. end;
  1308.  
  1309. procedure TDataSetTableProducer.Notification(AComponent: TComponent; Operation: TOperation);
  1310. begin
  1311.   inherited Notification(AComponent, Operation);
  1312.   if (Operation = opRemove) and (AComponent = FDataSet) then
  1313.     FDataSet := nil;
  1314. end;
  1315.  
  1316. procedure TDataSetTableProducer.SetDataSet(ADataSet: TDataSet);
  1317. begin
  1318.   if FDataSet <> ADataSet then
  1319.   begin
  1320.     if ADataSet <> nil then ADataSet.FreeNotification(Self);
  1321.     FDataSet := ADataSet;
  1322.     InternalDataSource.DataSet := FDataSet;
  1323.   end;
  1324. end;
  1325.  
  1326. function HtmlTable(DataSet: TDataSet; DataSetHandler: TDSTableProducer;
  1327.   MaxRows: Integer): string;
  1328. var
  1329.   I, J: Integer;
  1330.   DisplayText, RowHeaderStr: string;
  1331.   Field: TField;
  1332.   Column: THTMLTableColumn;
  1333. begin
  1334.   RowHeaderStr := DataSetHandler.RowHeader;
  1335.   Result := DataSetHandler.TableHeader + DataSetHandler.TableCaption + #13#10 +
  1336.     RowHeaderStr;
  1337.   Result := Result + DataSetHandler.ColumnHeader + EndRow + #13#10;
  1338.   if DataSet.State = dsBrowse then
  1339.   begin
  1340.     J := 1;
  1341.     while (MaxRows <> 0) and not DataSet.EOF do
  1342.     begin
  1343.       Result := Result + RowHeaderStr;
  1344.       for I := 0 to DataSetHandler.Columns.Count - 1 do
  1345.       begin
  1346.         Column := DataSetHandler.Columns[I];
  1347.         Field := Column.Field;
  1348.         if Field <> nil then
  1349.           DisplayText := Field.DisplayText
  1350.         else DisplayText := '';
  1351.         with Column do
  1352.           Result := Result + DataSetHandler.FormatCell(J, I, DisplayText, 'TD',
  1353.             BgColor, Align, VAlign, Custom);
  1354.       end;
  1355.       Result := Result + EndRow + #13#10;
  1356.       DataSet.Next;
  1357.       Dec(MaxRows);
  1358.       Inc(J);
  1359.     end;
  1360.   end;
  1361.   Result := Result + '</Table>';
  1362. end;
  1363.  
  1364. end.
  1365.