{***************************************************************************}
{ TMS IntraWeb Component Pack Pro                                           }
{ for Delphi & C++Builder                                                   }
{                                                                           }
{ written by TMS Software                                                   }
{            copyright © 2002 - 2008                                        }
{            Email : info@tmssoftware.com                                   }
{            Web : http://www.tmssoftware.com                               }
{                                                                           }
{ The source code is given as is. The author is not responsible             }
{ for any possible damage done due to the use of this code.                 }
{ The component can be freely used in any application. The complete         }
{ source code remains property of the author and may not be distributed,    }
{ published, given or sold in any form as such. No parts of the source      }
{ code can be included in any other component or application without        }
{ written authorization of the author.                                      }
{***************************************************************************}

unit IWDBTMSCtrls;

interface

{$I TMSDEFS.INC}

uses
  {$IFDEF LINUX}
  QControls, QGraphics,
  {$ELSE}
  Controls, Windows, Graphics,
  {$ENDIF}
  Classes, IWTMSCtrls, IWTMSCal, DB, SysUtils, IWCompListBox,
  IWHTMLTag, IWTMSBase
  {$IFDEF TMSIW6}
  , IWRenderContext
  {$ENDIF}
  {$IFDEF TMSIW9}
  ,IWXMLTag
  {$ENDIF}
  ;

type
  TTIWDBHTMLLabel = class;

  TTIWDBHTMLLabel = class(TTIWHTMLLabel)
  private
    FDataSource: TDataSource;
    FDBHTMLText:string;
    function GetDataSource: TDataSource;
    procedure SetDataSource(const Value: TDataSource);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    function HTMLDBReplace(s:string; DataSet: TDataSet):string;
    procedure DBUpdate;
  public
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure UpdateHTML;
    function GetDisplText: string; override;
  published
    property Datasource:  TDataSource read GetDataSource write SetDataSource;
  end;

  TTIWDBAdvEdit = class(TTIWAdvEdit)
  private
    FAutoEditable: Boolean;
    FDataField: string;
    FDataSource: TDataSource;
  protected
    {$IFDEF TMSIW9}
    function RenderAsync(AContext: TIWBaseHTMLComponentContext): TIWXMLTag; override;
    {$ENDIF}
  public
    constructor Create(AOwner: TComponent); override;
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;    
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    procedure SetValue(const AValue: string); override;
  published
    property AutoEditable: Boolean read FAutoEditable write FAutoEditable default true;
    property DataField: string read FDataField write FDataField;
    property DataSource: TDataSource read FDataSource write FDataSource;
  end;

  TTIWDBAdvLUEdit = class(TTIWAdvLUEdit)
  private
    FAutoEditable: Boolean;
    FDataField: string;
    FDataSource: TDataSource;
  protected
    {$IFDEF TMSIW9}
    function RenderAsync(AContext: TIWBaseHTMLComponentContext): TIWXMLTag; override;
    {$ENDIF}
  public
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    procedure SetValue(const AValue: string); override;
  published
    property AutoEditable: Boolean read FAutoEditable write FAutoEditable;
    property DataField: string read FDataField write FDataField;
    property DataSource: TDataSource read FDataSource write FDataSource;
  end;

  TTIWDBCountryComboBox = class(TTIWCountryComboBox)
  private
    FAutoEditable: Boolean;
    FCountryField : string;
    FCountrySource : TDataSource;
    FDataField: string;
    FDataSource: TDataSource;
  protected
  public
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    procedure SetValue(const AValue: string); override;
  published
    property AutoEditable: Boolean read FAutoEditable write FAutoEditable;
    property CountryField : string read FCountryField write FCountryField;
    property CountrySource : TDataSource read FCountrySource write FCountrySource;
    property DataField: string read FDataField write FDataField;
    property DataSource: TDataSource read FDataSource write FDataSource;
  end;

  TTIWDBStateComboBox = class(TTIWStateComboBox)
  private
    FAutoEditable: Boolean;
    FStateField : string;
    FStateSource : TDataSource;
    FDataField: string;
    FDataSource: TDataSource;
  protected
  public
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    procedure SetValue(const AValue: string); override;
  published
    property AutoEditable: Boolean read FAutoEditable write FAutoEditable;
    property DataField: string read FDataField write FDataField;
    property DataSource: TDataSource read FDataSource write FDataSource;
    property StateField : string read FStateField write FStateField;
    property StateSource : TDataSource read FStateSource write FStateSource;
  end;

  TTIWDBCalendar = class(TTIWCalendar)
  private
    FAutoEditable: Boolean;
    FDataField: string;
    FDataSource: TDataSource;
  protected
  public
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    procedure SetValue(const AValue: String); override;
  published
    property AutoEditable: Boolean read FAutoEditable write FAutoEditable;
    property DataField: string read FDataField write FDataField;
    property DataSource: TDataSource read FDataSource write FDataSource;
  end;

  TTIWDBDatePicker = class(TTIWCustomDatePicker)
  private
    FAutoEditable: Boolean;
    FDataField: string;
    FDataSource: TDataSource;
    FFullTime: TDateTime;
  protected
  public
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    constructor Create(AOwner: TComponent); override;
    procedure SetValue(const AValue: string); override;
  published
    property AutoEditable: Boolean read FAutoEditable write FAutoEditable default true;
    property DataField: string read FDataField write FDataField;
    property DataSource: TDataSource read FDataSource write FDataSource;
    property BorderColor;
    property BorderWidth;
    property CalendarFont;
    property CalendarWidth;
    property CalendarHeight;
    property ClientEvents;
    property Color;
    property DateSep;
    property DisabledAppearance;
    property DropDownImage;
    property EditorEnabled;
    property Flat;
    property FocusColor;
    property Font;
    property HoverColor;
    property TodayColor;
    property MonthColor;
    property MonthTextColor;
    property DateFormat;
    property Day;
    property Enabled;
    property Month;
    property Year;
    property NameOfMonths;
    property NameOfDays;
    property NullIsToday;
    property TabOrder;
    property BorderCollapse;
    property ShowNextMonth;
    property ShowPrevMonth;
    property ShowNextYear;
    property ShowPrevYear;
    property HintPrevYear;
    property HintNextYear;
    property HintNextMonth;
    property HintPrevMonth;
    property OnClick;
    property BackgroundImage;
    property Glyphs;
    property GradientStartColor;
    property GradientEndColor;
    property GradientDirection;
    property GridLineWidth;
    property GridLineColor;
    property MonthGradientStartColor;
    property MonthGradientEndColor;
    property MonthGradientDirection;
    property StartDay;
    property Transparency;
    property WeekendColor;
    property WeekendTextColor;
  end;

  function InEditMode(ADataset: TDataset): Boolean;
  function CheckDataSource(ADataSource: TDataSource): Boolean; overload;
  function CheckDataSource(ADataSource: TDataSource; const AFieldName: string; var VField: TField): Boolean; overload;
  
implementation

uses
  IWApplication, IWServerControllerBase;

function InEditMode(ADataset: TDataset): Boolean;
begin
  Result := ADataset.State in [dsEdit, dsInsert];
end;

function CheckDataSource(ADataSource: TDataSource): boolean; overload;
begin
  Result := False;
  if ADataSource <> nil then
  begin
    if ADataSource.Dataset <> nil then
  begin
      Result := ADataSource.Dataset.Active;
    end;
  end;
end;

function CheckDataSource(ADataSource: TDataSource; const AFieldName: string; var VField: TField)
 : boolean;
begin
  Result := CheckDataSource(ADataSource) and (Length(AFieldName) > 0);
  if Result then begin
    VField := ADataSource.Dataset.FieldByName(AFieldName);
  end;
end;

function TTIWDBHTMLLabel.HTMLDBReplace(s:string; DataSet: TDataSet):string;
var
  BeforeTag,AfterTag,Fld,DBFld:string;
  i,j: Integer;
  DBField: TField;
  LPathName: string;
  bmp: TBitmap;

  function VarPos(su,s: string; var Res: Integer): Integer;
  begin
    Res := Pos(su,s);
    Result := Res;
  end;

begin
  i := 1;

  BeforeTag := '';

  while VarPos('(#',s,i) > 0 do
  begin
    BeforeTag := BeforeTag + Copy(s,1,i - 1); //part prior to the tag
    AfterTag := Copy(s,i,Length(s)); //part after the tag

    j := Pos(')',AfterTag);
    if j = 0 then
      Break;
       
    Fld := Copy(AfterTag,1,j - 1);

    Delete(Fld,1,2);
    Delete(s,1,i + j - 1);

    DBFld := '';

    if Assigned(DataSet) and (DBFld = '') then
    begin
      if DataSet.Active then
      begin
        if Assigned(DataSet.FindField(Fld)) then
        begin
          DBField := DataSet.FieldByName(fld);
          if DBField.DataType <> ftGraphic then
            DBFld := DBField.DisplayText
          else
          begin
            if not (csDesigning in ComponentState) then
            begin
              {$IFDEF TMSIW71}
              LPathname := TIWServerControllerBase.NewCacheFile('bmp',true);
              {$ELSE}
              LPathname := TIWServerControllerBase.NewCacheFile('bmp');
              {$ENDIF}
              bmp := TBitmap.Create;
              bmp.Assign(DBField);
              bmp.SaveToFile(LPathname);
              DBFld := GetCacheDir(Self) + ExtractFilename(LPathname);
              bmp.Free;
            end
            else
            begin
              bmp := TBitmap.Create;
              bmp.Assign(DBField);
              bmp.SaveToFile('tmp.bmp');
              DBFld := 'file://'+GetCurrentDir + '/tmp.bmp';
              bmp.Free;
            end;
          end;
        end;
      end
      else
        DBfld := '['+fld+']';
    end
    else
     if DBFld='' then DBfld := '['+fld+']';

    BeforeTag := BeforeTag + DBFld;
  end;

  Result := Beforetag + s;
end;


{ TDBHTMLabel }

constructor TTIWDBHTMLLabel.Create(AOwner: TComponent);
begin
  inherited;
end;

procedure TTIWDBHTMLLabel.DBUpdate;
begin
  if Assigned(Datasource) then
  begin
    if Assigned(DataSource.DataSet) then
    begin
      if DataSource.DataSet.Active then
      begin
        FDBHTMLText := HTMLDBReplace(HTMLText,Datasource.Dataset);
      end
      else
        FDBHTMLText := HTMLDBReplace(HTMLText,nil);
    end
    else
      FDBHTMLText := HTMLDBReplace(HTMLText,nil);
  end
  else
  begin
    FDBHTMLText := HTMLDBReplace(HTMLText,nil);
  end;

  //FDBHTMLText := HTMLText;
end;

destructor TTIWDBHTMLLabel.Destroy;
begin
  inherited;
end;

function TTIWDBHTMLLabel.GetDataSource: TDataSource;
begin
  Result := FDataSource;
end;


procedure TTIWDBHTMLLabel.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (AComponent = DataSource) then
    DataSource := nil;
end;

procedure TTIWDBHTMLLabel.SetDataSource(const Value: TDataSource);
begin
  FDataSource := Value;
  DBUpdate;
end;

procedure TTIWDBHTMLLabel.UpdateHTML;
begin
  DBUpdate;
end;

{$IFDEF TMSIW6}
function TTIWDBHTMLLabel.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWDBHTMLLabel.RenderHTML: TIWHTMLTag;
{$ENDIF}
begin
  Result := TIWHTMLTag.CreateTag('DIV');
  Result.Contents.AddText(GetDisplText);
end;

function TTIWDBHTMLLabel.GetDisplText: string;
begin
  DBUpdate;
  Result := FDBHTMLText;
end;

{ TTIWDBAdvEdit }

{$IFDEF TMSIW9}
function TTIWDBAdvEdit.RenderAsync(
  AContext: TIWBaseHTMLComponentContext): TIWXMLTag;
var
  LField: TField;
begin

  if CheckDataSource(DataSource, DataField, LField) then
  begin
    if AutoEditable then
    begin
      Editable := InEditMode(DataSource.Dataset);
    end;

    if (DataSource.DataSet.State in [dsInsert,dsEdit]) then
      Text := LField.AsString
    else
      Text := LField.DisplayText;
  end;


  Result := inherited RenderAsync(AContext);
end;
{$ENDIF}

constructor TTIWDBAdvEdit.Create(AOwner: TComponent);
begin
  inherited;
  FAutoEditable := true;
end;


{$IFDEF TMSIW6}
function TTIWDBAdvEdit.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWDBAdvEdit.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  LField: TField;
begin
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    if AutoEditable then
    begin
      Editable := InEditMode(DataSource.Dataset);
    end;
    if (DataSource.DataSet.State in [dsInsert,dsEdit]) then
      Text := LField.AsString
    else
      Text := LField.DisplayText;
  end
  else
  begin
    Text := '';
    if AutoEditable then
    begin
      Editable := False;
    end;
  end;
  {$IFDEF TMSIW6}
  Result := inherited RenderHTML(AContext);  
  {$ELSE}
  Result := inherited RenderHTML;
  {$ENDIF}
end;


procedure TTIWDBAdvEdit.SetValue(const AValue: string);
var
  LField: TField;
begin
  inherited;
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    if LField.DisplayText <> Text then
    begin
      Datasource.Edit;
      LField.Text := Text;
    end;
  end;
end;


{ TTIWDBAdvLUEdit }

{$IFDEF TMSIW9}
function TTIWDBAdvLUEdit.RenderAsync(
  AContext: TIWBaseHTMLComponentContext): TIWXMLTag;
var                 
  LField: TField;
begin

  if CheckDataSource(DataSource, DataField, LField) then
  begin
    if AutoEditable then
    begin
      Editable := InEditMode(DataSource.Dataset);
    end;

    if (DataSource.DataSet.State in [dsInsert,dsEdit]) then
      Text := LField.AsString
    else
      Text := LField.DisplayText;
  end;

  Result := inherited RenderAsync(AContext);
end;
{$ENDIF}



{$IFDEF TMSIW6}
function TTIWDBAdvLUEdit.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWDBAdvLUEdit.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  LField: TField;
begin
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    if AutoEditable then
    begin
      Editable := InEditMode(DataSource.Dataset);
    end;

    if (DataSource.DataSet.State in [dsInsert,dsEdit]) then
      Text := LField.AsString
    else
      Text := LField.DisplayText;
  end
  else
  begin
    Text := '';
    if AutoEditable then
    begin
      Editable := False;
    end;
  end;
  {$IFDEF TMSIW6}
  Result := inherited RenderHTML(AContext);
  {$ELSE}
  Result := inherited RenderHTML;
  {$ENDIF}
end;

procedure TTIWDBAdvLUEdit.SetValue(const AValue: string);
var
  LField: TField;
begin
  inherited;
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    if LField.DisplayText <> Text then
    begin
      Datasource.Edit;
      LField.Text := Text;
    end;
  end;
end;

{ TTIWDBCalendar }

{$IFDEF TMSIW6}
function TTIWDBCalendar.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWDBCalendar.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  LField: TField;
begin
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    Date := LField.AsDateTime;
    if AutoEditable then
    begin
      Editable := InEditMode(DataSource.Dataset);
    end;
  end
  else
  begin
    Date := Now;
    if AutoEditable then
    begin
      Editable := False;
    end;
  end;
  {$IFDEF TMSIW6}
  Result := inherited RenderHTML(AContext);  
  {$ELSE}
  Result := inherited RenderHTML;
  {$ENDIF}
end;

procedure TTIWDBCalendar.SetValue(const AValue: string);
var
  LField: TField;
begin
  inherited;
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    if LField.AsDateTime <> Date then
    begin
      Datasource.Edit;
      LField.AsDateTime := Date;
    end;
  end;

end;

{ TTIWDBDatePicker }

constructor TTIWDBDatePicker.Create(AOwner: TComponent);
begin
  inherited;
  {$IFDEF TMSIW6}
  {TODO}
  {$ELSE}
  FSupportsInput := True;
  FSupportsSubmit := True;
  {$ENDIF}
  FAutoEditable := True;
end;

{$IFDEF TMSIW6}
function TTIWDBDatePicker.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWDBDatePicker.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  LField: TField;
begin
  FFullTime := 0;
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    Enabled := (DataSource.Dataset.State in [dsEdit,dsInsert]) and AutoEditable;

    if (LField.IsNull) then
    begin
      if NullIsToday then
        Date := Now
      else
        Date := 0;
    end
    else
    begin
      Date := LField.AsDateTime;
      FFullTime := LField.AsDateTime;
    end;

    if AutoEditable then
    begin
      Editable := InEditMode(DataSource.Dataset);
    end;
  end
  else
  begin
    Enabled := False;
    Date := Now;
    if AutoEditable then
    begin
      Editable := False;
    end;
  end;
  {$IFDEF TMSIW6}
  Result := inherited RenderHTML(AContext);
  {$ELSE}
  Result := inherited RenderHTML;
  {$ENDIF}
end;

procedure TTIWDBDatePicker.SetValue(const AValue: string);
var
  LField: TField;
begin
  inherited;

  if not Enabled then
    Exit;
    
  if CheckDataSource(DataSource, DataField, LField) then
  begin

    if (LField.AsDateTime <> Date) or (LField.AsString = '') then
    begin
      Datasource.Edit;
      if Date = 0 then
        LField.SetData(nil)
      else
        LField.AsDateTime := Date + Frac(FFullTime);

    end;
  end;
end;


{ TTIWDBCountryComboBox }

{$IFDEF TMSIW6}
function TTIWDBCountryComboBox.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWDBCountryComboBox.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  LField: TField;
begin
  if CheckDataSource(CountrySource, CountryField, LField) then
  begin
    if Assigned(CountrySource) then
    begin
      Items.Clear;
      CountrySource.DataSet.First;
      while not (CountrySource.DataSet.Eof) do
      begin
        Items.Add(LField.Text);
        CountrySource.DataSet.Next;
      end;
    end;
  end;
  if CheckDataSource(DataSource,DataField,LField) then
    ItemIndex := Items.IndexOf(LField.Text);
  {$IFDEF TMSIW6}
  Result := inherited RenderHTML(AContext);
  {$ELSE}
  Result := inherited RenderHTML;
  {$ENDIF}
end;

procedure TTIWDBCountryComboBox.SetValue(const AValue: string);
var
  LField: TField;
begin
  inherited;
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    Datasource.Edit;
    if (StrToInt(Avalue) = -1) then
       LField.Text := Items[0]
    else
    LField.Text := Items[StrToInt(AValue)];
  end;
end;

{ TTIWDBStateComboBox }
{$IFDEF TMSIW6}
function TTIWDBStateComboBox.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWDBStateComboBox.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  LField: TField;
begin
  if CheckDataSource(StateSource, StateField, LField) then
  begin
    if Assigned(StateSource) then
    begin
      Items.Clear;
      StateSource.DataSet.First;
      while not (StateSource.DataSet.Eof) do
      begin
        Items.Add(LField.Text);
        StateSource.DataSet.Next;
      end;
    end;
  end;
  if CheckDataSource(DataSource,DataField,LField) then
    ItemIndex := Items.IndexOf(LField.Text);
  {$IFDEF TMSIW6}
  Result := inherited RenderHTML(AContext);
  {$ELSE}
  Result := inherited RenderHTML;
  {$ENDIF}
end;

procedure TTIWDBStateComboBox.SetValue(const AValue: string);
var
  LField: TField;
begin
  inherited;
  if CheckDataSource(DataSource, DataField, LField) then
  begin
    Datasource.Edit;
    if (StrToInt(Avalue) = -1) then
       LField.Text := Items[0]
    else
    LField.Text := Items[StrToInt(AValue)];
  end;
end;




end.
