{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

The Original Code is: JvDataSource.PAS, released on 08-07-2006.

The Initial Developer of the Original Code is Andreas Hausladen
[Andreas dott Hausladen att gmx dott com]
Portions created by Andreas Hausladen are Copyright (C) 2006 Andreas Hausladen.
All Rights Reserved.

Contributor(s):

You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net

Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvDataSource.pas 10872 2006-08-09 17:03:16Z outchy $

unit JvDataSource;

{$I jvcl.inc}

interface

uses
  SysUtils, Classes, JvDataSourceIntf, DB, DBConsts;

type
  TJvDataSource = class(TDataSource, IJvDataSource, IJvDataSourceConnectorHandler)
  private
    FDataLink: TDataLink;
    FDataConnectors: TList;
    FUpdateLock: Integer;
    FUpdateLookBookmark: TObject;
    function GetDataConnector(Index: Integer): TJvDataConnector;
    function GetDataConnectorCount: Integer;
  protected
    procedure DataConnectorsFreeNotification;
    procedure AddDataConnector(DataConnector: TJvDataConnector);
    procedure RemoveDataConnector(DataConnector: TJvDataConnector);

    function DataSet: TDataSet;
    procedure Notify(Msg: Integer);

    property DataConnectorCount: Integer read GetDataConnectorCount;
    property DataConnectors[Index: Integer]: TJvDataConnector read GetDataConnector; default;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    { IJvDataSource implementation }
  protected
    { DataSource }
    procedure Edit; // DataSource.Edit
    function GetState: TJvDataSetState;
    function GetAutoEdit: Boolean;
    function GetEnabled: Boolean;

    { DataSet }
  public
    function GetDataSet: TObject;
    procedure DataSetEdit; // DataSet.Edit
    function CanModify: Boolean;
    procedure First;
    procedure Last;
    procedure Next;
    procedure Prior;
    function Eof: Boolean;
    function Bof: Boolean;
    function RecordCount: Integer;
    function FieldByName(const FieldName: TDataFieldString): TObject;
    function FindField(const FieldName: TDataFieldString): TObject;
    procedure GetFieldNames(List: TStrings);
    function GetRecNo: Integer;
    procedure SetRecNo(Value: Integer);
    procedure Append;
    procedure Insert;
    procedure Post;
    procedure Cancel;
    procedure Delete;
    procedure Open;
    procedure Close;
    procedure MoveBy(Distance: Integer);
    function Locate(const KeyFields: string; const KeyValues: Variant;
      Options: TJvDBLocateOptions): Boolean;

    procedure BeginUpdate;
    procedure EndUpdate;
    
    property RecNo: Integer read GetRecNo write SetRecNo;

    { Fields }
    function GetFieldCount: Integer;
    function GetField(Index: Integer): TObject;
    function GetFieldName(Field: TObject): TDataFieldString;
    function GetFieldType(Field: TObject): TJvDBFieldType;
    function GetFieldSize(Field: TObject): Integer;
    function GetFieldDisplayLabel(Field: TObject): TDataFieldString;
    function GetFieldDisplayWidth(Field: TObject): Integer;
    procedure SetFieldDisplayWidth(Field: TObject; Value: Integer);
    function GetFieldEditMask(Field: TObject): TJvEditMask;
    function GetFieldReadOnly(Field: TObject): Boolean;
    function GetFieldVisible(Field: TObject): Boolean;
    function GetFieldRequired(Field: TObject): Boolean;
    procedure FieldClear(Field: TObject);
    function GetFieldIsNull(Field: TObject): Boolean;
    function GetFieldIsBlob(Field: TObject): Boolean;
    function GetFieldCanModify(Field: TObject): Boolean;

    function GetFieldOldValue(Field: TObject): Variant;
    function GetFieldValue(Field: TObject): Variant;
    procedure SetFieldValue(Field: TObject; const Value: Variant);
    function GetFieldString(Field: TObject): string;
    procedure SetFieldString(Field: TObject; const Value: string);
    function GetFieldWideString(Field: TObject): WideString;
    procedure SetFieldWideString(Field: TObject; const Value: WideString);
    function GetFieldInteger(Field: TObject): Integer;
    procedure SetFieldInteger(Field: TObject; const Value: Integer);
    function GetFieldFloat(Field: TObject): Double;
    procedure SetFieldFloat(Field: TObject; const Value: Double);
    function GetFieldDateTime(Field: TObject): TDateTime;
    procedure SetFieldDateTime(Field: TObject; const Value: TDateTime);
    function GetFieldBoolean(Field: TObject): Boolean;
    procedure SetFieldBoolean(Field: TObject; const Value: Boolean);

    property FieldCount: Integer read GetFieldCount;
    property Fields[Index: Integer]: TObject read GetField;
    property FieldName[Field: TObject]: TDataFieldString read GetFieldName;
    property FieldType[Field: TObject]: TJvDBFieldType read GetFieldType;
    property FieldSize[Field: TObject]: Integer read GetFieldSize;
    property FieldDisplayLabel[Field: TObject]: TDataFieldString read GetFieldDisplayLabel;
    property FieldDisplayWidth[Field: TObject]: Integer read GetFieldDisplayWidth write SetFieldDisplayWidth;
    property FieldEditMask[Field: TObject]: TJvEditMask read GetFieldEditMask;
    property FieldReadOnly[Field: TObject]: Boolean read GetFieldReadOnly;
    property FieldVisible[Field: TObject]: Boolean read GetFieldVisible;
    property FieldRequired[Field: TObject]: Boolean read GetFieldRequired;
    property FieldIsNull[Field: TObject]: Boolean read GetFieldIsNull;
    property FieldIsBlob[Field: TObject]: Boolean read GetFieldIsBlob;
    property FieldCanModify[Field: TObject]: Boolean read GetFieldCanModify;

    property FieldOldValue[Field: TObject]: Variant read GetFieldOldValue;
    property FieldValue[Field: TObject]: Variant read GetFieldValue write SetFieldValue;
    property FieldString[Field: TObject]: string read GetFieldString write SetFieldString;
    property FieldWideString[Field: TObject]: WideString read GetFieldWideString write SetFieldWideString;
    property FieldInteger[Field: TObject]: Integer read GetFieldInteger write SetFieldInteger;
    property FieldFloat[Field: TObject]: Double read GetFieldFloat write SetFieldFloat;
    property FieldDataTime[Field: TObject]: TDateTime read GetFieldDateTime write SetFieldDateTime;
    property FieldBoolean[Field: TObject]: Boolean read GetFieldBoolean write SetFieldBoolean;
  end;

  TJvDataSourceDataLink = class(TDataLink)
  private
    FDataSource: TJvDataSource;
  protected
    procedure ActiveChanged; override;
    procedure RecordChanged(Field: TField); override;
    procedure UpdateData; override;
    procedure LayoutChanged; override;
  public
    constructor Create(ADataSource: TJvDataSource);
  end;

implementation

{ TJvDataSourceDataLink }

constructor TJvDataSourceDataLink.Create(ADataSource: TJvDataSource);
begin
  inherited Create;
  FDataSource := ADataSource
end;

procedure TJvDataSourceDataLink.LayoutChanged;
begin
  //inherited LayoutChanged;
  FDataSource.Notify(DC_LAYOUTCHANGED);
end;

procedure TJvDataSourceDataLink.ActiveChanged;
begin
  FDataSource.Notify(DC_ACTIVECHANGED);
end;

procedure TJvDataSourceDataLink.RecordChanged(Field: TField);
begin
  FDataSource.Notify(DC_RECORDCHANGED);
end;

procedure TJvDataSourceDataLink.UpdateData;
begin
  FDataSource.Notify(DC_UPDATEDATA);
end;

{ TJvDataSource }

constructor TJvDataSource.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDataLink := TJvDataSourceDataLink.Create(Self);
  FDataConnectors := TList.Create;
  FDataLink.DataSource := Self;
end;

procedure TJvDataSource.DataConnectorsFreeNotification;
var
  I: Integer;
begin
  { Notify all DataConnectors by setting their DataSource property to NIL }
  I := FDataConnectors.Count - 1;
  while i >= 0 do
  begin
    DataConnectors[I].DataSource := nil;
    if I >= DataConnectorCount then
      I := DataConnectorCount - 1
    else
      Dec(I);
  end;
end;

destructor TJvDataSource.Destroy;
begin
  DataConnectorsFreeNotification;
  FDataLink.Free;
  FDataConnectors.Free;
  inherited Destroy;
end;

function TJvDataSource.GetDataConnector(Index: Integer): TJvDataConnector;
begin
  Result := TJvDataConnector(FDataConnectors[Index]);
end;

function TJvDataSource.GetDataConnectorCount: Integer;
begin
  Result := FDataConnectors.Count;
end;

procedure TJvDataSource.Notify(Msg: Integer);
var
  M: TJvDataConnectorMsg;
  I: Integer;
begin
  M.Msg := Msg;
  for I := 0 to DataConnectorCount - 1 do
    DataConnectors[I].Dispatch(M);
end;

procedure TJvDataSource.AddDataConnector(DataConnector: TJvDataConnector);
begin
  FDataConnectors.Add(DataConnector);
end;

procedure TJvDataSource.RemoveDataConnector(DataConnector: TJvDataConnector);
begin
  FDataConnectors.Remove(DataConnector);
end;

procedure TJvDataSource.Edit;
begin
  inherited Edit;
end;

function TJvDataSource.GetState: TJvDataSetState;
begin
  Result := TJvDataSetState(State);
end;

function TJvDataSource.GetAutoEdit: Boolean;
begin
  Result := AutoEdit;
end;

function TJvDataSource.GetEnabled: Boolean;
begin
  Result := Enabled;
end;

function TJvDataSource.DataSet: TDataSet;
begin
  Result := inherited DataSet;
  if not Assigned(Result) then
    raise EDatabaseError.CreateRes(@SDataSetClosed);
end;

function TJvDataSource.GetDataSet: TObject;
begin
  Result := inherited DataSet;
end;

procedure TJvDataSource.DataSetEdit;
begin
  DataSet.Edit;
end;

function TJvDataSource.CanModify: Boolean;
begin
  Result := Assigned(inherited DataSet) and DataSet.CanModify;
end;

procedure TJvDataSource.First;
begin
  DataSet.First;
end;

procedure TJvDataSource.Last;
begin
  DataSet.Last;
end;

procedure TJvDataSource.Next;
begin
  DataSet.Next;
end;

procedure TJvDataSource.Prior;
begin
  DataSet.Prior;
end;

function TJvDataSource.Eof: Boolean;
begin
  Result := DataSet.Eof;
end;

function TJvDataSource.Bof: Boolean;
begin
  Result := DataSet.Bof;
end;

function TJvDataSource.RecordCount: Integer;
begin
  Result := DataSet.RecordCount;
end;

function TJvDataSource.FieldByName(const FieldName: TDataFieldString): TObject;
begin
  Result := DataSet.FieldByName(FieldName);
end;

function TJvDataSource.FindField(const FieldName: TDataFieldString): TObject;
begin
  Result := DataSet.FindField(FieldName);
end;

procedure TJvDataSource.GetFieldNames(List: TStrings);
begin
  {$IFDEF COMPILER10_UP}
  {$WARN SYMBOL_DEPRECATED OFF}
  DataSet.GetFieldNames(List);
  {$WARN SYMBOL_DEPRECATED ON}
  {$ELSE}
  DataSet.GetFieldNames(List);
  {$ENDIF COMPILER10_UP}
end;

function TJvDataSource.GetRecNo: Integer;
begin
  Result := DataSet.RecNo;
end;

procedure TJvDataSource.SetRecNo(Value: Integer);
begin
  DataSet.RecNo := Value;
end;

procedure TJvDataSource.Append;
begin
  DataSet.Append;
end;

procedure TJvDataSource.Insert;
begin
  DataSet.Insert;
end;

procedure TJvDataSource.Post;
begin
  DataSet.Post;
end;

procedure TJvDataSource.Cancel;
begin
  DataSet.Cancel;
end;

procedure TJvDataSource.Delete;
begin
  DataSet.Delete;
end;

procedure TJvDataSource.Open;
begin
  DataSet.Open;
end;

procedure TJvDataSource.Close;
begin
  DataSet.Close;
end;

procedure TJvDataSource.MoveBy(Distance: Integer);
begin
  DataSet.MoveBy(Distance)
end;

function TJvDataSource.Locate(const KeyFields: string; const KeyValues: Variant;
  Options: TJvDBLocateOptions): Boolean;
begin
  Result := DataSet.Locate(KeyFields, KeyValues, TLocateOptions(Options));
end;

procedure TJvDataSource.BeginUpdate;
begin
  if FUpdateLock = 0 then
  begin
    DataSet.DisableControls;
    FUpdateLookBookmark := DataSet.GetBookmark;
  end;
  Inc(FUpdateLock);
end;

procedure TJvDataSource.EndUpdate;
begin
  Dec(FUpdateLock);
  if FUpdateLock = 0 then
  begin
    try
      try
        DataSet.GotoBookmark(FUpdateLookBookmark);
      except
      end;
      DataSet.FreeBookmark(FUpdateLookBookmark);
    finally
      DataSet.EnableControls;
    end;
  end;
end;

function TJvDataSource.GetFieldCount: Integer;
begin
  Result := DataSet.FieldCount;
end;

function TJvDataSource.GetField(Index: Integer): TObject;
begin
  Result := DataSet.Fields[Index];
end;

function TJvDataSource.GetFieldName(Field: TObject): TDataFieldString;
begin
  Result := TField(Field).FieldName;
end;

function TJvDataSource.GetFieldType(Field: TObject): TJvDBFieldType;
begin
  Result := TJvDBFieldType(TField(Field).DataType);
end;

function TJvDataSource.GetFieldSize(Field: TObject): Integer;
begin
  Result := TField(Field).Size;
end;

function TJvDataSource.GetFieldDisplayLabel(Field: TObject): TDataFieldString;
begin
  Result := TField(Field).DisplayLabel;
end;

function TJvDataSource.GetFieldDisplayWidth(Field: TObject): Integer;
begin
  Result := TField(Field).DisplayWidth;
end;

procedure TJvDataSource.SetFieldDisplayWidth(Field: TObject; Value: Integer);
begin
  TField(Field).DisplayWidth := Value;
end;

function TJvDataSource.GetFieldEditMask(Field: TObject): TJvEditMask;
begin
  Result := TField(Field).EditMask;
end;

function TJvDataSource.GetFieldReadOnly(Field: TObject): Boolean;
begin
  Result := TField(Field).ReadOnly;
end;

function TJvDataSource.GetFieldVisible(Field: TObject): Boolean;
begin
  Result := TField(Field).Visible;
end;

function TJvDataSource.GetFieldRequired(Field: TObject): Boolean;
begin
  Result := TField(Field).Required;
end;

procedure TJvDataSource.FieldClear(Field: TObject);
begin
  TField(Field).Clear;
end;

function TJvDataSource.GetFieldIsNull(Field: TObject): Boolean;
begin
  Result := TField(Field).IsNull
end;

function TJvDataSource.GetFieldIsBlob(Field: TObject): Boolean;
begin
  Result := TField(Field).IsBlob;
end;

function TJvDataSource.GetFieldCanModify(Field: TObject): Boolean;
begin
  Result := TField(Field).CanModify;
end;

function TJvDataSource.GetFieldOldValue(Field: TObject): Variant;
begin
  Result := TField(Field).OldValue;
end;

function TJvDataSource.GetFieldValue(Field: TObject): Variant;
begin
  Result := TField(Field).AsVariant;
end;

procedure TJvDataSource.SetFieldValue(Field: TObject; const Value: Variant);
begin
  TField(Field).AsVariant := Value;
end;

function TJvDataSource.GetFieldString(Field: TObject): string;
begin
  Result := TField(Field).AsString;
end;

procedure TJvDataSource.SetFieldString(Field: TObject; const Value: string);
begin
  TField(Field).AsString := Value;
end;

function TJvDataSource.GetFieldWideString(Field: TObject): WideString;
begin
  {$IFDEF COMPILER10_UP}
  Result := TField(Field).AsWideString;
  {$ELSE}
  Result := TField(Field).AsString;
  {$ENDIF COMPILER10_UP}
end;

procedure TJvDataSource.SetFieldWideString(Field: TObject; const Value: WideString);
begin
  {$IFDEF COMPILER10_UP}
  TField(Field).AsWideString := Value;
  {$ELSE}
  TField(Field).AsString := Value;
  {$ENDIF COMPILER10_UP}
end;

function TJvDataSource.GetFieldInteger(Field: TObject): Integer;
begin
  Result := TField(Field).AsInteger;
end;

procedure TJvDataSource.SetFieldInteger(Field: TObject; const Value: Integer);
begin
  TField(Field).AsInteger := Value;
end;

function TJvDataSource.GetFieldFloat(Field: TObject): Double;
begin
  Result := TField(Field).AsFloat;
end;

procedure TJvDataSource.SetFieldFloat(Field: TObject; const Value: Double);
begin
  TField(Field).AsFloat := Value;
end;

function TJvDataSource.GetFieldDateTime(Field: TObject): TDateTime;
begin
  Result := TField(Field).AsDateTime;
end;

procedure TJvDataSource.SetFieldDateTime(Field: TObject; const Value: TDateTime);
begin
  TField(Field).AsDateTime := Value;
end;

function TJvDataSource.GetFieldBoolean(Field: TObject): Boolean;
begin
  Result := TField(Field).AsBoolean;
end;

procedure TJvDataSource.SetFieldBoolean(Field: TObject; const Value: Boolean);
begin                                         
  TField(Field).AsBoolean := Value;
end;

end.

