rmd_dbwrap.pas

来自「report machine 2.3 功能强大」· PAS 代码 · 共 871 行 · 第 1/2 页

PAS
871
字号

{*****************************************}
{                                         }
{           Report Machine v2.0           }
{        Wrapper for Table & Query        }
{                                         }
{*****************************************}

unit RMD_DBWrap;

interface

{$I RM.inc}

uses
  Classes, SysUtils, Controls, Forms, Menus, DB, RM_Class, RM_DBSet, RM_Pars
{$IFDEF Delphi6}, Variants{$ENDIF};

const
  RMFieldClasses: array[0..9] of TFieldClass = (
    TStringField, TSmallintField, TIntegerField, TWordField,
    TBooleanField, TFloatField, TCurrencyField, TDateField,
    TTimeField, TBlobField);

  RMParamTypes: array[0..10] of TFieldType = (
    ftBCD, ftBoolean, ftCurrency, ftDate, ftDateTime, ftInteger,
    ftFloat, ftSmallint, ftString, ftTime, ftWord);

type
  TRMParamKind = (rmpkValue, rmpkAssignFromMaster);

 { TRMDDataSet }
  TRMDDataSet = class(TRMNonVisualControl)
  private
    FDataSet: TDataSet;
    procedure P1Click(Sender: TObject);
    procedure SetDataSet(Value: TDataSet);
    function GetDatabaseName: string;
    procedure SetDatabaseName(const Value: string);
  protected
		FCanBrowse: Boolean;
  	FHaveFilter: Boolean;
    FDataSource: TDataSource;
    FDBDataSet: TRMDBDataset;
    procedure FieldsEditor(Sender: TObject);
    procedure SetPropValue(Index: string; Value: Variant); override;
    function GetPropValue(Index: string): Variant; override;
    function DoMethod(const MethodName: string; Par1, Par2, Par3: Variant): Variant; override;

    function GetDatabases: string; virtual; abstract;  //获取数据库列表
  public
    constructor Create; override;
    destructor Destroy; override;
    procedure DefineProperties; override;
    procedure Loaded; override;
    procedure ShowEditor; override;
    procedure LoadFromStream(Stream: TStream); override;
    procedure SaveToStream(Stream: TStream); override;
    procedure DefinePopupMenu(Popup: TPopupMenu); override;

    property DataSet: TDataSet read FDataSet write SetDataSet;
    property DatabaseName: string read GetDatabaseName write SetDatabaseName;
  published
  end;

 { TRMDTable }
  TRMDTable = class(TRMDDataSet)
  private
    procedure JoinEditor(Sender: TObject);
  protected
    function GetTableNames: string; virtual; abstract; //获取表列表
    procedure GetIndexNames(sl: TStrings); virtual; abstract; //获取索引列表
  public
    procedure DefineProperties; override;
    procedure LoadFromStream(Stream: TStream); override;
    procedure SaveToStream(Stream: TStream); override;
    procedure Loaded; override;
  published
  end;

  { TRMDQuery }
  TRMDQuery = class(TRMDDataSet)
  private
    FEditSQLAsText: Boolean;
    FVisualSQL: TStringList;
    FParamCount: Integer;
    FOnSQLTextChanged: TNotifyEvent;
    procedure SQLEditor(Sender: TObject);
    procedure ParamsEditor(Sender: TObject);
    function GetParamCount: Integer;
    function GetSQL: string;
    procedure SetSQL(aSql: string);
  protected
    FParams: TRMVariables;
    procedure OnBeforeOpenQueryEvent(DataSet: TDataSet); virtual;

    function GetParamName(Index: Integer): string; virtual; abstract;
    function GetParamType(Index: Integer): TFieldType; virtual; abstract;
    procedure SetParamType(Index: Integer; Value: TFieldType); virtual; abstract;
    function GetParamKind(Index: Integer): TRMParamKind; virtual; abstract;
    procedure SetParamKind(Index: Integer; Value: TRMParamKind); virtual; abstract;
    function GetParamText(Index: Integer): string; virtual; abstract;
    procedure SetParamText(Index: Integer; Value: string); virtual; abstract;
    function GetParamValue(Index: Integer): Variant; virtual; abstract;
    procedure SetParamValue(Index: Integer; Value: Variant); virtual; abstract;
    procedure GetTableNames(DB: string; Strings: TStrings); virtual; abstract;

    procedure GetTableFieldNames(const DB, TName: string; sl: TStrings); virtual; abstract; //获取表的字段名称列表
 public
    constructor Create; override;
    destructor Destroy; override;
    procedure DefineProperties; override;
    procedure Loaded; override;
    procedure LoadFromStream(Stream: TStream); override;
    procedure SaveToStream(Stream: TStream); override;
    function ParamIndex(const ParName: string): Integer;

    property EditSQLAsText: Boolean read FEditSQLAsText write FEditSQLAsText;
    property SQL: string read GetSQL write SetSQL;
    property VisualSQL: TStringList read FVisualSQL write FVisualSQL;

    property ParamCount: Integer read GetParamCount;
    property ParamName[Index: Integer]: string read GetParamName; //取得参数的名称
    property ParamType[Index: Integer]: TFieldType read GetParamType write SetParamType; //取得(设置)参数类型
    property ParamKind[Index: Integer]: TRMParamKind read GetParamKind write SetParamKind; //取得(设置)参数初始化类型
    property ParamText[Index: Integer]: string read GetParamText write SetParamText; //取得(设置)参数初始化值
    property ParamValue[Index: Integer]: Variant read GetParamValue write SetParamValue; //取得(设置)参数值

		property OnSQLTextChanged: TNotifyEvent read FOnSQLTextChanged write FOnSQLTextChanged;
   published
  end;

