123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2004 by the Free Pascal development team
- Some RTTI utils, based on RX rtti utils.
- 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.
- **********************************************************************}
- { **********************************************************************
- Based on the rttiutils unit that comes with RXLib.
- Adapted to work with FCL, free of VCL dependencies.
- Fixed some errors along the way as well. MVC.
- To make it work across the 'Root Component' (Form/Datamodule etc),
- you MUST set the FindGlobalComponentCallBack event handler.
- Original copyright:
- Delphi VCL Extensions (RX)
- Copyright (c) 1995, 1996 AO ROSNO
- Copyright (c) 1997 Master-Bank
- **********************************************************************}
- {$mode objfpc}
- {$H+}
- unit RttiUtils;
- interface
- uses
- SysUtils, Classes, {Graphics, Controls, Forms,} TypInfo, StrUtils;
- type
- { TPropInfoList }
- TPropInfoList = class(TObject)
- private
- FList: PPropList;
- FCount: Integer;
- FSize: Integer;
- function Get(Index: Integer): PPropInfo;
- public
- constructor Create(AObject: TObject; Filter: TTypeKinds; Sorted: Boolean = True);
- destructor Destroy; override;
- function Contains(P: PPropInfo): Boolean;
- function Find(const AName: string): PPropInfo;
- procedure Delete(Index: Integer);
- procedure Intersect(List: TPropInfoList);
- property Count: Integer read FCount;
- property Items[Index: Integer]: PPropInfo read Get; default;
- end;
- { TPropsStorage }
- TReadStrEvent = function(const ASection, Item, Default: string): string of object;
- TWriteStrEvent = procedure(const ASection, Item, Value: string) of object;
- TEraseSectEvent = procedure(const ASection: string) of object;
- TPropStorageOption = (psoAlwaysStoreStringsCount);
- TPropStorageOptions = set of TPropStorageOption;
-
- TPropsStorage = class(TObject)
- private
- FObject: TObject;
- FOwner: TComponent;
- FPrefix: string;
- FSection: string;
- FOptions : TPropStorageOptions;
- FOnReadString: TReadStrEvent;
- FOnWriteString: TWriteStrEvent;
- FOnEraseSection: TEraseSectEvent;
- function StoreIntegerProperty(PropInfo: PPropInfo): string;
- function StoreCharProperty(PropInfo: PPropInfo): string;
- function StoreEnumProperty(PropInfo: PPropInfo): string;
- function StoreFloatProperty(PropInfo: PPropInfo): string;
- function StoreStringProperty(PropInfo: PPropInfo): string;
- function StoreSetProperty(PropInfo: PPropInfo): string;
- function StoreClassProperty(PropInfo: PPropInfo): string;
- function StoreStringsProperty(PropInfo: PPropInfo): string;
- function StoreComponentProperty(PropInfo: PPropInfo): string;
- function StoreLStringProperty(PropInfo: PPropInfo): string;
- function StoreWCharProperty(PropInfo: PPropInfo): string;
- function StoreVariantProperty(PropInfo: PPropInfo): string;
- procedure LoadLStringProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadWCharProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadVariantProperty(const S: string; PropInfo: PPropInfo);
- function StoreInt64Property(PropInfo: PPropInfo): string;
- procedure LoadInt64Property(const S: string; PropInfo: PPropInfo);
- procedure LoadIntegerProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadCharProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadEnumProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadFloatProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadStringProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadSetProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadClassProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadStringsProperty(const S: string; PropInfo: PPropInfo);
- procedure LoadComponentProperty(const S: string; PropInfo: PPropInfo);
- function CreateInfoList(AComponent: TComponent; StoredList: TStrings): TStrings;
- procedure FreeInfoLists(Info: TStrings);
- protected
- function ReadString(const ASection, Item, Default: string): string; virtual;
- procedure WriteString(const ASection, Item, Value: string); virtual;
- procedure EraseSection(const ASection: string); virtual;
- function GetItemName(const APropName: string): string; virtual;
- function CreateStorage: TPropsStorage; virtual;
- public
- procedure StoreAnyProperty(PropInfo: PPropInfo);
- procedure LoadAnyProperty(PropInfo: PPropInfo);
- procedure StoreProperties(PropList: TStrings);
- procedure LoadProperties(PropList: TStrings);
- procedure LoadObjectsProps(AComponent: TComponent; StoredList: TStrings);
- procedure StoreObjectsProps(AComponent: TComponent; StoredList: TStrings);
- Property Options : TPropStorageOptions Read FOptions Write FOptions;
- property AObject: TObject read FObject write FObject;
- property Prefix: string read FPrefix write FPrefix;
- property Section: string read FSection write FSection;
- property OnReadString: TReadStrEvent read FOnReadString write FOnReadString;
- property OnWriteString: TWriteStrEvent read FOnWriteString write FOnWriteString;
- property OnEraseSection: TEraseSectEvent read FOnEraseSection write FOnEraseSection;
- end;
- { Utility routines }
- procedure UpdateStoredList(AComponent: TComponent; AStoredList: TStrings; FromForm: Boolean);
- function CreateStoredItem(const CompName, PropName: string): string;
- function ParseStoredItem(const Item: string; var CompName, PropName: string): Boolean;
- const
- sPropNameDelimiter: string = '_';
- Type
- TFindComponentEvent = Function (Const Name : String) : TComponent;
- Var
- FindGlobalComponentCallBack : TFindComponentEvent;
- implementation
- const
- sCount = 'Count';
- sItem = 'Item%d';
- sNull = '(null)';
- type
- TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
- function GetPropType(PropInfo: PPropInfo): PTypeInfo;
- begin
- Result := PropInfo^.PropType;
- end;
- { TPropInfoList }
- constructor TPropInfoList.Create(AObject: TObject; Filter: TTypeKinds; Sorted: Boolean);
- begin
- if AObject <> nil then
- begin
- FCount := GetPropList(AObject.ClassInfo, Filter, nil, Sorted);
- FSize := FCount * SizeOf(Pointer);
- GetMem(FList, FSize);
- GetPropList(AObject.ClassInfo, Filter, FList, Sorted);
- end
- else
- begin
- FCount := 0;
- FList := nil;
- end;
- end;
- destructor TPropInfoList.Destroy;
- begin
- if FList <> nil then FreeMem(FList, FSize);
- end;
- function TPropInfoList.Contains(P: PPropInfo): Boolean;
- var
- I: Integer;
- begin
- for I := 0 to FCount - 1 do
- with FList^[I]^ do
- if (PropType = P^.PropType) and (CompareText(Name, P^.Name) = 0) then
- begin
- Result := True;
- Exit;
- end;
- Result := False;
- end;
- function TPropInfoList.Find(const AName: string): PPropInfo;
- var
- I: Integer;
- begin
- for I := 0 to FCount - 1 do
- with FList^[I]^ do
- if (CompareText(Name, AName) = 0) then
- begin
- Result := FList^[I];
- Exit;
- end;
- Result := nil;
- end;
- procedure TPropInfoList.Delete(Index: Integer);
- begin
- Dec(FCount);
- if Index < FCount then Move(FList^[Index + 1], FList^[Index],
- (FCount - Index) * SizeOf(Pointer));
- end;
- function TPropInfoList.Get(Index: Integer): PPropInfo;
- begin
- Result := FList^[Index];
- end;
- procedure TPropInfoList.Intersect(List: TPropInfoList);
- var
- I: Integer;
- begin
- for I := FCount - 1 downto 0 do
- if not List.Contains(FList^[I]) then Delete(I);
- end;
- { Utility routines }
- function CreateStoredItem(const CompName, PropName: string): string;
- begin
- Result := '';
- if (CompName <> '') and (PropName <> '') then
- Result := CompName + '.' + PropName;
- end;
- function ParseStoredItem(const Item: string; var CompName, PropName: string): Boolean;
- var
- I: Integer;
- begin
- Result := False;
- if Length(Item) = 0 then Exit;
- I := Pos('.', Item);
- if I > 0 then begin
- CompName := Trim(Copy(Item, 1, I - 1));
- PropName := Trim(Copy(Item, I + 1, MaxInt));
- Result := (Length(CompName) > 0) and (Length(PropName) > 0);
- end;
- end;
- function ReplaceComponentName(const Item, CompName: string): string;
- var
- ACompName, APropName: string;
- begin
- Result := '';
- if ParseStoredItem(Item, ACompName, APropName) then
- Result := CreateStoredItem(CompName, APropName);
- end;
- procedure UpdateStoredList(AComponent: TComponent; AStoredList: TStrings; FromForm: Boolean);
- var
- I: Integer;
- Component: TComponent;
- CompName, PropName: string;
- begin
- if (AStoredList = nil) or (AComponent = nil) then
- Exit;
- for I := AStoredList.Count - 1 downto 0 do
- begin
- if ParseStoredItem(AStoredList[I], CompName, PropName) then
- begin
- if FromForm then
- begin
- Component := AComponent.FindComponent(CompName);
- if Component = nil then
- AStoredList.Delete(I)
- else
- AStoredList.Objects[I]:=Component;
- end
- else
- begin
- Component := TComponent(AStoredList.Objects[I]);
- if Component <> nil then
- AStoredList[I] := ReplaceComponentName(AStoredList[I], Component.Name)
- else
- AStoredList.Delete(I);
- end;
- end
- else
- AStoredList.Delete(I);
- end;
- end;
- function FindGlobalComponent(const Name: string): TComponent;
- begin
- Result:=Nil;
- If Assigned(FindGlobalComponentCallBack) then
- Result:=FindGlobalComponentCallBack(Name);
- end;
- { TPropsStorage }
- function TPropsStorage.GetItemName(const APropName: string): string;
- begin
- Result := Prefix + APropName;
- end;
- procedure TPropsStorage.LoadAnyProperty(PropInfo: PPropInfo);
- var
- S, Def: string;
- begin
- try
- if PropInfo <> nil then
- begin
- case PropInfo^.PropType^.Kind of
- tkBool,
- tkInteger: Def := StoreIntegerProperty(PropInfo);
- tkChar: Def := StoreCharProperty(PropInfo);
- tkEnumeration: Def := StoreEnumProperty(PropInfo);
- tkFloat: Def := StoreFloatProperty(PropInfo);
- tkWChar: Def := StoreWCharProperty(PropInfo);
- tkAstring,
- tkLString: Def := StoreLStringProperty(PropInfo);
- tkWString: Def := StoreLStringProperty(PropInfo);
- tkVariant: Def := StoreVariantProperty(PropInfo);
- tkInt64: Def := StoreInt64Property(PropInfo);
- tkString: Def := StoreStringProperty(PropInfo);
- tkSet: Def := StoreSetProperty(PropInfo);
- tkClass: Def := '';
- else
- Exit;
- end;
- if (Def <> '') or (PropInfo^.PropType^.Kind in [tkString, tkClass])
- or (PropInfo^.PropType^.Kind in [tkAString,tkLString, tkWString, tkWChar]) then
- S := Trim(ReadString(Section, GetItemName(PropInfo^.Name), Def))
- else
- S := '';
- case PropInfo^.PropType^.Kind of
- tkBool:LoadIntegerProperty(S,PropInfo);
- tkInteger: LoadIntegerProperty(S, PropInfo);
- tkChar: LoadCharProperty(S, PropInfo);
- tkEnumeration: LoadEnumProperty(S, PropInfo);
- tkFloat: LoadFloatProperty(S, PropInfo);
- tkWChar: LoadWCharProperty(S, PropInfo);
- tkAString,
- tkLString: LoadLStringProperty(S, PropInfo);
- tkWString: LoadLStringProperty(S, PropInfo);
- tkVariant: LoadVariantProperty(S, PropInfo);
- tkInt64: LoadInt64Property(S, PropInfo);
- tkString: LoadStringProperty(S, PropInfo);
- tkSet: LoadSetProperty(S, PropInfo);
- tkClass: LoadClassProperty(S, PropInfo);
- else
- Exit;
- end;
- end;
- except
- { ignore any exception }
- end;
- end;
- procedure TPropsStorage.StoreAnyProperty(PropInfo: PPropInfo);
- var
- S: string;
- begin
- if PropInfo <> nil then
- begin
- case PropInfo^.PropType^.Kind of
- tkInteger: S := StoreIntegerProperty(PropInfo);
- tkChar: S := StoreCharProperty(PropInfo);
- tkEnumeration: S := StoreEnumProperty(PropInfo);
- tkFloat: S := StoreFloatProperty(PropInfo);
- tkAstring: S := StoreLStringProperty(PropInfo);
- tkWString: S := StoreLStringProperty(PropInfo);
- tkWChar: S := StoreWCharProperty(PropInfo);
- tkVariant: S := StoreVariantProperty(PropInfo);
- tkInt64: S := StoreInt64Property(PropInfo);
- tkString: S := StoreStringProperty(PropInfo);
- tkSet: S := StoreSetProperty(PropInfo);
- tkClass: S := StoreClassProperty(PropInfo);
- tkBool: S:=StoreIntegerProperty(PropInfo);
- else
- Exit;
- end;
- if (S <> '') or (PropInfo^.PropType^.Kind in [tkString
- , tkLString, tkAString, tkWString, tkWChar ]) then
- WriteString(Section, GetItemName(PropInfo^.Name), Trim(S));
- end;
- end;
- function TPropsStorage.StoreIntegerProperty(PropInfo: PPropInfo): string;
- begin
- Result := IntToStr(GetOrdProp(FObject, PropInfo));
- end;
- function TPropsStorage.StoreCharProperty(PropInfo: PPropInfo): string;
- begin
- Result := Char(GetOrdProp(FObject, PropInfo));
- end;
- function TPropsStorage.StoreEnumProperty(PropInfo: PPropInfo): string;
- begin
- Result := GetEnumName(GetPropType(PropInfo), GetOrdProp(FObject, PropInfo));
- end;
- function TPropsStorage.StoreFloatProperty(PropInfo: PPropInfo): string;
- const
- Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
- begin
- Result := StringReplace(FloatToStrF(GetFloatProp(FObject, PropInfo), ffGeneral,
- Precisions[GetTypeData(GetPropType(PropInfo))^.FloatType], 0),
- DecimalSeparator, '.',[rfReplaceAll]);
- end;
- function TPropsStorage.StoreStringProperty(PropInfo: PPropInfo): string;
- begin
- Result := GetStrProp(FObject, PropInfo);
- end;
- function TPropsStorage.StoreLStringProperty(PropInfo: PPropInfo): string;
- begin
- Result := GetStrProp(FObject, PropInfo);
- end;
- function TPropsStorage.StoreWCharProperty(PropInfo: PPropInfo): string;
- begin
- Result := Char(GetOrdProp(FObject, PropInfo));
- end;
- function TPropsStorage.StoreVariantProperty(PropInfo: PPropInfo): string;
- begin
- Result := GetVariantProp(FObject, PropInfo);
- end;
- function TPropsStorage.StoreInt64Property(PropInfo: PPropInfo): string;
- begin
- Result := IntToStr(GetInt64Prop(FObject, PropInfo));
- end;
- function TPropsStorage.StoreSetProperty(PropInfo: PPropInfo): string;
- var
- TypeInfo: PTypeInfo;
- W: Cardinal;
- I: Integer;
- begin
- Result := '[';
- W := GetOrdProp(FObject, PropInfo);
- TypeInfo := GetTypeData(GetPropType(PropInfo))^.CompType;
- for I := 0 to SizeOf(TCardinalSet) * 8 - 1 do
- if I in TCardinalSet(W) then begin
- if Length(Result) <> 1 then Result := Result + ',';
- Result := Result + GetEnumName(TypeInfo, I);
- end;
- Result := Result + ']';
- end;
- function TPropsStorage.StoreStringsProperty(PropInfo: PPropInfo): string;
- var
- List: TObject;
- I: Integer;
- SectName: string;
- begin
- Result := '';
- List := TObject(GetObjectProp(Self.FObject, PropInfo));
- SectName := Format('%s.%s', [Section, GetItemName(PropInfo^.Name)]);
- EraseSection(SectName);
- if (List is TStrings)
- and ((TStrings(List).Count > 0) or (psoAlwaysStoreStringsCount in Options)) then
- begin
- WriteString(SectName, sCount, IntToStr(TStrings(List).Count));
- for I := 0 to TStrings(List).Count - 1 do
- WriteString(SectName, Format(sItem, [I]), TStrings(List)[I]);
- end;
- end;
- function TPropsStorage.StoreComponentProperty(PropInfo: PPropInfo): string;
- var
- Comp: TComponent;
- RootName: string;
- begin
- Comp := TComponent(GetObjectProp(FObject, PropInfo));
- if Comp <> nil then begin
- Result := Comp.Name;
- if (Comp.Owner <> nil) and (Comp.Owner <> FOwner) then begin
- RootName := Comp.Owner.Name;
- if RootName = '' then begin
- RootName := Comp.Owner.ClassName;
- if (RootName <> '') and (UpCase(RootName[1]) = 'T') then
- Delete(RootName, 1, 1);
- end;
- Result := Format('%s.%s', [RootName, Result]);
- end;
- end
- else Result := sNull;
- end;
- function TPropsStorage.StoreClassProperty(PropInfo: PPropInfo): string;
- var
- Saver: TPropsStorage;
- I: Integer;
- Obj: TObject;
- procedure StoreObjectProps(Obj: TObject; const APrefix, ASection: string);
- var
- I: Integer;
- Props: TPropInfoList;
- begin
- with Saver do begin
- AObject := Obj;
- Prefix := APrefix;
- Section := ASection;
- FOnWriteString := Self.FOnWriteString;
- FOnEraseSection := Self.FOnEraseSection;
- Props := TPropInfoList.Create(AObject, tkProperties);
- try
- for I := 0 to Props.Count - 1 do StoreAnyProperty(Props.Items[I]);
- finally
- Props.Free;
- end;
- end;
- end;
- begin
- Result := '';
- Obj := TObject(GetObjectProp(Self.FObject, PropInfo));
- if (Obj <> nil) then begin
- if Obj is TStrings then StoreStringsProperty(PropInfo)
- else if Obj is TCollection then begin
- EraseSection(Format('%s.%s', [Section, Prefix + PropInfo^.Name]));
- Saver := CreateStorage;
- try
- WriteString(Section, Format('%s.%s', [Prefix + PropInfo^.Name, sCount]),
- IntToStr(TCollection(Obj).Count));
- for I := 0 to TCollection(Obj).Count - 1 do begin
- StoreObjectProps(TCollection(Obj).Items[I],
- Format(sItem, [I]) + sPropNameDelimiter,
- Format('%s.%s', [Section, Prefix + PropInfo^.Name]));
- end;
- finally
- Saver.Free;
- end;
- end
- else if Obj is TComponent then begin
- Result := StoreComponentProperty(PropInfo);
- Exit;
- end;
- end;
- Saver := CreateStorage;
- try
- with Saver do begin
- StoreObjectProps(Obj, Self.Prefix + PropInfo^.Name, Self.Section);
- end;
- finally
- Saver.Free;
- end;
- end;
- procedure TPropsStorage.LoadIntegerProperty(const S: string; PropInfo: PPropInfo);
- begin
- SetOrdProp(FObject, PropInfo, StrToIntDef(S, 0));
- end;
- procedure TPropsStorage.LoadCharProperty(const S: string; PropInfo: PPropInfo);
- begin
- SetOrdProp(FObject, PropInfo, Integer(S[1]));
- end;
- procedure TPropsStorage.LoadEnumProperty(const S: string; PropInfo: PPropInfo);
- var
- I: Integer;
- EnumType: PTypeInfo;
- begin
- EnumType := GetPropType(PropInfo);
- with GetTypeData(EnumType)^ do
- for I := MinValue to MaxValue do
- if CompareText(GetEnumName(EnumType, I), S) = 0 then
- begin
- SetOrdProp(FObject, PropInfo, I);
- Exit;
- end;
- end;
- procedure TPropsStorage.LoadFloatProperty(const S: string; PropInfo: PPropInfo);
- begin
- SetFloatProp(FObject, PropInfo, StrToFloat(StringReplace(S, '.',
- DecimalSeparator,[rfReplaceAll])));
- end;
- procedure TPropsStorage.LoadInt64Property(const S: string; PropInfo: PPropInfo);
- begin
- SetInt64Prop(FObject, PropInfo, StrToInt64Def(S, 0));
- end;
- procedure TPropsStorage.LoadLStringProperty(const S: string; PropInfo: PPropInfo);
- begin
- SetStrProp(FObject, PropInfo, S);
- end;
- procedure TPropsStorage.LoadWCharProperty(const S: string; PropInfo: PPropInfo);
- begin
- SetOrdProp(FObject, PropInfo, Longint(S[1]));
- end;
- procedure TPropsStorage.LoadVariantProperty(const S: string; PropInfo: PPropInfo);
- begin
- SetVariantProp(FObject, PropInfo, S);
- end;
- procedure TPropsStorage.LoadStringProperty(const S: string; PropInfo: PPropInfo);
- begin
- SetStrProp(FObject, PropInfo, S);
- end;
- procedure TPropsStorage.LoadSetProperty(const S: string; PropInfo: PPropInfo);
- const
- Delims = [' ', ',', '[', ']'];
- var
- TypeInfo: PTypeInfo;
- W: Cardinal;
- I, N: Integer;
- Count: Integer;
- EnumName: string;
- begin
- W := 0;
- TypeInfo := GetTypeData(GetPropType(PropInfo))^.CompType;
- Count := WordCount(S, Delims);
- for N := 1 to Count do begin
- EnumName := ExtractWord(N, S, Delims);
- try
- I := GetEnumValue(TypeInfo, EnumName);
- if I >= 0 then Include(TCardinalSet(W), I);
- except
- end;
- end;
- SetOrdProp(FObject, PropInfo, W);
- end;
- procedure TPropsStorage.LoadStringsProperty(const S: string; PropInfo: PPropInfo);
- var
- List: TObject;
- Temp: TStrings;
- I, Cnt: Integer;
- SectName: string;
- begin
- List := TObject(GetObjectProp(Self.FObject, PropInfo));
- if (List is TStrings) then begin
- SectName := Format('%s.%s', [Section, GetItemName(PropInfo^.Name)]);
- Cnt := StrToIntDef(Trim(ReadString(SectName, sCount, '0')), 0);
- if Cnt > 0 then begin
- Temp := TStringList.Create;
- try
- for I := 0 to Cnt - 1 do
- Temp.Add(ReadString(SectName, Format(sItem, [I]), ''));
- TStrings(List).Assign(Temp);
- finally
- Temp.Free;
- end;
- end;
- end;
- end;
- procedure TPropsStorage.LoadComponentProperty(const S: string; PropInfo: PPropInfo);
- var
- RootName, Name: string;
- Root: TComponent;
- P: Integer;
- begin
- if Trim(S) = '' then Exit;
- if CompareText(SNull, Trim(S)) = 0 then begin
- SetOrdProp(FObject, PropInfo, Longint(nil));
- Exit;
- end;
- P := Pos('.', S);
- if P > 0 then begin
- RootName := Trim(Copy(S, 1, P - 1));
- Name := Trim(Copy(S, P + 1, MaxInt));
- end
- else begin
- RootName := '';
- Name := Trim(S);
- end;
- if RootName <> '' then Root := FindGlobalComponent(RootName)
- else Root := FOwner;
- if (Root <> nil) then
- SetObjectProp(FObject, PropInfo, Root.FindComponent(Name));
- end;
- procedure TPropsStorage.LoadClassProperty(const S: string; PropInfo: PPropInfo);
- var
- Loader: TPropsStorage;
- I: Integer;
- Cnt: Integer;
- Recreate: Boolean;
- Obj: TObject;
- procedure LoadObjectProps(Obj: TObject; const APrefix, ASection: string);
- var
- I: Integer;
- Props: TPropInfoList;
- begin
- with Loader do begin
- AObject := Obj;
- Prefix := APrefix;
- Section := ASection;
- FOnReadString := Self.FOnReadString;
- Props := TPropInfoList.Create(AObject, tkProperties);
- try
- for I := 0 to Props.Count - 1 do LoadAnyProperty(Props.Items[I]);
- finally
- Props.Free;
- end;
- end;
- end;
- begin
- Obj := TObject(GetObjectProp(Self.FObject, PropInfo));
- if (Obj <> nil) then begin
- if Obj is TStrings then LoadStringsProperty(S, PropInfo)
- else if Obj is TCollection then begin
- Loader := CreateStorage;
- try
- Cnt := TCollection(Obj).Count;
- Cnt := StrToIntDef(ReadString(Section, Format('%s.%s',
- [Prefix + PropInfo^.Name, sCount]), IntToStr(Cnt)), Cnt);
- Recreate := TCollection(Obj).Count <> Cnt;
- TCollection(Obj).BeginUpdate;
- try
- if Recreate then TCollection(Obj).Clear;
- for I := 0 to Cnt - 1 do begin
- if Recreate then TCollection(Obj).Add;
- LoadObjectProps(TCollection(Obj).Items[I],
- Format(sItem, [I]) + sPropNameDelimiter,
- Format('%s.%s', [Section, Prefix + PropInfo^.Name]));
- end;
- finally
- TCollection(Obj).EndUpdate;
- end;
- finally
- Loader.Free;
- end;
- end
- else if Obj is TComponent then begin
- LoadComponentProperty(S, PropInfo);
- Exit;
- end;
- end;
- Loader := CreateStorage;
- try
- LoadObjectProps(Obj, Self.Prefix + PropInfo^.Name, Self.Section);
- finally
- Loader.Free;
- end;
- end;
- procedure TPropsStorage.StoreProperties(PropList: TStrings);
- var
- I: Integer;
- Props: TPropInfoList;
- begin
- Props := TPropInfoList.Create(AObject, tkProperties);
- try
- for I := 0 to PropList.Count - 1 do
- StoreAnyProperty(Props.Find(PropList[I]));
- finally
- Props.Free;
- end;
- end;
- procedure TPropsStorage.LoadProperties(PropList: TStrings);
- var
- I: Integer;
- Props: TPropInfoList;
- begin
- Props := TPropInfoList.Create(AObject, tkProperties);
- try
- for I := 0 to PropList.Count - 1 do
- LoadAnyProperty(Props.Find(PropList[I]));
- finally
- Props.Free;
- end;
- end;
- function TPropsStorage.CreateInfoList(AComponent: TComponent; StoredList: TStrings): TStrings;
- var
- I: Integer;
- Obj: TComponent;
- Props: TPropInfoList;
- begin
- UpdateStoredList(AComponent, StoredList, False);
- Result := TStringList.Create;
- try
- TStringList(Result).Sorted := True;
- for I := 0 to StoredList.Count - 1 do
- begin
- Obj := TComponent(StoredList.Objects[I]);
- if Result.IndexOf(Obj.Name) < 0 then
- begin
- Props := TPropInfoList.Create(Obj, tkProperties);
- try
- Result.AddObject(Obj.Name, Props);
- except
- Props.Free;
- raise;
- end;
- end;
- end;
- except
- On E : Exception do
- begin
- Result.Free;
- Result := nil;
- end;
- end;
- end;
- procedure TPropsStorage.FreeInfoLists(Info: TStrings);
- var
- I: Integer;
- begin
- for I := Info.Count - 1 downto 0 do Info.Objects[I].Free;
- Info.Free;
- end;
- procedure TPropsStorage.LoadObjectsProps(AComponent: TComponent; StoredList: TStrings);
- var
- Info: TStrings;
- I, Idx: Integer;
- Props: TPropInfoList;
- CompName, PropName: string;
- begin
- Info := CreateInfoList(AComponent, StoredList);
- if Info <> nil then
- try
- FOwner := AComponent;
- for I := 0 to StoredList.Count - 1 do
- begin
- if ParseStoredItem(StoredList[I], CompName, PropName) then
- begin
- AObject := StoredList.Objects[I];
- Prefix := TComponent(AObject).Name;
- Idx := Info.IndexOf(Prefix);
- if Idx >= 0 then
- begin
- Prefix := Prefix + sPropNameDelimiter;
- Props := TPropInfoList(Info.Objects[Idx]);
- if Props <> nil then
- LoadAnyProperty(Props.Find(PropName));
- end;
- end;
- end;
- finally
- FOwner := nil;
- FreeInfoLists(Info);
- end;
- end;
- procedure TPropsStorage.StoreObjectsProps(AComponent: TComponent; StoredList: TStrings);
- var
- Info: TStrings;
- I, Idx: Integer;
- Props: TPropInfoList;
- CompName, PropName: string;
- begin
- Info := CreateInfoList(AComponent, StoredList);
- if Info <> nil then
- try
- FOwner := AComponent;
- for I := 0 to StoredList.Count - 1 do
- begin
- if ParseStoredItem(StoredList[I], CompName, PropName) then
- begin
- AObject := StoredList.Objects[I];
- Prefix := TComponent(AObject).Name;
- Idx := Info.IndexOf(Prefix);
- if Idx >= 0 then
- begin
- Prefix := Prefix + sPropNameDelimiter;
- Props := TPropInfoList(Info.Objects[Idx]);
- if Props <> nil then
- StoreAnyProperty(Props.Find(PropName));
- end;
- end;
- end;
- finally
- FOwner := nil;
- FreeInfoLists(Info);
- end;
- end;
- function TPropsStorage.CreateStorage: TPropsStorage;
- begin
- Result := TPropsStorage.Create;
- end;
- function TPropsStorage.ReadString(const ASection, Item, Default: string): string;
- begin
- if Assigned(FOnReadString) then Result := FOnReadString(ASection, Item, Default)
- else Result := '';
- end;
- procedure TPropsStorage.WriteString(const ASection, Item, Value: string);
- begin
- if Assigned(FOnWriteString) then FOnWriteString(ASection, Item, Value);
- end;
- procedure TPropsStorage.EraseSection(const ASection: string);
- begin
- if Assigned(FOnEraseSection) then FOnEraseSection(ASection);
- end;
- end.
|