{*********************************************************} {* Classes for table field/index lists *} {*********************************************************} (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * 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/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower FlashFiler * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1996-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {$I ffdefine.inc} unit uelement; interface uses ffllbase, fflldict, ubase, Classes, SysUtils; type TffeScratchDict = class(TffDataDictionary) public function CreateFieldDesc(const aIdent : TffDictItemName; const aDesc : TffDictItemDesc; aType : TffFieldType; aUnits : Integer; aDecPl : Integer; aReqFld : Boolean; const aValCheck : TffVCheckDescriptor) : PffFieldDescriptor; end; TffeBaseListItem = class(TffListItem) protected public Name: TffDictItemName; {$IFDEF DefeatWarnings} function Compare(aKey : Pointer): Integer; override; function Key: Pointer; override; {$ENDIF} end; TffeBaseList = class(TffList) protected function GetItem(aIndex: LongInt): TffeBaseListItem; public constructor Create; procedure Exchange(aIndex1, aIndex2: LongInt); function IndexOf(aElementName: TffDictItemName): LongInt; function InsertAt(aIndex: LongInt; aItem: TffeBaseListItem): Boolean; property Items[aIndex: LongInt]: TffeBaseListItem read GetItem; end; TffeFieldListItem = class(TffeBaseListItem) protected { private } protected function GetFieldType: TffFieldType; public fiDataTypeIndex : Integer; fiUnits : Word; fiDecPlaces : Word; fiRequired : Boolean; fiDescription : TffDictItemDesc; fiSize : Word; fiValCheck : TffVCheckDescriptor; constructor Create; procedure CalcActualValues; {- Use the DataDictionary to compute actual Units, Dec Pl, and Size } property FieldType: TffFieldType read GetFieldType; end; TffeFieldList = class(TffeBaseList) private protected function GetItem(aIndex: LongInt): TffeFieldListItem; public function AddEmpty: Boolean; function Insert(aName : TffDictItemName; aType : Integer; aUnits : Word; aDecPl : Word; aRequired : Boolean; aDesc : TffShStr; aValCheck : PffVCheckDescriptor): Boolean; function InsertEmpty(aIndex: LongInt): Boolean; property Items[aIndex: LongInt]: TffeFieldListItem read GetItem; end; TffeIndexListItem = class(TffeBaseListItem) protected {private} FFields: TStringList; { List of field names comprising this key } protected function GetBlockSize: Integer; function GetFieldCount: Integer; function GetFieldName(aIndex: Integer): TffDictItemName; procedure SetFieldName(aIndex: Integer; const Value: TffDictItemName); public iiKeyTypeIndex: Integer; {-1 = Undefined, 0 = Composite, 1 = User-Defined} iiKeyLen: SmallInt; iiUnique: Boolean; iiAscending: Boolean; iiCaseSensitive: Boolean; iiExtension: TffExtension; iiBlockSizeIndex: Integer; {-1 = Undefined, 0,1,2,3 = 4096, 8148, 16384, 32768} iiDescription: TffDictItemDesc; constructor Create; destructor Destroy; override; procedure AddField(aFieldName: TffDictItemName); procedure DeleteField(aFieldName: TffDictItemName); procedure ExchangeFields(aFieldName1, aFieldName2: TffDictItemName); property BlockSize: Integer read GetBlockSize; property FieldCount: Integer read GetFieldCount; property FieldName[aIndex: Integer]: TffDictItemName read GetFieldName write SetFieldName; end; TffeIndexList = class(TffeBaseList) private protected function GetItem(aIndex: LongInt): TffeIndexListItem; public function AddEmpty: Boolean; function FieldInUse(aFieldName: TffDictItemName): Integer; function Insert(aName: TffDictItemName; aKeyTypeIndex: Integer; aKeyLen: Integer; aUnique: Boolean; aAscending: Boolean; aCaseSensitive: Boolean; aExt: TffExtension; aBlockSize: Integer; aDesc: TffShStr): Boolean; function InsertEmpty(aIndex: LongInt): Boolean; procedure LoadFromDict(aDictionary: TffDataDictionary); property Items[aIndex: LongInt]: TffeIndexListItem read GetItem; end; const ktComposite = 0; ktUserDefined = 1; implementation var ScratchDict: TffeScratchDict; {=====TffeScratchDict methods=====} function TffeScratchDict.CreateFieldDesc(const aIdent : TffDictItemName; const aDesc : TffDictItemDesc; aType : TffFieldType; aUnits : Integer; aDecPl : Integer; aReqFld : Boolean; const aValCheck : TffVCheckDescriptor) : PffFieldDescriptor; begin { This was necessary to expose the protected method } Result := inherited CreateFieldDesc(aIdent, aDesc, aType, aUnits, aDecPl, aReqFld, PffVCheckDescriptor(@aValCheck)); end; {=====TffeBaseListItem methods=====} {$IFDEF DefeatWarnings} function TffeBaseListItem.Compare(aKey : Pointer): Integer; begin Result := 0; end; function TffeBaseListItem.Key: Pointer; begin Result := nil; end; {$ENDIF} {=====TffeBaseList methods=====} constructor TffeBaseList.Create; begin inherited Create; Sorted := False; end; procedure TffeBaseList.Exchange(aIndex1, aIndex2: LongInt); var Temp: Pointer; begin if not Sorted then begin Temp := fflList[aIndex1]; fflList[aIndex1] := fflList[aIndex2]; fflList[aIndex2] := Temp; end; end; function TffeBaseList.GetItem(aIndex: LongInt): TffeBaseListItem; begin Result := TffeBaseListItem(inherited Items[aIndex]); end; function TffeBaseList.IndexOf(aElementName: TffDictItemName): LongInt; var I: LongInt; begin Result := -1; aElementName := ANSIUppercase(aElementName); for I := 0 to Count - 1 do if ANSIUppercase(Items[I].Name) = aElementName then begin Result := I; Exit; end; end; function TffeBaseList.InsertAt(aIndex: LongInt; aItem: TffeBaseListItem): Boolean; begin Result := False; if not Sorted then begin if aIndex < Count then begin Result := Insert(aItem); Move(fflList^[aIndex], fflList^[aIndex + 1], SizeOf(fflList^[0]) * ((Count - 1) - aIndex)); {!!.55} fflList[aIndex] := aItem; end; end end; {=====TffeFieldListItem methods=====} constructor TffeFieldListItem.Create; begin inherited Create; Name := ''; fiDataTypeIndex := -1; fiUnits := 0; fiDecPlaces := 0; fiRequired := False; fiDescription := ''; end; procedure TffeFieldListItem.CalcActualValues; var FldCheck : TffVCheckDescriptor; FldDesc : PffFieldDescriptor; begin FldCheck.vdHasDefVal := False; { Compute the actual size, units, and dec pl for this field type } FldDesc := ScratchDict.CreateFieldDesc(Name, fiDescription, FieldType, fiUnits, fiDecPlaces, fiRequired, FldCheck); try fiSize := FldDesc^.fdLength; fiUnits := FldDesc^.fdUnits; fiDecPlaces := FldDesc^.fdDecPl; finally FFFreeMem(FldDesc, SizeOf(TffFieldDescriptor)); end; end; function TffeFieldListItem.GetFieldType: TffFieldType; begin Result := fftBoolean; if fiDataTypeIndex <> -1 then Result := FFEIndexToFieldType(fiDataTypeIndex); end; {=====TffeFieldList methods=====} function TffeFieldList.AddEmpty: Boolean; begin Result := inherited Insert(TffeFieldListItem.Create); end; function TffeFieldList.Insert(aName : TffDictItemName; aType : Integer; aUnits : Word; aDecPl : Word; aRequired : Boolean; aDesc : TffShStr; aValCheck : PffVCheckDescriptor): Boolean; var Item: TffeFieldListItem; begin Item := TffeFieldListItem.Create; with Item do begin Name := aName; fiDataTypeIndex := aType; fiUnits := aUnits; fiDecPlaces := aDecPl; fiRequired := aRequired; fiDescription := aDesc; if Assigned(aValCheck) then fiValCheck := aValCheck^; CalcActualValues; end; Result := inherited Insert(Item); end; function TffeFieldList.InsertEmpty(aIndex: LongInt): Boolean; begin Result := InsertAt(aIndex, TffeFieldListItem.Create); end; function TffeFieldList.GetItem(aIndex: LongInt): TffeFieldListItem; begin Result := nil; if aIndex < Count then Result := TffeFieldListItem(inherited Items[aIndex]); end; {=====TffeIndexListItem methods=====} constructor TffeIndexListItem.Create; begin inherited Create; Name := ''; iiKeyTypeIndex := ktComposite; iiKeyLen := 0; iiUnique := False; iiAscending := True; iiCaseSensitive := False; iiExtension := ''; iiBlockSizeIndex := -1; iiDescription := ''; FFields := TStringList.Create; end; destructor TffeIndexListItem.Destroy; begin FFields.Free; inherited Destroy; end; procedure TffeIndexListItem.AddField(aFieldName : TffDictItemName); begin if (Name <> '') then begin if (FieldCount >= ffcl_MaxIndexFlds) then {!!.05} raise Exception.CreateFmt('Maximum of %d fields per composite index', [ffcl_MaxIndexFlds]); FFields.Add(aFieldName); end; end; procedure TffeIndexListItem.DeleteField(aFieldName: TffDictItemName); var I: LongInt; begin I := FFields.IndexOf(aFieldName); if I <> -1 then FFields.Delete(I); end; procedure TffeIndexListItem.ExchangeFields(aFieldName1, aFieldName2 : TffDictItemName); begin with FFields do Exchange(IndexOf(aFieldName1),IndexOf(aFieldName2)); end; function TffeIndexListItem.GetBlockSize: Integer; begin Result := 0; if iiBlockSizeIndex > -1 then Result := (1 shl iiBlockSizeIndex) shl 12; end; function TffeIndexListItem.GetFieldCount: Integer; begin Result := FFields.Count; end; function TffeIndexListItem.GetFieldName(aIndex: Integer): TffDictItemName; begin Result := ''; if aIndex < FFields.Count then Result := FFields[aIndex]; end; procedure TffeIndexListItem.SetFieldName(aIndex: Integer; const Value: TffDictItemName); begin FFields.Delete(aIndex); FFields.Insert(aIndex, Value); end; {=====TffeIndexList methods=====} function TffeIndexList.AddEmpty: Boolean; begin Result := inherited Insert(TffeIndexListItem.Create); end; function TffeIndexList.FieldInUse(aFieldName: TffDictItemName): Integer; var F: Integer; begin for Result := 0 to Count - 1 do with Items[Result] do for F := 0 to FieldCount do if FFCmpShStr(FieldName[F], aFieldName, 255) = 0 then Exit; Result := -1; end; function TffeIndexList.Insert(aName: TffDictItemName; aKeyTypeIndex: Integer; aKeyLen: Integer; aUnique: Boolean; aAscending: Boolean; aCaseSensitive: Boolean; aExt: TffExtension; aBlockSize: Integer; aDesc: TffShStr): Boolean; var Item: TffeIndexListItem; begin Item := TffeIndexListItem.Create; with Item do begin Name := aName; iiKeyTypeIndex := aKeyTypeIndex; iiKeyLen := aKeyLen; iiUnique := aUnique; iiAscending := aAscending; iiCaseSensitive := aCaseSensitive; iiExtension := aExt; iiBlockSizeIndex := FFEBlockSizeIndex(aBlockSize); iiDescription := aDesc; end; Result := inherited Insert(Item); end; function TffeIndexList.InsertEmpty(aIndex: LongInt): Boolean; begin Result := InsertAt(aIndex, TffeIndexListItem.Create); end; function TffeIndexList.GetItem(aIndex: LongInt): TffeIndexListItem; begin Result := nil; if aIndex < Count then Result := TffeIndexListItem(inherited Items[aIndex]); end; procedure TffeIndexList.LoadFromDict(aDictionary: TffDataDictionary); var I, J: Integer; KeyTypeIndex: Integer; FileExtension: TffExtension; FileBlock: Integer; begin with aDictionary do begin Empty; for I := 0 to IndexCount - 1 do begin with IndexDescriptor[I]^ do begin if idCount = -1 then KeyTypeIndex := ktUserDefined else KeyTypeIndex := ktComposite; FileExtension := FileExt[idFile]; FileBlock := FileBlockSize[idFile]; if idFile = 0 then begin FileExtension := ''; FileBlock := -1; end; Insert(idName, KeyTypeIndex, idKeyLen, not idDups, idAscend, not idNoCase, FileExtension, FileBlock, idDesc); case KeyTypeIndex of ktComposite: { Get the fields, in order, that make up this index } for J := 0 to idCount - 1 do Items[IndexOf(idName)].AddField(FieldName[idFields[J]]); end; end; end; end; end; end.