function RMFindFieldDef(DataSet: TDataSet; FieldName: string): TFieldDef;
function RMGetDataSetName(Owner: TComponent; d: TDataSource): string;
function RMGetDataSource(Owner: TComponent; d: TDataSet): TDataSource;

implementation

uses RM_Const, RM_Utils, RMD_DBFldEditor, RMD_md, RMD_QueryParm, RMD_QryDesigner,
  RMD_DataPrv, RM_DCtrl, RM_DBCtrls;

function RMFindFieldDef(DataSet: TDataSet; FieldName: string): TFieldDef;
var
  i: Integer;
begin
  Result := nil;
  with DataSet do
  begin
    for i := 0 to FieldDefs.Count - 1 do
    begin
      if AnsiCompareText(FieldDefs.Items[i].Name, FieldName) = 0 then
      begin
        Result := FieldDefs.Items[i];
        break;
      end;
    end;
  end;
end;

function RMGetDataSetName(Owner: TComponent; d: TDataSource): string;
begin
  Result := '';
  if (d <> nil) and (d.DataSet <> nil) then
  begin
    Result := d.Dataset.Name;
    if d.Dataset.Owner <> Owner then
      Result := d.Dataset.Owner.Name + '.' + Result;
  end;
end;

function RMGetDataSource(Owner: TComponent; d: TDataSet): TDataSource;
var
  i: Integer;
  sl: TStringList;
  ds: TDataSource;
begin
  sl := TStringList.Create;
  Result := nil;
  RMGetComponents(Owner, TDataSource, sl, nil);
  for i := 0 to sl.Count - 1 do
  begin
    ds := RMFindComponent(Owner, sl[i]) as TDataSource;
    if (ds <> nil) and (ds.DataSet = d) then
    begin
      Result := ds;
      break;
    end;
  end;
  sl.Free;
end;


{------------------------------------------------------------------------------}
{------------------------------------------------------------------------------}
{TRMDDataset}

constructor TRMDDataset.Create;
begin
  inherited Create;
  FDataSource := TDataSource.Create(RMDialogForm);
  FDataSource.DataSet := nil;

  FDBDataSet := TRMDBDataSet.Create(RMDialogForm);
  FDBDataSet.DataSource := FDataSource;

  Flags := Flags or flDontUndo;
  FCanBrowse := True;
	FHaveFilter := True;
end;

destructor TRMDDataset.Destroy;
begin
	if Assigned(RMDialogForm) then
  begin
	  FDBDataset.Free;
  	FDataSource.Free;
	  FDataSet.Free;
  end;
  inherited Destroy;
end;

procedure TRMDDataset.DefineProperties;
begin
  inherited DefineProperties;
  AddProperty('Active', [rmdtBoolean], nil);
  AddEnumProperty('Database', GetDatabases, [Null]);
  AddProperty('Fields', [rmdtHasEditor, rmdtOneObject], FieldsEditor);
  AddProperty('FieldCount', [], nil);
	if FHaveFilter then
	  AddProperty('Filter', [rmdtString], nil);
  AddProperty('EOF', [], nil);
  AddProperty('RecordCount', [], nil);
{$IFNDEF Delphi2}
  AddProperty('IsEmpty', [], nil);
{$ENDIF}
end;

procedure TRMDDataset.SetPropValue(Index: string; Value: Variant);
var
	d: TComponent;
  ds: TDataSource;
begin
  inherited SetPropValue(Index, Value);
  Index := AnsiUpperCase(Index);
  if Index = 'NAME' then
  begin
    FDataSource.Name := 'S' + FDataSet.Name;
    FDBDataSet.Name := '_' + FDataSet.Name;
  end
  else if Index = 'ACTIVE' then
  begin
		if Boolean(Value) and (Self is TRMDQuery) then
    begin
	    d := RMFindComponent(FDataSet.Owner, Prop['DataSource']);
      if d <> nil then
      begin
	  	  ds := RMGetDataSource(FDataSet.Owner, TDataSet(d));
	      if (ds <> nil) and (ds.DataSet <> nil) then
  	    	ds.DataSet.Open;
      end;
		end;
    FDataSet.Active := Value;
  end
  else if Index = 'FILTER' then
  begin
    FDataSet.Filter := Value;
    FDataSet.Filtered := Trim(Value) <> '';
  end;
end;

