FastReport_FMX_2.8.12/Source/FMX.frxDBSet.pas
2024-07-06 22:41:12 +02:00

474 lines
11 KiB
ObjectPascal

{******************************************}
{ }
{ FastReport v4.0 }
{ DB dataset }
{ }
{ Copyright (c) 1998-2008 }
{ by Alexander Tzyganenko, }
{ Fast Reports Inc. }
{ }
{******************************************}
unit FMX.frxDBSet;
interface
{$I fmx.inc}
{$I frx.inc}
{$I fmx.inc}
uses
System.SysUtils, System.Classes, FMX.frxClass, Data.DB, System.Variants, System.WideStrings;
type
{$I frxFMX_PlatformsAttribute.inc}
TfrxDBDataset = class(TfrxCustomDBDataset)
private
FBookmark: TBookmark;
FDataSet: TDataSet;
FDataSource: TDataSource;
FDS: TDataSet;
FEof: Boolean;
FBCDToCurrency: Boolean;
FSaveOpenEvent: TDatasetNotifyEvent;
FSaveCloseEvent: TDatasetNotifyEvent;
procedure BeforeClose(Sender: TDataSet);
procedure AfterOpen(Sender: TDataset);
procedure SetDataSet(Value: TDataSet);
procedure SetDataSource(Value: TDataSource);
function DataSetActive: Boolean;
function IsDataSetStored: Boolean;
protected
function GetDisplayText(Index: String): WideString; override;
function GetDisplayWidth(Index: String): Integer; override;
function GetFieldType(Index: String): TfrxFieldType; override;
function GetValue(Index: String): Variant; override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
procedure Initialize; override;
procedure Finalize; override;
procedure First; override;
procedure Next; override;
procedure Prior; override;
procedure Open; override;
procedure Close; override;
function Eof: Boolean; override;
function GetDataSet: TDataSet;
function IsBlobField(const fName: String): Boolean; override;
function RecordCount: Integer; override;
procedure AssignBlobTo(const fName: String; Obj: TObject); override;
procedure GetFieldList(List: TStrings); override;
published
property DataSet: TDataSet read FDataSet write SetDataSet stored IsDataSetStored;
property DataSource: TDataSource read FDataSource write SetDataSource stored IsDataSetStored;
property BCDToCurrency: Boolean read FBCDToCurrency write FBCDToCurrency;
end;
implementation
uses FMX.frxUtils, FMX.frxRes, FMX.frxUnicodeUtils;
type
EDSError = class(Exception);
{ TfrxDBDataset }
procedure TfrxDBDataset.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if Operation = opRemove then
if AComponent = FDataSource then
DataSource := nil
else if AComponent = FDataSet then
DataSet := nil
end;
procedure TfrxDBDataset.SetDataSet(Value: TDataSet);
begin
FDataSet := Value;
if Value <> nil then
FDataSource := nil;
FDS := GetDataSet;
end;
procedure TfrxDBDataset.SetDataSource(Value: TDataSource);
begin
FDataSource := Value;
if Value <> nil then
FDataSet := nil;
FDS := GetDataSet;
end;
function TfrxDBDataset.DataSetActive: Boolean;
begin
Result := (FDS <> nil) and FDS.Active;
end;
function TfrxDBDataset.GetDataset: TDataSet;
begin
if FDataSet <> nil then
Result := FDataSet
else if (FDataSource <> nil) and (FDataSource.DataSet <> nil) then
Result := FDataSource.DataSet
else
Result := nil;
end;
function TfrxDBDataset.IsDataSetStored: Boolean;
begin
Result := Report = nil;
end;
procedure TfrxDBDataset.Initialize;
begin
FDS := GetDataSet;
if FDS = nil then
raise Exception.Create(Format(frxResources.Get('dbNotConn'), [Name]));
FSaveOpenEvent := FDS.AfterOpen;
FDS.AfterOpen := AfterOpen;
FSaveCloseEvent := FDS.BeforeClose;
FDS.BeforeClose := BeforeClose;
FEof := False;
FInitialized := False;
end;
procedure TfrxDBDataset.Finalize;
begin
if FDS = nil then Exit;
if FBookMark <> nil then
begin
FDS.GotoBookmark(FBookmark);
FDS.FreeBookmark(FBookmark);
end;
FBookMark := nil;
if CloseDataSource then
Close;
FDS.AfterOpen := FSaveOpenEvent;
FDS.BeforeClose := FSaveCloseEvent;
FSaveOpenEvent := nil;
FSaveCloseEvent := nil;
FInitialized := False;
end;
procedure TfrxDBDataSet.Open;
begin
if FInitialized then
Exit;
FInitialized := True;
FDS.Open;
AfterOpen(nil);
if (RangeBegin = rbCurrent) or (RangeEnd = reCurrent) then
FBookmark := FDS.GetBookmark else
FBookmark := nil;
inherited;
end;
procedure TfrxDBDataSet.Close;
begin
inherited;
BeforeClose(nil);
FDS.Close;
end;
procedure TfrxDBDataset.AfterOpen(Sender: TDataset);
var
i: Integer;
begin
GetFieldList(Fields);
for i := 0 to Fields.Count - 1 do
Fields.Objects[i] := FDS.FindField(ConvertAlias(Fields[i]));
if Assigned(FSaveOpenEvent) and (Sender <> nil) then
FSaveOpenEvent(Sender);
end;
procedure TfrxDBDataset.BeforeClose(Sender: TDataSet);
begin
if Assigned(FSaveCloseEvent) and (Sender <> nil) then
FSaveCloseEvent(Sender);
if FBookMark <> nil then
FDS.FreeBookmark(FBookmark);
FBookMark := nil;
FInitialized := False;
end;
procedure TfrxDBDataSet.First;
begin
if not FInitialized then
Open;
if RangeBegin = rbFirst then
FDS.First else
FDS.GotoBookmark(FBookmark);
FEof := False;
inherited First;
end;
procedure TfrxDBDataSet.Next;
var
b: TBookmark;
begin
if not FInitialized then
Open;
FEof := False;
if RangeEnd = reCurrent then
begin
b := FDS.GetBookmark;
if FDS.CompareBookmarks(b, FBookmark) = 0 then
FEof := True;
FDS.FreeBookmark(b);
if FEof then
Exit;
end;
FDS.Next;
inherited Next;
end;
procedure TfrxDBDataSet.Prior;
begin
if not FInitialized then
Open;
FDS.Prior;
inherited Prior;
end;
function TfrxDBDataSet.Eof: Boolean;
begin
if not FInitialized then
Open;
Result := inherited Eof or FDS.Eof or FEof;
end;
function TfrxDBDataset.GetDisplayText(Index: String): WideString;
var
i: Integer;
s: WideString;
begin
s := '';
if not FInitialized then
Open;
if DataSetActive then
if Fields.Count = 0 then
s := FDS.FieldByName(Index).DisplayText
else
begin
i := Fields.IndexOf(Index);
if i <> -1 then
begin
if TField(Fields.Objects[i]) is TWideStringField then
s := VarToWideStr(TField(Fields.Objects[i]).Value)
else
s := TField(Fields.Objects[i]).DisplayText;
end
else
begin
s := frxResources.Get('dbFldNotFound') + ' ' + UserName + '."' +
Index + '"';
ReportRef.Errors.Add(ReportRef.CurObject + ': ' + s);
end;
end
else
s := UserName + '."' + Index + '"';
Result := s;
end;
function TfrxDBDataset.GetValue(Index: String): Variant;
var
i: Integer;
v: Variant;
begin
if not FInitialized then
Open;
i := Fields.IndexOf(Index);
if i <> -1 then
begin
if TField(Fields.Objects[i]) is TFMTBCDField then
begin
if TField(Fields.Objects[i]).IsNull then
v := Null
else if BCDToCurrency then
v := TField(Fields.Objects[i]).AsCurrency
else
v := TField(Fields.Objects[i]).AsFloat
end
else
if TField(Fields.Objects[i]) is TLargeIntField then
begin
{ TLargeIntField.AsVariant converts value to vt_decimal variant type
which is not supported by Delphi }
if TField(Fields.Objects[i]).IsNull then
v := Null
else
v := TLargeIntField(Fields.Objects[i]).AsLargeInt
end
else if TField(Fields.Objects[i]) is TSQLTimeStampField then
begin
if TField(Fields.Objects[i]).IsNull then
v := Null
else
v := TSQLTimeStampField(Fields.Objects[i]).AsDateTime;
end
else
if Fields.Objects[i] is TBlobField then
begin
if (TBlobField(Fields.Objects[i]).BlobType
in [ftWideString, ftWideMemo, ftFixedWideChar]) then
v := TField(Fields.Objects[i]).AsWideString
else v := TField(Fields.Objects[i]).AsString
end
else
v := TField(Fields.Objects[i]).Value
end
else
begin
v := Null;
ReportRef.Errors.Add(ReportRef.CurObject + ': ' +
frxResources.Get('dbFldNotFound') + ' ' + UserName + '."' + Index + '"');
end;
Result := v;
end;
function TfrxDBDataset.GetDisplayWidth(Index: String): Integer;
var
f: TField;
fDef: TFieldDef;
begin
Result := 10;
Index := ConvertAlias(Index);
f := FDS.FindField(Index);
if f <> nil then
Result := f.DisplayWidth
else
begin
try
if not FDS.FieldDefs.Updated then
FDS.FieldDefs.Update;
except
end;
fDef := FDS.FieldDefs.Find(Index);
if fDef <> nil then
case fDef.DataType of
ftString, ftWideString: Result := fDef.Size;
ftLargeInt: Result := 15;
ftDateTime: Result := 20;
end;
end;
end;
function TfrxDBDataset.GetFieldType(Index: String): TfrxFieldType;
var
f: TField;
begin
Result := fftNumeric;
f := FDS.FindField(ConvertAlias(Index));
if f <> nil then
case f.DataType of
ftString, ftWideString, ftMemo:
Result := fftString;
ftBoolean:
Result := fftBoolean;
end;
end;
procedure TfrxDBDataset.AssignBlobTo(const fName: String; Obj: TObject);
var
Field: TField;
BlobStream: TStream;
sl: TStringList;
begin
if not FInitialized then
Open;
Field := TField(Fields.Objects[Fields.IndexOf(fName)]);
if (Field <> nil) and Field.IsBlob then
// if Field is TBlobField then
begin
if Obj is TfrxWideStrings then
begin
BlobStream := TMemoryStream.Create;
sl := TStringList.Create;
try
TBlobField(Field).SaveToStream(BlobStream);
BlobStream.Position := 0;
if Field is TWideMemoField then
TfrxWideStrings(Obj).LoadFromWStream(BlobStream)
else if Field is TMemoField then
TfrxWideStrings(Obj).Text := Field.AsWideString;
finally
BlobStream.Free;
sl.Free;
end;
end
else if Obj is TStream then
begin
if (Field is TWideMemoField) and (Obj is TStringStream) then
TStringStream(Obj).WriteString(TWideMemoField(Field).AsWideString)
else
TBlobField(Field).SaveToStream(TStream(Obj));
TStream(Obj).Position := 0;
end;
end;
end;
procedure TfrxDBDataset.GetFieldList(List: TStrings);
var
i: Integer;
begin
List.Clear;
if FieldAliases.Count = 0 then
begin
try
if FDS <> nil then
begin
FDS.GetFieldNames(List);
List.BeginUpdate;
for i := 0 to FDS.AggFields.Count - 1 do
List.Add(FDS.AggFields[i].FieldName);
List.EndUpdate;
end;
except
end;
end
else
begin
for i := 0 to FieldAliases.Count - 1 do
if Pos('-', FieldAliases.Names[i]) <> 1 then
List.Add(FieldAliases.Values[FieldAliases.Names[i]]);
end;
end;
function TfrxDBDataset.IsBlobField(const fName: String): Boolean;
var
Field: TField;
i: Integer;
begin
if not FInitialized then
Open;
Result := False;
i := Fields.IndexOf(fName);
if i <> -1 then
begin
Field := TField(Fields.Objects[i]);
Result := (Field <> nil) and Field.IsBlob;
end;
end;
function TfrxDBDataset.RecordCount: Integer;
begin
if not FInitialized then
Open;
Result := FDS.RecordCount;
end;
end.