{ $Id$ This file is part of the Free Pascal run time library. Copyright (c) 1999-2000 by Michael Van Canneyt, member of the Free Pascal development team TFields and related components implementations. See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} Procedure DumpMem (P : Pointer;Size : Longint); Var i : longint; begin Write ('Memory dump : '); For I:=0 to Size-1 do Write (Pbyte(P)[i],' '); Writeln; end; { --------------------------------------------------------------------- TFieldDef ---------------------------------------------------------------------} Constructor TFieldDef.Create(AOwner: TFieldDefs; const AName: string; ADataType: TFieldType; ASize: Word; ARequired: Boolean; AFieldNo: Longint); begin Inherited Create(AOwner); {$ifdef dsdebug } Writeln('TFieldDef.Create : ',Aname,'(',AFieldNo,')'); {$endif} FName:=Aname; FDatatype:=ADatatype; FSize:=ASize; FRequired:=ARequired; FPrecision:=-1; // Correct sizes. If FDataType=ftFloat then begin If Not (FSize in [4,8,10]) then FSize:=10 end else If FDataType in [ftWord,ftsmallint,ftinteger] Then If Not (FSize in [1,2,4]) then FSize:=4; FFieldNo:=AFieldNo; AOwner.FItems.Add(Self); end; Destructor TFieldDef.Destroy; Var I : longint; begin Inherited destroy; end; Function TFieldDef.CreateField(AOwner: TComponent): TField; Var TheField : TFieldClass; begin {$ifdef dsdebug} Writeln ('Creating field '+FNAME); {$endif dsdebug} TheField:=GetFieldClass; if TheField=Nil then DatabaseErrorFmt(SUnknownFieldType,[FName]); Result:=Thefield.Create(AOwner); Try Result.Size:=FSize; Result.Required:=FRequired; Result.FieldName:=FName; Result.FFieldNo:=Self.FieldNo; Result.SetFieldType(DataType); {$ifdef dsdebug} Writeln ('TFieldDef.CReateField : Trying to set dataset'); {$endif dsdebug} {$ifdef dsdebug} Writeln ('TFieldDef.CReateField : Result Fieldno : ',Result.FieldNo,' Self : ',FieldNo); {$endif dsdebug} Result.Dataset:=TFieldDefs(Owner).FDataset; If Result is TFloatField then TFloatField(Result).Precision:=FPrecision; except Result.Free; Raise; end; end; Function TFieldDef.GetFieldClass : TFieldClass; begin //!! Should be owner as tdataset but that doesn't work ?? If Assigned(Owner) then Result:=TFieldDefs(Owner).FDataSet.GetFieldClass(FDataType) else Result:=Nil; end; { --------------------------------------------------------------------- TFieldDefs ---------------------------------------------------------------------} destructor TFieldDefs.Destroy; begin FItems.Free; // This will destroy all fielddefs since we own them... Inherited Destroy; end; procedure TFieldDefs.Add(const AName: string; ADataType: TFieldType); begin Add(AName,ADatatype,0,False); end; procedure TFieldDefs.Add(const AName: string; ADataType: TFieldType; ASize : Word); begin Add(AName,ADatatype,ASize,False); end; procedure TFieldDefs.Add(const AName: string; ADataType: TFieldType; ASize: Word; ARequired: Boolean); begin If Length(AName)=0 Then DatabaseError(SNeedFieldName); // the fielddef will register itself here as a owned component. // fieldno is 1 based ! TFieldDef.Create(Self,AName,ADataType,ASize,Arequired,FItems.Count+1); end; function TFieldDefs.GetCount: Longint; begin Result:=FItems.Count; end; function TFieldDefs.GetItem(Index: Longint): TFieldDef; begin Result:=TFieldDef(FItems[Index]); end; constructor TFieldDefs.Create(ADataSet: TDataSet); begin Inherited Create(ADataSet); FItems:=TList.Create; FDataset:=ADataset; end; procedure TFieldDefs.Assign(FieldDefs: TFieldDefs); Var I : longint; begin Clear; For i:=0 to FieldDefs.Count-1 do With FieldDefs[i] do Add(Name,DataType,Size,Required); end; procedure TFieldDefs.Clear; Var I : longint; begin For I:=FItems.Count-1 downto 0 do TFieldDef(Fitems[i]).Free; FItems.Clear; end; function TFieldDefs.Find(const AName: string): TFieldDef; Var I : longint; begin I:=IndexOf(AName); If I=-1 Then DataBaseErrorFmt(SUnknownField,[AName,FDataSet.Name]); Result:=TFieldDef(Fitems[i]); end; function TFieldDefs.IndexOf(const AName: string): Longint; Var I : longint; begin For I:=0 to Fitems.Count-1 do If AnsiCompareText(TFieldDef(FItems[I]).Name,AName)=0 then begin Result:=I; Exit; end; Result:=-1; end; procedure TFieldDefs.Update; begin FDataSet.UpdateFieldDefs; end; Function TFieldDefs.AddFieldDef : TFieldDef; begin Result:=TFieldDef.Create(Self,'',ftUnknown,0,False,FItems.Count+1); end; { --------------------------------------------------------------------- TField ---------------------------------------------------------------------} Const SBoolean = 'Boolean'; SDateTime = 'TDateTime'; SFloat = 'Float'; SInteger = 'Integer'; SVariant = 'Variant'; SString = 'String'; constructor TField.Create(AOwner: TComponent); begin Inherited Create(AOwner); FVisible:=True; FValidChars:=[#0..#155]; FProviderFlags := [pfInUpdate,pfInWhere]; end; destructor TField.Destroy; begin IF Assigned(FDataSet) then begin FDataSet.Active:=False; FDataSet.RemoveField(Self); end; Inherited Destroy; end; function TField.AccessError(const TypeName: string): EDatabaseError; begin Result:=EDatabaseError.CreateFmt(SinvalidTypeConversion,[TypeName,FFieldName]); end; procedure TField.Assign(Source: TPersistent); begin //!! To be implemented end; procedure TField.Change; begin If Assigned(FOnChange) Then FOnChange(Self); end; procedure TField.CheckInactive; begin If Assigned(FDataSet) then FDataset.CheckInactive; end; procedure TField.Clear; begin SetData(Nil); end; procedure TField.DataChanged; begin FDataset.DataEvent(deFieldChange,ptrint(Self)); end; procedure TField.FocusControl; begin FDataSet.DataEvent(deFocusControl,ptrint(Self)); end; procedure TField.FreeBuffers; begin // Empty. Provided for backward compatibiliy; // TDataset manages the buffers. end; function TField.GetAsBoolean: Boolean; begin AccessError(SBoolean); end; function TField.GetAsDateTime: TDateTime; begin AccessError(SdateTime); end; function TField.GetAsFloat: Double; begin AccessError(SDateTime); end; function TField.GetAsLongint: Longint; begin AccessError(SInteger); end; function TField.GetAsVariant: Variant; begin AccessError(SVariant); end; function TField.GetAsInteger: Integer; begin Result:=GetAsLongint; end; function TField.GetAsString: string; begin AccessError(SString); end; function TField.GetOldValue: Variant; var SaveState : tDatasetState; begin with FDataset do begin SaveState := State; SetTempState(dsOldValue); Result := GetAsVariant; RestoreState(SaveState); end; end; function TField.GetCanModify: Boolean; begin Result:=Not ReadOnly; If Result then begin Result:=Assigned(DataSet); If Result then Result:= DataSet.CanModify; end; end; function TField.GetData(Buffer: Pointer): Boolean; begin IF FDataset=Nil then DatabaseErrorFmt(SNoDataset,[FieldName]); If FVAlidating then begin result:=Not(FValueBuffer=Nil); If Result then Move (FValueBuffer^,Buffer^ ,DataSize); end else Result:=FDataset.GetFieldData(Self,Buffer); end; function TField.GetDataSize: Word; begin Result:=0; end; function TField.GetDefaultWidth: Longint; begin Result:=10; end; function TField.GetDisplayName : String; begin If FDisplayLabel<>'' then result:=FDisplayLabel else Result:=FFieldName; end; Function TField.IsDisplayStored : Boolean; begin Result:=(DisplayLabel<>FieldName); end; function TField.getIndex : longint; begin If Assigned(FDataset) then Result:=FDataset.FFieldList.IndexOf(Self) else Result:=-1; end; procedure TField.SetAlignment(const AValue: TAlignMent); begin if FAlignment <> AValue then begin FAlignment := Avalue; PropertyChanged(false); end; end; function TField.GetIsNull: Boolean; begin Result:=Not(GetData (Nil)); end; function TField.GetParentComponent: TComponent; begin //!! To be implemented end; procedure TField.GetText(var AText: string; ADisplayText: Boolean); begin AText:=GetAsString; end; function TField.HasParent: Boolean; begin HasParent:=True; end; function TField.IsValidChar(InputChar: Char): Boolean; begin // FValidChars must be set in Create. Result:=InputChar in FValidChars; end; procedure TField.Notification(AComponent: TComponent; Operation: TOperation); begin Inherited Notification(AComponent,Operation); end; procedure TField.PropertyChanged(LayoutAffected: Boolean); begin If (FDataset<>Nil) and (FDataset.Active) then If LayoutAffected then FDataset.DataEvent(deLayoutChange,0) else FDataset.DataEvent(deDatasetchange,0); end; procedure TField.ReadState(Reader: TReader); begin //!! To be implemented end; procedure TField.SetAsBoolean(AValue: Boolean); begin AccessError(SBoolean); end; procedure TField.SetAsDateTime(AValue: TDateTime); begin AccessError(SDateTime); end; procedure TField.SetAsFloat(AValue: Double); begin AccessError(SFloat); end; procedure TField.SetAsVariant(AValue: Variant); begin AccessError(SVariant); end; procedure TField.SetAsLongint(AValue: Longint); begin AccessError(SInteger); end; procedure TField.SetAsInteger(AValue: Integer); begin SetAsLongint(AValue); end; procedure TField.SetAsString(const AValue: string); begin AccessError(SString); end; procedure TField.SetData(Buffer: Pointer); begin If Not Assigned(FDataset) then EDatabaseError.CreateFmt(SNoDataset,[FieldName]); FDataSet.SetFieldData(Self,Buffer); end; Procedure TField.SetDataset (Value : TDataset); begin {$ifdef dsdebug} Writeln ('Setting dataset'); {$endif} If Value=FDataset then exit; If Assigned(FDataset) Then begin FDataset.CheckInactive; FDataset.FFieldList.Remove(Self); end; If Assigned(Value) then begin Value.CheckInactive; Value.FFieldList.Add(Self); end; FDataset:=Value; end; procedure TField.SetDataType(AValue: TFieldType); begin FDataType := AValue; end; procedure TField.SetFieldType(AValue: TFieldType); begin //!! To be implemented end; procedure TField.SetParentComponent(AParent: TComponent); begin //!! To be implemented end; procedure TField.SetSize(AValue: Word); begin CheckInactive; CheckTypeSize(AValue); FSize:=AValue; end; procedure TField.SetText(const AValue: string); begin AsString:=AValue; end; procedure TField.Validate(Buffer: Pointer); begin If assigned(OnValidate) Then begin FValueBuffer:=Buffer; FValidating:=True; Try OnValidate(Self); finally FValidating:=False; end; end; end; class function Tfield.IsBlob: Boolean; begin Result:=False; end; class procedure TField.CheckTypeSize(AValue: Longint); begin If (AValue<>0) and Not IsBlob Then DatabaseErrorFmt(SInvalidFieldSize,[AValue]); end; // TField private methods function TField.GetDisplayText: String; begin SetLength(Result, 0); if Assigned(OnGetText) then OnGetText(Self, Result, True) else GetText(Result, True); end; procedure TField.SetDisplayLabel(const AValue: string); begin if FDisplayLabel<>Avalue then begin FDisplayLabel:=Avalue; PropertyChanged(true); end; end; procedure TField.SetDisplayWidth(const AValue: Longint); begin if FDisplayWidth<>AValue then begin FDisplayWidth:=AValue; PropertyChanged(True); end; end; function TField.GetDisplayWidth: integer; begin if FDisplayWidth=0 then result:=GetDefaultWidth else result:=FDisplayWidth; end; procedure TField.SetReadOnly(const AValue: Boolean); begin if (FReadOnly<>Avalue) then begin FReadOnly:=AValue; PropertyChanged(True); end; end; procedure TField.SetVisible(const AValue: Boolean); begin if FVisible<>Avalue then begin FVisible:=AValue; PropertyChanged(True); end; end; { --------------------------------------------------------------------- TStringField ---------------------------------------------------------------------} constructor TStringField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDataType(ftString); Size:=20; end; class procedure TStringField.CheckTypeSize(AValue: Longint); begin If (AValue<1) or (AValue>dsMaxStringSize) Then databaseErrorFmt(SInvalidFieldSize,[AValue]) end; function TStringField.GetAsBoolean: Boolean; Var S : String; begin S:=GetAsString; result := (Length(S)>0) and (Upcase(S[1]) in ['T',YesNoChars[True]]); end; function TStringField.GetAsDateTime: TDateTime; begin Result:=StrToDateTime(GetAsString); end; function TStringField.GetAsFloat: Double; begin Result:=StrToFloat(GetAsString); end; function TStringField.GetAsLongint: Longint; begin Result:=StrToInt(GetAsString); end; function TStringField.GetAsString: string; begin If Not GetValue(Result) then Result:=''; end; function TStringField.GetAsVariant: Variant; Var s : string; begin If GetValue(s) then Result:=s else Result:=Null; end; function TStringField.GetDataSize: Word; begin Result:=Size+1; end; function TStringField.GetDefaultWidth: Longint; begin result:=Size; end; Procedure TStringField.GetText(var AText: string; ADisplayText: Boolean); begin AText:=GetAsString; end; function TStringField.GetValue(var AValue: string): Boolean; Var Buf : TStringFieldBuffer; begin Result:=GetData(@Buf); If Result then AValue:=Buf; end; procedure TStringField.SetAsBoolean(AValue: Boolean); begin If AValue Then SetAsString('T') else SetAsString('F'); end; procedure TStringField.SetAsDateTime(AValue: TDateTime); begin SetAsString(DateTimeToStr(AValue)); end; procedure TStringField.SetAsFloat(AValue: Double); begin SetAsString(FloatToStr(AValue)); end; procedure TStringField.SetAsLongint(AValue: Longint); begin SetAsString(intToStr(AValue)); end; procedure TStringField.SetAsString(const AValue: string); Const NullByte : char = #0; begin IF Length(AValue)=0 then SetData(@NullByte) else SetData(@AValue[1]); end; { --------------------------------------------------------------------- TNumericField ---------------------------------------------------------------------} constructor TNumericField.Create(AOwner: TComponent); begin Inherited Create(AOwner); AlignMent:=taRightJustify; end; procedure TNumericField.RangeError(AValue, Min, Max: Double); begin DatabaseErrorFMT(SRangeError,[AValue,Min,Max,FieldName]); end; procedure TNumericField.SetDisplayFormat(const AValue: string); begin If FDisplayFormat<>AValue then begin FDisplayFormat:=AValue; PropertyChanged(True); end; end; procedure TNumericField.SetEditFormat(const AValue: string); begin If FEDitFormat<>AValue then begin FEDitFormat:=AVAlue; PropertyChanged(True); end; end; { --------------------------------------------------------------------- TLongintField ---------------------------------------------------------------------} constructor TLongintField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDatatype(ftinteger); FMinRange:=Low(LongInt); FMaxRange:=High(LongInt); FValidchars:=['+','-','0'..'9']; end; function TLongintField.GetAsFloat: Double; begin Result:=GetAsLongint; end; function TLongintField.GetAsLongint: Longint; begin If Not GetValue(Result) then Result:=0; end; function TLongintField.GetAsVariant: Variant; Var L : Longint; v : variant; begin If GetValue(L) then Result:=L else Result:=Null; end; function TLongintField.GetAsString: string; Var L : Longint; begin If GetValue(L) then Result:=IntTostr(L) else Result:=''; end; function TLongintField.GetDataSize: Word; begin Result:=SizeOf(Longint); end; procedure TLongintField.GetText(var AText: string; ADisplayText: Boolean); var l : longint; fmt : string; begin Atext:=''; If Not GetValue(l) then exit; If ADisplayText or (FEditFormat='') then fmt:=FDisplayFormat else fmt:=FEditFormat; If length(fmt)<>0 then AText:=FormatFloat(fmt,L) else Str(L,AText); end; function TLongintField.GetValue(var AValue: Longint): Boolean; Var L : Longint; P : PLongint; begin P:=@L; Result:=GetData(P); If Result then Case Datatype of ftInteger,ftautoinc : AValue:=Plongint(P)^; ftword : Avalue:=Pword(P)^; ftsmallint : AValue:=PSmallint(P)^; end; end; procedure TLongintField.SetAsFloat(AValue: Double); begin SetAsLongint(Round(Avalue)); end; procedure TLongintField.SetAsLongint(AValue: Longint); begin If CheckRange(AValue) then SetData(@AValue) else RangeError(Avalue,FMinrange,FMaxRange); end; procedure TLongintField.SetAsVariant(AValue: Variant); begin SetAsLongint(AValue); end; procedure TLongintField.SetAsString(const AValue: string); Var L,Code : longint; begin If length(AValue)=0 then Clear else begin Val(AVAlue,L,Code); If Code=0 then SetAsLongint(L) else DatabaseErrorFMT(SNotAnInteger,[Avalue]); end; end; Function TLongintField.CheckRange(AValue : longint) : Boolean; begin result := true; if (FMaxValue=0) then begin if (AValue>FMaxRange) Then result := false; end else if AValue>FMaxValue then result := false; if (FMinValue=0) then begin if (AValue=FMinRange) and (AValue<=FMaxRange) then FMaxValue:=AValue else RangeError(AValue,FMinRange,FMaxRange); end; Procedure TLongintField.SetMinValue (AValue : longint); begin If (AValue>=FMinRange) and (AValue<=FMaxRange) then FMinValue:=AValue else RangeError(AValue,FMinRange,FMaxRange); end; { --------------------------------------------------------------------- TLargeintField ---------------------------------------------------------------------} constructor TLargeintField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDatatype(ftLargeint); FMinRange:=Low(Largeint); FMaxRange:=High(Largeint); FValidchars:=['+','-','0'..'9']; end; function TLargeintField.GetAsFloat: Double; begin Result:=GetAsLargeint; end; function TLargeintField.GetAsLargeint: Largeint; begin If Not GetValue(Result) then Result:=0; end; function TLargeIntField.GetAsVariant: Variant; Var L : Largeint; begin If GetValue(L) then Result:=L else Result:=Null; end; function TLargeintField.GetAsLongint: Longint; begin Result:=GetAsLargeint; end; function TLargeintField.GetAsString: string; Var L : Largeint; begin If GetValue(L) then Result:=IntTostr(L) else Result:=''; end; function TLargeintField.GetDataSize: Word; begin Result:=SizeOf(Largeint); end; procedure TLargeintField.GetText(var AText: string; ADisplayText: Boolean); var l : largeint; fmt : string; begin Atext:=''; If Not GetValue(l) then exit; If ADisplayText or (FEditFormat='') then fmt:=FDisplayFormat else fmt:=FEditFormat; If length(fmt)<>0 then AText:=FormatFloat(fmt,L) else Str(L,AText); end; function TLargeintField.GetValue(var AValue: Largeint): Boolean; type PLargeint = ^Largeint; Var P : PLargeint; begin P:=@AValue; Result:=GetData(P); end; procedure TLargeintField.SetAsFloat(AValue: Double); begin SetAsLargeint(Round(Avalue)); end; procedure TLargeintField.SetAsLargeint(AValue: Largeint); begin If CheckRange(AValue) then SetData(@AValue) else RangeError(Avalue,FMinrange,FMaxRange); end; procedure TLargeintField.SetAsLongint(AValue: Longint); begin SetAsLargeint(Avalue); end; procedure TLargeintField.SetAsString(const AValue: string); Var L : largeint; code : longint; begin If length(AValue)=0 then Clear else begin Val(AVAlue,L,Code); If Code=0 then SetAsLargeint(L) else DatabaseErrorFMT(SNotAnInteger,[Avalue]); end; end; Function TLargeintField.CheckRange(AValue : largeint) : Boolean; begin result := true; if (FMaxValue=0) then begin if (AValue>FMaxRange) Then result := false; end else if AValue>FMaxValue then result := false; if (FMinValue=0) then begin if (AValue=FMinRange) and (AValue<=FMaxRange) then FMaxValue:=AValue else RangeError(AValue,FMinRange,FMaxRange); end; Procedure TLargeintField.SetMinValue (AValue : largeint); begin If (AValue>=FMinRange) and (AValue<=FMaxRange) then FMinValue:=AValue else RangeError(AValue,FMinRange,FMaxRange); end; { TSmallintField } function TSmallintField.GetDataSize: Word; begin Result:=SizeOf(SmallInt); end; constructor TSmallintField.Create(AOwner: TComponent); begin inherited Create(AOwner); SetDataType(ftSmallInt); FMinRange:=-32768; FMaxRange:=32767; end; { TWordField } function TWordField.GetDataSize: Word; begin Result:=SizeOf(Word); end; constructor TWordField.Create(AOwner: TComponent); begin inherited Create(AOwner); SetDataType(ftWord); FMinRange:=0; FMaxRange:=65535; FValidchars:=['+','0'..'9']; end; { TAutoIncField } constructor TAutoIncField.Create(AOwner: TComponent); begin Inherited Create(AOWner); SetDataType(ftAutoInc); end; Procedure TAutoIncField.SetAsLongint(AValue : Longint); begin DataBaseError(SCantSetAutoIncfields); end; { TFloatField } function TFloatField.GetAsFloat: Double; begin If Not GetData(@Result) Then Result:=0.0; end; function TFloatField.GetAsVariant: Variant; Var f : Double; begin If GetData(@f) then Result := f else Result:=Null; end; function TFloatField.GetAsLongint: Longint; begin Result:=Round(GetAsFloat); end; function TFloatField.GetAsString: string; Var R : Double; begin If GetData(@R) then Result:=FloatToStr(R) else Result:=''; end; function TFloatField.GetDataSize: Word; begin Result:=SizeOf(Double); end; procedure TFloatField.GetText(var TheText: string; ADisplayText: Boolean); Var fmt : string; E : Double; begin text:=''; If Not GetData(@E) then exit; If ADisplayText or (Length(FEditFormat) = 0) Then Fmt:=FDisplayFormat else Fmt:=FEditFormat; If fmt<>'' then TheText:=FormatFloat(fmt,E) else TheText:=FloatToStrF(E,ffgeneral,FPrecision,0); end; procedure TFloatField.SetAsFloat(AValue: Double); begin If CheckRange(AValue) then SetData(@Avalue) else RangeError(AValue,FMinValue,FMaxValue); end; procedure TFloatField.SetAsLongint(AValue: Longint); begin SetAsFloat(Avalue); end; procedure TFloatField.SetAsString(const AValue: string); Var R : Double; Code : longint; begin Val(AVAlue,R,Code); If Code<>0 then DatabaseErrorFmt(SNotAFloat,[AVAlue]) Else SetAsFloat(R); end; constructor TFloatField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDatatype(ftfloat); end; Function TFloatField.CheckRange(AValue : Double) : Boolean; begin If (FMinValue<>0) or (FmaxValue<>0) then Result:=(AValue>=FMinValue) and (AVAlue<=FMAxValue) else Result:=True; end; { TBooleanField } function TBooleanField.GetAsBoolean: Boolean; begin If not GetData(@Result) then Result:=False; end; function TBooleanField.GetAsVariant: Variant; Var b : boolean; begin If GetData(@b) then Result := b else Result:=Null; end; function TBooleanField.GetAsString: string; Var B : boolean; begin If Getdata(@B) then Result:=FDisplays[False,B] else result:=''; end; function TBooleanField.GetDataSize: Word; begin Result:=SizeOf(Boolean); end; function TBooleanField.GetDefaultWidth: Longint; begin Result:=Length(FDisplays[false,false]); If ResultAValue then begin I:=Pos(';',AValue); If (I<2) or (I=Length(AValue)) then DatabaseErrorFmt(SInvalidDisplayValues,[AValue]); FdisplayValues:=AValue; // Store display values and their uppercase equivalents; FDisplays[False,True]:=Copy(AValue,1,I-1); FDisplays[True,True]:=UpperCase(FDisplays[False,True]); FDisplays[False,False]:=Copy(AValue,I+1,Length(AValue)-i); FDisplays[True,False]:=UpperCase(FDisplays[False,False]); PropertyChanged(True); end; end; { TDateTimeField } function TDateTimeField.GetAsDateTime: TDateTime; begin If Not GetData(@Result) then Result:=0; end; function TDateTimeField.GetAsVariant: Variant; Var d : tDateTime; begin If Getdata(@d) then Result := d else Result:=Null; end; function TDateTimeField.GetAsFloat: Double; begin Result:=GetAsdateTime; end; function TDateTimeField.GetAsString: string; begin GetText(Result,False); end; function TDateTimeField.GetDataSize: Word; begin Result:=SizeOf(TDateTime); end; procedure TDateTimeField.GetText(var TheText: string; ADisplayText: Boolean); Var R : TDateTime; F : String; begin If Not Getdata(@R) then TheText:='' else begin If (ADisplayText) and (Length(FDisplayFormat)<>0) then F:=FDisplayFormat else Case DataType of ftTime : F:=ShortTimeFormat; ftDate : F:=ShortDateFormat; else F:='c' end; TheText:=FormatDateTime(F,R); end; end; procedure TDateTimeField.SetAsDateTime(AValue: TDateTime); begin SetData(@Avalue); end; procedure TDateTimeField.SetAsFloat(AValue: Double); begin SetAsDateTime(AValue); end; procedure TDateTimeField.SetAsString(const AValue: string); Var R : TDateTime; begin R:=StrToDateTime(AVAlue); SetData(@R); end; constructor TDateTimeField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDataType(ftDateTime); end; { TDateField } function TDateField.GetDataSize: Word; begin Result:=SizeOf(TDateTime); end; constructor TDateField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDataType(ftDate); end; { TTimeField } function TTimeField.GetDataSize: Word; begin Result:=SizeOf(TDateTime); end; constructor TTimeField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDataType(ftTime); end; { TBinaryField } class procedure TBinaryField.CheckTypeSize(AValue: Longint); begin // Just check for really invalid stuff; actual size is // dependent on the record... If AValue<1 then DatabaseErrorfmt(SInvalidFieldSize,[Avalue]); end; function TBinaryField.GetAsString: string; begin Setlength(Result,DataSize); GetData(Pointer(Result)); end; procedure TBinaryField.GetText(var TheText: string; ADisplayText: Boolean); begin TheText:=GetAsString; end; procedure TBinaryField.SetAsString(const AValue: string); Var Buf : PChar; Allocated : Boolean; begin Allocated:=False; If Length(AVAlue)=DataSize then Buf:=PChar(Avalue) else begin GetMem(Buf,DataSize); Move(Pchar(Avalue)[0],Buf^,DataSize); Allocated:=True; end; SetData(Buf); If Allocated then FreeMem(Buf,DataSize); end; procedure TBinaryField.SetText(const AValue: string); begin SetAsString(Avalue); end; constructor TBinaryField.Create(AOwner: TComponent); begin Inherited Create(AOwner); end; { TBytesField } function TBytesField.GetDataSize: Word; begin Result:=Size; end; constructor TBytesField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDataType(ftBytes); Size:=16; end; { TVarBytesField } function TVarBytesField.GetDataSize: Word; begin Result:=Size+2; end; constructor TVarBytesField.Create(AOwner: TComponent); begin INherited Create(AOwner); SetDataType(ftvarbytes); Size:=16; end; { TBCDField } class procedure TBCDField.CheckTypeSize(AValue: Longint); begin If not (AValue in [1..4]) then DatabaseErrorfmt(SInvalidFieldSize,[Avalue]); end; function TBCDField.GetAsCurrency: Currency; Var C : system.Currency; begin if GetData(@C) then result := C; end; function TBCDField.GetAsVariant: Variant; Var c : system.Currency; begin If GetData(@c) then Result := c else Result:=Null; end; function TBCDField.GetAsFloat: Double; begin result := GetAsCurrency; end; function TBCDField.GetAsLongint: Longint; begin result := round(GetAsCurrency); end; function TBCDField.GetAsString: string; var c : system.currency; begin If GetData(@C) then Result:=CurrToStr(C) else Result:=''; end; function TBCDField.GetDataSize: Word; begin result := sizeof(currency); end; function TBCDField.GetDefaultWidth: Longint; begin if precision > 0 then result := precision else result := 10; end; procedure TBCDField.GetText(var TheText: string; ADisplayText: Boolean); var c : system.currency; begin If GetData(@C) then begin if ADisplayText then begin if Displayformat='' then begin if Fcurrency then TheText := FloatToStrF(C,ffcurrency,FPrecision,0) else TheText := FloatToStrF(C,ffgeneral,FPrecision,0); end else TheText := CurrToStr(C); // ToDo: Displayformat is ignored end else begin if (Displayformat='') and (Editformat='') then begin if Fcurrency then TheText := FloatToStrF(C,ffcurrency,FPrecision,0) else TheText := FloatToStrF(C,ffFixed,FPrecision,0); end else TheText := CurrToStr(C); // ToDo: Displayformat is ignored end; end else TheText:=''; end; procedure TBCDField.SetAsCurrency(AValue: Currency); begin If CheckRange(AValue) then setdata(@AValue) else RangeError(AValue,FMinValue,FMaxvalue); end; Function TBCDField.CheckRange(AValue : Currency) : Boolean; begin If (FMinValue<>0) or (FmaxValue<>0) then Result:=(AValue>=FMinValue) and (AVAlue<=FMaxValue) else Result:=True; end; procedure TBCDField.SetAsFloat(AValue: Double); begin SetAsCurrency(AValue); end; procedure TBCDField.SetAsLongint(AValue: Longint); begin SetAsCurrency(AValue); end; procedure TBCDField.SetAsString(const AValue: string); begin SetAsCurrency(strtocurr(AValue)); end; constructor TBCDField.Create(AOwner: TComponent); begin Inherited Create(AOwner); FMaxvalue := 0; FMinvalue := 0; SetDataType(ftBCD); Size:=4; end; { TBlobField } procedure TBlobField.AssignTo(Dest: TPersistent); begin //!! To be implemented end; Function TBlobField.GetBlobStream(Mode : TBlobStreamMode) : TStream; begin Result:=FDataset.CreateBlobStream(Self,Mode); end; procedure TBlobField.FreeBuffers; begin end; function TBlobField.GetAsString: string; var Stream: TStream; begin Stream := GetBlobStream(bmRead); if Stream<>nil then With GetBlobStream(bmRead) do try SetLength(Result,Size); ReadBuffer(Pointer(Result)^,Size); finally Free end else Result := '(blob)'; end; function TBlobField.GetBlobSize: Longint; var Stream: TStream; begin Stream := GetBlobStream(bmread); if Stream <> nil then With Stream do try Result:=Size; finally Free; end else result := 0; end; function TBlobField.GetIsNull: Boolean; begin If Not Modified then result:= inherited GetIsnull else With GetBlobStream(bmread) do try Result:=(Size=0); Finally Free; end; end; procedure TBlobField.GetText(var TheText: string; ADisplayText: Boolean); begin TheText:=GetAsString; end; procedure TBlobField.SetAsString(const AValue: string); begin With GetBlobStream(bmwrite) do try WriteBuffer(Pointer(Avalue)^,Length(Avalue)); finally Free; end; end; procedure TBlobField.SetText(const AValue: string); begin SetAsString(AValue); end; constructor TBlobField.Create(AOwner: TComponent); begin Inherited Create(AOWner); SetDataType(ftBlob); end; procedure TBlobField.Assign(Source: TPersistent); begin //!! To be implemented end; procedure TBlobField.Clear; begin GetBlobStream(bmWrite).free; end; class function TBlobField.IsBlob: Boolean; begin Result:=True; end; procedure TBlobField.LoadFromFile(const FileName: string); Var S : TFileStream; begin S:=TFileStream.Create(FileName,fmOpenRead); try LoadFromStream(S); finally S.Free; end; end; procedure TBlobField.LoadFromStream(Stream: TStream); begin With GetBlobStream(bmWrite) do Try CopyFrom(Stream,0); finally Free; end; end; procedure TBlobField.SaveToFile(const FileName: string); Var S : TFileStream; begin S:=TFileStream.Create(FileName,fmCreate); try SaveToStream(S); finally S.Free; end; end; procedure TBlobField.SaveToStream(Stream: TStream); Var S : TStream; begin S:=GetBlobStream(bmRead); Try Stream.CopyFrom(S,0); finally S.Free; end; end; procedure TBlobField.SetFieldType(AValue: TFieldType); begin If AValue in [Low(TBlobType)..High(TBlobType)] then SetDatatype(Avalue); end; { TMemoField } constructor TMemoField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDataType(ftMemo); end; { TGraphicField } constructor TGraphicField.Create(AOwner: TComponent); begin Inherited Create(AOwner); SetDataType(ftGraphic); end; { TFields } Constructor TFields.Create(ADataset : TDataset); begin FDataSet:=ADataset; FFieldList:=TList.Create; FValidFieldKinds:=[fkData..fkInternalcalc]; end; Destructor TFields.Destroy; begin FFieldList.Free; end; Procedure Tfields.Changed; begin If Assigned(FOnChange) then FOnChange(Self); end; Procedure TFields.CheckfieldKind(Fieldkind : TFieldKind; Field : TField); begin If Not (FieldKind in ValidFieldKinds) Then DatabaseErrorFmt(SInvalidFieldKind,[Field.FieldName]); end; Function Tfields.GetCount : Longint; begin Result:=FFieldList.Count; end; Function TFields.GetField (Index : longint) : TField; begin Result:=Tfield(FFieldList[Index]); end; Procedure TFields.SetFieldIndex (Field : TField;Value : Integer); Var Old : Longint; begin Old := FFieldList.indexOf(Field); If Old=-1 then Exit; // Check value If Value=Count then Value:=Count-1; If Value<>Old then begin FFieldList.Delete(Old); FFieldList.Insert(Value,Field); Field.PropertyChanged(True); Changed; end; end; Procedure TFields.Add(Field : TField); begin CheckFieldName(Field.FieldName); FFieldList.Add(Field); Field.FFields:=Self; Changed; end; Procedure TFields.CheckFieldName (Const Value : String); Var I : longint; S : String; begin If FindField(Value)<>Nil then begin S:=UpperCase(Value); For I:=0 To FFieldList.Count-1 do If S=UpperCase(TField(FFieldList[i]).FieldName) Then DataBaseErrorFmt(SDuplicateFieldName,[Value],FDataset); end; end; Procedure TFields.CheckFieldNames (Const Value : String); Var I : longint; S,T : String; begin T:=Value; Repeat I:=Pos(T,';'); If I=0 Then I:=Length(T); S:=Copy(T,1,I-1); Delete(T,1,I); // Will raise an error if no such field... FieldByName(S); Until (T=''); end; Procedure TFields.Clear; begin FFieldList.Clear; end; Function TFields.FindField (Const Value : String) : TField; Var S : String; I : longint; begin Result:=Nil; S:=UpperCase(Value); For I:=0 To FFieldList.Count-1 do If S=UpperCase(TField(FFieldList[i]).FieldName) Then Begin {$ifdef dsdebug} Writeln ('Found field ',Value); {$endif} Result:=TField(FFieldList[I]); Exit; end; end; Function TFields.FieldByName (Const Value : String) : TField; begin Result:=FindField(Value); If result=Nil then DatabaseErrorFmt(SFieldNotFound,[Value],FDataset); end; Function TFields.FieldByNumber(FieldNo : Integer) : TField; Var i : Longint; begin Result:=Nil; For I:=0 to FFieldList.Count-1 do If FieldNo=TField(FFieldList[I]).FieldNo then begin Result:=TField(FFieldList[i]); Exit; end; end; Procedure TFields.GetFieldNames (Values : TStrings); Var i : longint; begin Values.Clear; For I:=0 to FFieldList.Count-1 do Values.Add(Tfield(FFieldList[I]).FieldName); end; Function TFields.IndexOf(Field : TField) : Longint; Var i : longint; begin Result:=-1; For I:=0 To FFieldList.Count-1 do If Pointer(Field)=FFieldList[i] Then Exit(I); end; procedure TFields.Remove(Value : TField); Var I : longint; begin I:=IndexOf(Value); If I<>0 then FFieldList.Delete(I); end; { $Log$ Revision 1.21 2005-01-12 10:29:54 michael * Patch from Joost Van der Sluis: - removed some duplicate definitions - restructured SetDataset - implemented UpdateMode, ProviderFlags Revision 1.20 2004/12/29 20:27:08 michael + Patch from Joost van der Sluis to correct AsVariant Revision 1.19 2004/12/13 19:20:42 michael * Patch from Joost van der Sluis - fixed bug #3180, TFields.Clear implemented - implemented TLargeintField Revision 1.18 2004/12/05 00:05:38 michael patch to enable RecNo and DisplayFormat Revision 1.17 2004/12/04 22:43:56 michael - implemented TBCDFields Revision 1.16 2004/11/30 21:18:34 michael + Fix from Jesus Reyes to fix TfieldDefs.Assign Revision 1.15 2004/08/21 21:10:00 michael * Patch from Joost van der Sluis - Empty recordsets don't show any bogus data anymore - Floatfiels.gettext fix - SetBufListsize fix forTDBGrid Revision 1.14 2004/08/01 13:00:29 michael + Patch for Tlongintfield by Joost van der Sluis Revision 1.13 2004/07/19 20:27:29 michael + Fixes from Jesus Reyes to implement DisplayWith, DisplayLabel, Visibility Revision 1.12 2004/07/18 13:16:50 michael + Changed extended to double for better Delphi compatibility Revision 1.11 2004/05/02 21:23:18 peter * use ptrint Revision 1.10 2004/03/25 20:43:39 michael Some compatibility additions Revision 1.9 2004/02/25 16:29:26 michael + Added AsInteger to TField. Maps to AsLongint for now Revision 1.8 2003/09/14 13:22:14 michael + Fixed error in TField.GetCanModify reported by Andrew Johnson Revision 1.7 2002/09/07 15:15:23 peter * old logs removed and tabs fixed }