function TRMDDataset.GetPropValue(Index: string): Variant;
begin
  Index := AnsiUpperCase(Index);
  Result := inherited GetPropValue(Index);
  if Result <> Null then Exit;
  if Index = 'ACTIVE' then
    Result := FDataSet.Active
  else if Index = 'FILTER' then
    Result := FDataSet.Filter
  else if Index = 'EOF' then
    Result := FDataSet.Eof
  else if Index = 'RECORDCOUNT' then
    Result := FDataSet.RecordCount
  else if Index = 'FIELDCOUNT' then
    Result := FDataSet.FieldCount
{$IFNDEF Delphi2}
  else if Index = 'ISEMPTY' then
    Result := FDataSet.IsEmpty
{$ENDIF}
end;

function TRMDDataset.DoMethod(const MethodName: string; Par1, Par2, Par3: Variant): Variant;
var
	d: TComponent;
  ds: TDataSource;
begin
  Result := inherited DoMethod(MethodName, Par1, Par2, Par3);
  if MethodName = 'GETINDEXPROPERTY' then
  begin
    if Par1 = 'FIELDS' then
      Result := FDataSet.FieldByName(Par2).AsVariant;
  end
  else if MethodName = 'OPEN' then
  begin
		if Self is TRMDQuery then
    begin
	    d := RMFindComponent(FDataSet.Owner, Prop['DataSource']);
      if d <> nil then
      begin
	  	  ds := RMGetDataSource(FDataSet.Owner, TDataSet(d));
	      if (ds <> nil) and (ds.DataSet <> nil) then
  	    	ds.DataSet.Open;
      end;
    end;
    FDataSet.Open;
  end
  else if MethodName = 'CLOSE' then
    FDataSet.Close
  else if MethodName = 'NEXT' then
    FDataSet.Next
  else if MethodName = 'PRIOR' then
    FDataSet.Prior
  else if MethodName = 'FIRST' then
    FDataSet.First
  else if MethodName = 'LAST' then
    FDataSet.Last;
end;

function TRMDDataset.GetDatabaseName: string;
begin
  Result := Prop['Database'];
end;

procedure TRMDDataset.SetDatabaseName(const Value: string);
begin
  Prop['Database'] := Value;
end;

procedure TRMDDataset.SetDataSet(Value: TDataSet);
begin
  if FDataSet <> Value then
  begin
    FDataSet := Value;
    FDataSource.DataSet := FDataSet;
    if Self is TRMDQuery then
      FDataSet.BeforeOpen := TRMDQuery(Self).OnBeforeOpenQueryEvent;
  end;
end;

procedure TRMDDataset.Loaded;
var
  i: Integer;
  s: string;
  ds: TDataSet;
  f: TField;
begin
  try
    for i := 0 to FFixupList.Count - 1 do
    begin
      s := FFixupList.Name[i];
      if s[1] = '.' then // lookup field
      begin
        f := FDataSet.FindField(Copy(s, 2, 255));
        ds := RMFindComponent(FDataSet.Owner, FFixupList.Value[i]) as TDataSet;
        f.LookupDataset := ds;
      end
    end;
    Prop['Active'] := FFixupList['Active'];
  except;
  end;
  FFixupList.Clear;
end;

procedure TRMDDataset.ShowEditor;
begin
  FieldsEditor(nil);
end;

procedure TRMDDataset.FieldsEditor(Sender: TObject);
var
  SaveActive: Boolean;
  tmpForm: TRMDFieldsEditorForm;
begin
  SaveActive := FDataSet.Active;
  FDataSet.Close;

  tmpForm := TRMDFieldsEditorForm.Create(nil);
  tmpForm.DataSet := FDataSet;
  tmpForm.ShowModal;
  tmpForm.Free;

  RMDesigner.BeforeChange;
  FDataSet.Active := SaveActive;
end;

procedure TRMDDataset.LoadFromStream(Stream: TStream);

  procedure LoadFields;
  var
    i: Integer;
    n: Word;
    s: string;
    Field: TField;
    ds1: TDataset;
    fName: string;
    fType: TFieldType;
    fLookup: Boolean;
    fSize: Word;
    fDefs: TFieldDefs;
  begin
    fDefs := FDataSet.FieldDefs;
    Stream.Read(n, 2); // FieldCount
    for i := 0 to n - 1 do
    begin
      fType := TFieldType(RMReadByte(Stream)); // DataType
      fName := RMReadString(Stream); // FieldName
      fLookup := RMReadBoolean(Stream); // Lookup
      fSize := RMReadWord(Stream); // Size

      fDefs.Add(fName, fType, fSize, False);
      Field := fDefs[fDefs.Count - 1].CreateField(FDataSet);
      if fLookup then
      begin
        with Field do
        begin
          Lookup := True;
          KeyFields := RMReadString(Stream); // KeyFields
          s := RMReadString(Stream); // LookupDataset
          ds1 := RMFindComponent(FDataSet.Owner, s) as TDataSet;
          FFixupList['.' + FieldName] := s;
          LookupDataset := ds1;
          LookupKeyFields := RMReadString(Stream); // LookupKeyFields
          LookupResultField := RMReadString(Stream); // LookupResultField
        end;
      end;
    end;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?