{----------------------------------------------------------------------------- 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/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: JvProps.PAS, released on 2002-07-04. The Initial Developers of the Original Code are: Fedor Koshevnikov, Igor Pavluk and Serge Korolev Copyright (c) 1997, 1998 Fedor Koshevnikov, Igor Pavluk and Serge Korolev Copyright (c) 2001,2002 SGB Software All Rights Reserved. Last Modified: 2002-07-04 You may retrieve the latest version of this file at the Project JEDI's JVCL home page, located at http://jvcl.sourceforge.net Known Issues: -----------------------------------------------------------------------------} {$I JVCL.INC} unit JvProps; interface uses SysUtils, Classes, Forms, TypInfo; type TJvPropInfoList = class(TObject) private FList: PPropList; FCount: Integer; FSize: Integer; function Get(Index: Integer): PPropInfo; public constructor Create(AObject: TObject; Filter: TTypeKinds); destructor Destroy; override; function Contains(P: PPropInfo): Boolean; function Find(const AName: string): PPropInfo; procedure Delete(Index: Integer); procedure Intersect(List: TJvPropInfoList); property Count: Integer read FCount; property Items[Index: Integer]: PPropInfo read Get; default; end; 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; TJvPropsStorage = class(TObject) private FObject: TObject; FOwner: TComponent; FPrefix: string; FSection: string; 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; {$IFDEF WIN32} 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); {$ENDIF} {$IFDEF COMPILER4_UP} function StoreInt64Property(PropInfo: PPropInfo): string; procedure LoadInt64Property(const S: string; PropInfo: PPropInfo); {$ENDIF} 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: TJvPropsStorage; 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 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 {$IFDEF WIN32} sPropNameDelimiter: string = '_'; {$ELSE} sPropNameDelimiter: Char = '_'; {$ENDIF} implementation uses {$IFNDEF WIN32} WinTypes, WinProcs, JvStr16, {$ENDIF} JvStrUtils; const sCount = 'Count'; sItem = 'Item%d'; sNull = '(null)'; type TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1; {$IFNDEF WIN32} function GetEnumName(TypeInfo: PTypeInfo; Value: Integer): string; begin Result := TypInfo.GetEnumName(TypeInfo, Value)^; end; {$ENDIF} function GetPropType(PropInfo: PPropInfo): PTypeInfo; begin {$IFDEF COMPILER3_UP} Result := PropInfo^.PropType^; {$ELSE} Result := PropInfo^.PropType; {$ENDIF} end; //=== TJvPropInfoList ======================================================== constructor TJvPropInfoList.Create(AObject: TObject; Filter: TTypeKinds); begin inherited Create; if AObject <> nil then begin FCount := GetPropList(AObject.ClassInfo, Filter, nil); FSize := FCount * SizeOf(Pointer); GetMem(FList, FSize); GetPropList(AObject.ClassInfo, Filter, FList); end else begin FCount := 0; FList := nil; end; end; destructor TJvPropInfoList.Destroy; begin if FList <> nil then FreeMem(FList, FSize); inherited Destroy; end; function TJvPropInfoList.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 TJvPropInfoList.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 TJvPropInfoList.Delete(Index: Integer); begin Dec(FCount); if Index < FCount then Move(FList^[Index + 1], FList^[Index], (FCount - Index) * SizeOf(Pointer)); end; function TJvPropInfoList.Get(Index: Integer): PPropInfo; begin Result := FList^[Index]; end; procedure TJvPropInfoList.Intersect(List: TJvPropInfoList); 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; {$IFDEF WIN32} function FindGlobalComponent(const Name: string): TComponent; var I: Integer; begin for I := 0 to Screen.FormCount - 1 do begin Result := Screen.Forms[I]; if CompareText(Name, Result.Name) = 0 then Exit; end; for I := 0 to Screen.DataModuleCount - 1 do begin Result := Screen.DataModules[I]; if CompareText(Name, Result.Name) = 0 then Exit; end; Result := nil; end; {$ENDIF} //=== TJvPropsStorage ======================================================== function TJvPropsStorage.GetItemName(const APropName: string): string; begin Result := Prefix + APropName; end; procedure TJvPropsStorage.LoadAnyProperty(PropInfo: PPropInfo); var S, Def: string; begin try if PropInfo <> nil then begin case PropInfo^.PropType^.Kind of tkInteger: Def := StoreIntegerProperty(PropInfo); tkChar: Def := StoreCharProperty(PropInfo); tkEnumeration: Def := StoreEnumProperty(PropInfo); tkFloat: Def := StoreFloatProperty(PropInfo); {$IFDEF WIN32} tkWChar: Def := StoreWCharProperty(PropInfo); tkLString: Def := StoreLStringProperty(PropInfo); {$IFNDEF COMPILER3_UP} { - Delphi 2.0, C++Builder 1.0 } tkLWString: Def := StoreLStringProperty(PropInfo); {$ENDIF} tkVariant: Def := StoreVariantProperty(PropInfo); {$ENDIF WIN32} {$IFDEF COMPILER4_UP} tkInt64: Def := StoreInt64Property(PropInfo); {$ENDIF} tkString: Def := StoreStringProperty(PropInfo); tkSet: Def := StoreSetProperty(PropInfo); tkClass: Def := ''; else Exit; end; if (Def <> '') or (PropInfo^.PropType^.Kind in [tkString, tkClass]) {$IFDEF WIN32} or (PropInfo^.PropType^.Kind in [tkLString, {$IFNDEF COMPILER3_UP}tkLWString, {$ENDIF}tkWChar]) {$ENDIF WIN32} then S := Trim(ReadString(Section, GetItemName(PropInfo^.Name), Def)) else S := ''; case PropInfo^.PropType^.Kind of tkInteger: LoadIntegerProperty(S, PropInfo); tkChar: LoadCharProperty(S, PropInfo); tkEnumeration: LoadEnumProperty(S, PropInfo); tkFloat: LoadFloatProperty(S, PropInfo); {$IFDEF WIN32} tkWChar: LoadWCharProperty(S, PropInfo); tkLString: LoadLStringProperty(S, PropInfo); {$IFNDEF COMPILER3_UP} { - Delphi 2.0, C++Builder 1.0 } tkLWString: LoadLStringProperty(S, PropInfo); {$ENDIF} tkVariant: LoadVariantProperty(S, PropInfo); {$ENDIF WIN32} {$IFDEF COMPILER4_UP} tkInt64: LoadInt64Property(S, PropInfo); {$ENDIF} tkString: LoadStringProperty(S, PropInfo); tkSet: LoadSetProperty(S, PropInfo); tkClass: LoadClassProperty(S, PropInfo); end; end; except { ignore any exception } end; end; procedure TJvPropsStorage.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); {$IFDEF WIN32} tkLString: S := StoreLStringProperty(PropInfo); {$IFNDEF COMPILER3_UP} { - Delphi 2.0, C++Builder 1.0 } tkLWString: S := StoreLStringProperty(PropInfo); {$ENDIF} tkWChar: S := StoreWCharProperty(PropInfo); tkVariant: S := StoreVariantProperty(PropInfo); {$ENDIF WIN32} {$IFDEF COMPILER4_UP} tkInt64: S := StoreInt64Property(PropInfo); {$ENDIF} tkString: S := StoreStringProperty(PropInfo); tkSet: S := StoreSetProperty(PropInfo); tkClass: S := StoreClassProperty(PropInfo); else Exit; end; if (S <> '') or (PropInfo^.PropType^.Kind in [tkString {$IFDEF WIN32}, tkLString, {$IFNDEF COMPILER3_UP} tkLWString, {$ENDIF} tkWChar {$ENDIF WIN32}]) then WriteString(Section, GetItemName(PropInfo^.Name), Trim(S)); end; end; function TJvPropsStorage.StoreIntegerProperty(PropInfo: PPropInfo): string; begin Result := IntToStr(GetOrdProp(FObject, PropInfo)); end; function TJvPropsStorage.StoreCharProperty(PropInfo: PPropInfo): string; begin Result := Char(GetOrdProp(FObject, PropInfo)); end; function TJvPropsStorage.StoreEnumProperty(PropInfo: PPropInfo): string; begin Result := GetEnumName(GetPropType(PropInfo), GetOrdProp(FObject, PropInfo)); end; function TJvPropsStorage.StoreFloatProperty(PropInfo: PPropInfo): string; const {$IFDEF WIN32} Precisions: array [TFloatType] of Integer = (7, 15, 18, 18, 19); {$ELSE} Precisions: array [TFloatType] of Integer = (7, 15, 18, 18); {$ENDIF} begin Result := ReplaceStr(FloatToStrF(GetFloatProp(FObject, PropInfo), ffGeneral, Precisions[GetTypeData(GetPropType(PropInfo))^.FloatType], 0), DecimalSeparator, '.'); end; function TJvPropsStorage.StoreStringProperty(PropInfo: PPropInfo): string; begin Result := GetStrProp(FObject, PropInfo); end; {$IFDEF WIN32} function TJvPropsStorage.StoreLStringProperty(PropInfo: PPropInfo): string; begin Result := GetStrProp(FObject, PropInfo); end; function TJvPropsStorage.StoreWCharProperty(PropInfo: PPropInfo): string; begin Result := Char(GetOrdProp(FObject, PropInfo)); end; function TJvPropsStorage.StoreVariantProperty(PropInfo: PPropInfo): string; begin Result := GetVariantProp(FObject, PropInfo); end; {$ENDIF} {$IFDEF COMPILER4_UP} function TJvPropsStorage.StoreInt64Property(PropInfo: PPropInfo): string; begin Result := IntToStr(GetInt64Prop(FObject, PropInfo)); end; {$ENDIF} function TJvPropsStorage.StoreSetProperty(PropInfo: PPropInfo): string; var TypeInfo: PTypeInfo; W: Cardinal; I: Integer; begin Result := '['; W := GetOrdProp(FObject, PropInfo); TypeInfo := GetTypeData(GetPropType(PropInfo))^.CompType{$IFDEF COMPILER3_UP}^{$ENDIF}; 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 TJvPropsStorage.StoreStringsProperty(PropInfo: PPropInfo): string; var List: TObject; I: Integer; SectName: string; begin Result := ''; List := TObject(GetOrdProp(Self.FObject, PropInfo)); SectName := Format('%s.%s', [Section, GetItemName(PropInfo^.Name)]); EraseSection(SectName); if (List is TStrings) and (TStrings(List).Count > 0) 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 TJvPropsStorage.StoreComponentProperty(PropInfo: PPropInfo): string; var Comp: TComponent; RootName: string; begin Comp := TComponent(GetOrdProp(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 TJvPropsStorage.StoreClassProperty(PropInfo: PPropInfo): string; var Saver: TJvPropsStorage; I: Integer; Obj: TObject; procedure StoreObjectProps(Obj: TObject; const APrefix, ASection: string); var I: Integer; Props: TJvPropInfoList; begin with Saver do begin AObject := Obj; Prefix := APrefix; Section := ASection; FOnWriteString := Self.FOnWriteString; FOnEraseSection := Self.FOnEraseSection; Props := TJvPropInfoList.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(GetOrdProp(Self.FObject, PropInfo)); if Obj <> nil then begin if Obj is TStrings then StoreStringsProperty(PropInfo) {$IFDEF WIN32} 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 {$ENDIF} 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 TJvPropsStorage.LoadIntegerProperty(const S: string; PropInfo: PPropInfo); begin SetOrdProp(FObject, PropInfo, StrToIntDef(S, 0)); end; procedure TJvPropsStorage.LoadCharProperty(const S: string; PropInfo: PPropInfo); begin SetOrdProp(FObject, PropInfo, Integer(S[1])); end; procedure TJvPropsStorage.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 TJvPropsStorage.LoadFloatProperty(const S: string; PropInfo: PPropInfo); begin SetFloatProp(FObject, PropInfo, StrToFloat(ReplaceStr(S, '.', DecimalSeparator))); end; {$IFDEF COMPILER4_UP} procedure TJvPropsStorage.LoadInt64Property(const S: string; PropInfo: PPropInfo); begin SetInt64Prop(FObject, PropInfo, StrToInt64Def(S, 0)); end; {$ENDIF} {$IFDEF WIN32} procedure TJvPropsStorage.LoadLStringProperty(const S: string; PropInfo: PPropInfo); begin SetStrProp(FObject, PropInfo, S); end; procedure TJvPropsStorage.LoadWCharProperty(const S: string; PropInfo: PPropInfo); begin SetOrdProp(FObject, PropInfo, Longint(S[1])); end; procedure TJvPropsStorage.LoadVariantProperty(const S: string; PropInfo: PPropInfo); begin SetVariantProp(FObject, PropInfo, S); end; {$ENDIF} procedure TJvPropsStorage.LoadStringProperty(const S: string; PropInfo: PPropInfo); begin SetStrProp(FObject, PropInfo, S); end; procedure TJvPropsStorage.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{$IFDEF COMPILER3_UP}^{$ENDIF}; 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 TJvPropsStorage.LoadStringsProperty(const S: string; PropInfo: PPropInfo); var List: TObject; Temp: TStrings; I, Cnt: Integer; SectName: string; begin List := TObject(GetOrdProp(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 TJvPropsStorage.LoadComponentProperty(const S: string; PropInfo: PPropInfo); {$IFDEF WIN32} 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 SetOrdProp(FObject, PropInfo, Longint(Root.FindComponent(Name))); end; {$ELSE} begin if Trim(S) = '' then Exit; if CompareText(SNull, Trim(S)) = 0 then begin SetOrdProp(FObject, PropInfo, Longint(nil)); Exit; end; if FOwner <> nil then SetOrdProp(FObject, PropInfo, Longint(FOwner.FindComponent(Trim(S)))); end; {$ENDIF} procedure TJvPropsStorage.LoadClassProperty(const S: string; PropInfo: PPropInfo); var Loader: TJvPropsStorage; I: Integer; {$IFDEF WIN32} Cnt: Integer; Recreate: Boolean; {$ENDIF} Obj: TObject; procedure LoadObjectProps(Obj: TObject; const APrefix, ASection: string); var I: Integer; Props: TJvPropInfoList; begin with Loader do begin AObject := Obj; Prefix := APrefix; Section := ASection; FOnReadString := Self.FOnReadString; Props := TJvPropInfoList.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(GetOrdProp(Self.FObject, PropInfo)); if Obj <> nil then begin if Obj is TStrings then LoadStringsProperty(S, PropInfo) {$IFDEF WIN32} 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 {$ENDIF} 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 TJvPropsStorage.StoreProperties(PropList: TStrings); var I: Integer; Props: TJvPropInfoList; begin Props := TJvPropInfoList.Create(AObject, tkProperties); try for I := 0 to PropList.Count - 1 do StoreAnyProperty(Props.Find(PropList[I])); finally Props.Free; end; end; procedure TJvPropsStorage.LoadProperties(PropList: TStrings); var I: Integer; Props: TJvPropInfoList; begin Props := TJvPropInfoList.Create(AObject, tkProperties); try for I := 0 to PropList.Count - 1 do LoadAnyProperty(Props.Find(PropList[I])); finally Props.Free; end; end; function TJvPropsStorage.CreateInfoList(AComponent: TComponent; StoredList: TStrings): TStrings; var I: Integer; Obj: TComponent; Props: TJvPropInfoList; 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 := TJvPropInfoList.Create(Obj, tkProperties); try Result.AddObject(Obj.Name, Props); except Props.Free; raise; end; end; end; except Result.Free; Result := nil; end; end; procedure TJvPropsStorage.FreeInfoLists(Info: TStrings); var I: Integer; begin for I := Info.Count - 1 downto 0 do Info.Objects[I].Free; Info.Free; end; procedure TJvPropsStorage.LoadObjectsProps(AComponent: TComponent; StoredList: TStrings); var Info: TStrings; I, Idx: Integer; Props: TJvPropInfoList; 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 := TJvPropInfoList(Info.Objects[Idx]); if Props <> nil then LoadAnyProperty(Props.Find(PropName)); end; end; end; finally FOwner := nil; FreeInfoLists(Info); end; end; procedure TJvPropsStorage.StoreObjectsProps(AComponent: TComponent; StoredList: TStrings); var Info: TStrings; I, Idx: Integer; Props: TJvPropInfoList; 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 := TJvPropInfoList(Info.Objects[Idx]); if Props <> nil then StoreAnyProperty(Props.Find(PropName)); end; end; end; finally FOwner := nil; FreeInfoLists(Info); end; end; function TJvPropsStorage.CreateStorage: TJvPropsStorage; begin Result := TJvPropsStorage.Create; end; function TJvPropsStorage.ReadString(const ASection, Item, Default: string): string; begin if Assigned(FOnReadString) then Result := FOnReadString(ASection, Item, Default) else Result := ''; end; procedure TJvPropsStorage.WriteString(const ASection, Item, Value: string); begin if Assigned(FOnWriteString) then FOnWriteString(ASection, Item, Value); end; procedure TJvPropsStorage.EraseSection(const ASection: string); begin if Assigned(FOnEraseSection) then FOnEraseSection(ASection); end; end.