Rxprops.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:27k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1995, 1996 AO ROSNO             }
  6. {         Copyright (c) 1997 Master-Bank                }
  7. {                                                       }
  8. {*******************************************************}
  9. unit RXProps;
  10. interface
  11. {$I RX.INC}
  12. uses SysUtils, Classes, Graphics, Controls, Forms, TypInfo, VclUtils;
  13. type
  14. { TPropInfoList }
  15.   TPropInfoList = class(TObject)
  16.   private
  17.     FList: PPropList;
  18.     FCount: Integer;
  19.     FSize: Integer;
  20.     function Get(Index: Integer): PPropInfo;
  21.   public
  22.     constructor Create(AObject: TObject; Filter: TTypeKinds);
  23.     destructor Destroy; override;
  24.     function Contains(P: PPropInfo): Boolean;
  25.     function Find(const AName: string): PPropInfo;
  26.     procedure Delete(Index: Integer);
  27.     procedure Intersect(List: TPropInfoList);
  28.     property Count: Integer read FCount;
  29.     property Items[Index: Integer]: PPropInfo read Get; default;
  30.   end;
  31. { TPropsStorage }
  32.   TReadStrEvent = function(const ASection, Item, Default: string): string of object;
  33.   TWriteStrEvent = procedure(const ASection, Item, Value: string) of object;
  34.   TEraseSectEvent = procedure(const ASection: string) of object;
  35.   TPropsStorage = class(TObject)
  36.   private
  37.     FObject: TObject;
  38.     FOwner: TComponent;
  39.     FPrefix: string;
  40.     FSection: string;
  41.     FOnReadString: TReadStrEvent;
  42.     FOnWriteString: TWriteStrEvent;
  43.     FOnEraseSection: TEraseSectEvent;
  44.     function StoreIntegerProperty(PropInfo: PPropInfo): string;
  45.     function StoreCharProperty(PropInfo: PPropInfo): string;
  46.     function StoreEnumProperty(PropInfo: PPropInfo): string;
  47.     function StoreFloatProperty(PropInfo: PPropInfo): string;
  48.     function StoreStringProperty(PropInfo: PPropInfo): string;
  49.     function StoreSetProperty(PropInfo: PPropInfo): string;
  50.     function StoreClassProperty(PropInfo: PPropInfo): string;
  51.     function StoreStringsProperty(PropInfo: PPropInfo): string;
  52.     function StoreComponentProperty(PropInfo: PPropInfo): string;
  53. {$IFDEF WIN32}
  54.     function StoreLStringProperty(PropInfo: PPropInfo): string;
  55.     function StoreWCharProperty(PropInfo: PPropInfo): string;
  56.     function StoreVariantProperty(PropInfo: PPropInfo): string;
  57.     procedure LoadLStringProperty(const S: string; PropInfo: PPropInfo);
  58.     procedure LoadWCharProperty(const S: string; PropInfo: PPropInfo);
  59.     procedure LoadVariantProperty(const S: string; PropInfo: PPropInfo);
  60. {$ENDIF}
  61. {$IFDEF RX_D4}
  62.     function StoreInt64Property(PropInfo: PPropInfo): string;
  63.     procedure LoadInt64Property(const S: string; PropInfo: PPropInfo);
  64. {$ENDIF}
  65.     procedure LoadIntegerProperty(const S: string; PropInfo: PPropInfo);
  66.     procedure LoadCharProperty(const S: string; PropInfo: PPropInfo);
  67.     procedure LoadEnumProperty(const S: string; PropInfo: PPropInfo);
  68.     procedure LoadFloatProperty(const S: string; PropInfo: PPropInfo);
  69.     procedure LoadStringProperty(const S: string; PropInfo: PPropInfo);
  70.     procedure LoadSetProperty(const S: string; PropInfo: PPropInfo);
  71.     procedure LoadClassProperty(const S: string; PropInfo: PPropInfo);
  72.     procedure LoadStringsProperty(const S: string; PropInfo: PPropInfo);
  73.     procedure LoadComponentProperty(const S: string; PropInfo: PPropInfo);
  74.     function CreateInfoList(AComponent: TComponent; StoredList: TStrings): TStrings;
  75.     procedure FreeInfoLists(Info: TStrings);
  76.   protected
  77.     function ReadString(const ASection, Item, Default: string): string; virtual;
  78.     procedure WriteString(const ASection, Item, Value: string); virtual;
  79.     procedure EraseSection(const ASection: string); virtual;
  80.     function GetItemName(const APropName: string): string; virtual;
  81.     function CreateStorage: TPropsStorage; virtual;
  82.   public
  83.     procedure StoreAnyProperty(PropInfo: PPropInfo);
  84.     procedure LoadAnyProperty(PropInfo: PPropInfo);
  85.     procedure StoreProperties(PropList: TStrings);
  86.     procedure LoadProperties(PropList: TStrings);
  87.     procedure LoadObjectsProps(AComponent: TComponent; StoredList: TStrings);
  88.     procedure StoreObjectsProps(AComponent: TComponent; StoredList: TStrings);
  89.     property AObject: TObject read FObject write FObject;
  90.     property Prefix: string read FPrefix write FPrefix;
  91.     property Section: string read FSection write FSection;
  92.     property OnReadString: TReadStrEvent read FOnReadString write FOnReadString;
  93.     property OnWriteString: TWriteStrEvent read FOnWriteString write FOnWriteString;
  94.     property OnEraseSection: TEraseSectEvent read FOnEraseSection write FOnEraseSection;
  95.   end;
  96. { Utility routines }
  97. procedure UpdateStoredList(AComponent: TComponent; AStoredList: TStrings; FromForm: Boolean);
  98. function CreateStoredItem(const CompName, PropName: string): string;
  99. function ParseStoredItem(const Item: string; var CompName, PropName: string): Boolean;
  100. const
  101. {$IFDEF WIN32}
  102.   sPropNameDelimiter: string = '_';
  103. {$ELSE}
  104.   sPropNameDelimiter: Char = '_';
  105. {$ENDIF}
  106. implementation
  107. uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, Str16, {$ENDIF}
  108.   Consts, rxStrUtils;
  109. const
  110.   sCount = 'Count';
  111.   sItem = 'Item%d';
  112.   sNull = '(null)';
  113. type
  114.   TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
  115. {$IFNDEF WIN32}
  116. function GetEnumName(TypeInfo: PTypeInfo; Value: Integer): string;
  117. begin
  118.   Result := TypInfo.GetEnumName(TypeInfo, Value)^;
  119. end;
  120. {$ENDIF}
  121. function GetPropType(PropInfo: PPropInfo): PTypeInfo;
  122. begin
  123. {$IFDEF RX_D3}
  124.   Result := PropInfo^.PropType^;
  125. {$ELSE}
  126.   Result := PropInfo^.PropType;
  127. {$ENDIF}
  128. end;
  129. { TPropInfoList }
  130. constructor TPropInfoList.Create(AObject: TObject; Filter: TTypeKinds);
  131. begin
  132.   if AObject <> nil then begin
  133.     FCount := GetPropList(AObject.ClassInfo, Filter, nil);
  134.     FSize := FCount * SizeOf(Pointer);
  135.     GetMem(FList, FSize);
  136.     GetPropList(AObject.ClassInfo, Filter, FList);
  137.   end
  138.   else begin
  139.     FCount := 0;
  140.     FList := nil;
  141.   end;
  142. end;
  143. destructor TPropInfoList.Destroy;
  144. begin
  145.   if FList <> nil then FreeMem(FList, FSize);
  146. end;
  147. function TPropInfoList.Contains(P: PPropInfo): Boolean;
  148. var
  149.   I: Integer;
  150. begin
  151.   for I := 0 to FCount - 1 do
  152.     with FList^[I]^ do
  153.       if (PropType = P^.PropType) and (CompareText(Name, P^.Name) = 0) then
  154.       begin
  155.         Result := True;
  156.         Exit;
  157.       end;
  158.   Result := False;
  159. end;
  160. function TPropInfoList.Find(const AName: string): PPropInfo;
  161. var
  162.   I: Integer;
  163. begin
  164.   for I := 0 to FCount - 1 do
  165.     with FList^[I]^ do
  166.       if (CompareText(Name, AName) = 0) then
  167.       begin
  168.         Result := FList^[I];
  169.         Exit;
  170.       end;
  171.   Result := nil;
  172. end;
  173. procedure TPropInfoList.Delete(Index: Integer);
  174. begin
  175.   Dec(FCount);
  176.   if Index < FCount then Move(FList^[Index + 1], FList^[Index],
  177.     (FCount - Index) * SizeOf(Pointer));
  178. end;
  179. function TPropInfoList.Get(Index: Integer): PPropInfo;
  180. begin
  181.   Result := FList^[Index];
  182. end;
  183. procedure TPropInfoList.Intersect(List: TPropInfoList);
  184. var
  185.   I: Integer;
  186. begin
  187.   for I := FCount - 1 downto 0 do
  188.     if not List.Contains(FList^[I]) then Delete(I);
  189. end;
  190. { Utility routines }
  191. function CreateStoredItem(const CompName, PropName: string): string;
  192. begin
  193.   Result := '';
  194.   if (CompName <> '') and (PropName <> '') then
  195.     Result := CompName + '.' + PropName;
  196. end;
  197. function ParseStoredItem(const Item: string; var CompName, PropName: string): Boolean;
  198. var
  199.   I: Integer;
  200. begin
  201.   Result := False;
  202.   if Length(Item) = 0 then Exit;
  203.   I := Pos('.', Item);
  204.   if I > 0 then begin
  205.     CompName := Trim(Copy(Item, 1, I - 1));
  206.     PropName := Trim(Copy(Item, I + 1, MaxInt));
  207.     Result := (Length(CompName) > 0) and (Length(PropName) > 0);
  208.   end;
  209. end;
  210. function ReplaceComponentName(const Item, CompName: string): string;
  211. var
  212.   ACompName, APropName: string;
  213. begin
  214.   Result := '';
  215.   if ParseStoredItem(Item, ACompName, APropName) then
  216.     Result := CreateStoredItem(CompName, APropName);
  217. end;
  218. procedure UpdateStoredList(AComponent: TComponent; AStoredList: TStrings; FromForm: Boolean);
  219. var
  220.   I: Integer;
  221.   Component: TComponent;
  222.   CompName, PropName: string;
  223. begin
  224.   if (AStoredList = nil) or (AComponent = nil) then Exit;
  225.   for I := AStoredList.Count - 1 downto 0 do begin
  226.     if ParseStoredItem(AStoredList[I], CompName, PropName) then
  227.     begin
  228.       if FromForm then begin
  229.         Component := AComponent.FindComponent(CompName);
  230.         if Component = nil then AStoredList.Delete(I)
  231.         else AStoredList.Objects[I] := Component;
  232.       end
  233.       else begin
  234.         Component := TComponent(AStoredList.Objects[I]);
  235.         if Component <> nil then
  236.           AStoredList[I] := ReplaceComponentName(AStoredList[I], Component.Name)
  237.         else AStoredList.Delete(I);
  238.       end;
  239.     end
  240.     else AStoredList.Delete(I);
  241.   end;
  242. end;
  243. {$IFDEF WIN32}
  244. function FindGlobalComponent(const Name: string): TComponent;
  245. var
  246.   I: Integer;
  247. begin
  248.   for I := 0 to Screen.FormCount - 1 do begin
  249.     Result := Screen.Forms[I];
  250.     if CompareText(Name, Result.Name) = 0 then Exit;
  251.   end;
  252.   for I := 0 to Screen.DataModuleCount - 1 do begin
  253.     Result := Screen.DataModules[I];
  254.     if CompareText(Name, Result.Name) = 0 then Exit;
  255.   end;
  256.   Result := nil;
  257. end;
  258. {$ENDIF}
  259. { TPropsStorage }
  260. function TPropsStorage.GetItemName(const APropName: string): string;
  261. begin
  262.   Result := Prefix + APropName;
  263. end;
  264. procedure TPropsStorage.LoadAnyProperty(PropInfo: PPropInfo);
  265. var
  266.   S, Def: string;
  267. begin
  268.   try
  269.     if PropInfo <> nil then begin
  270.       case PropInfo^.PropType^.Kind of
  271.         tkInteger: Def := StoreIntegerProperty(PropInfo);
  272.         tkChar: Def := StoreCharProperty(PropInfo);
  273.         tkEnumeration: Def := StoreEnumProperty(PropInfo);
  274.         tkFloat: Def := StoreFloatProperty(PropInfo);
  275. {$IFDEF WIN32}
  276.         tkWChar: Def := StoreWCharProperty(PropInfo);
  277.         tkLString: Def := StoreLStringProperty(PropInfo);
  278.   {$IFNDEF RX_D3} { - Delphi 2.0, C++Builder 1.0 }
  279.         tkLWString: Def := StoreLStringProperty(PropInfo);
  280.   {$ENDIF}
  281.         tkVariant: Def := StoreVariantProperty(PropInfo);
  282. {$ENDIF WIN32}
  283. {$IFDEF RX_D4}
  284.         tkInt64: Def := StoreInt64Property(PropInfo);
  285. {$ENDIF}
  286.         tkString: Def := StoreStringProperty(PropInfo);
  287.         tkSet: Def := StoreSetProperty(PropInfo);
  288.         tkClass: Def := '';
  289.         else Exit;
  290.       end;
  291.       if (Def <> '') or (PropInfo^.PropType^.Kind in [tkString, tkClass])
  292. {$IFDEF WIN32}
  293.         or (PropInfo^.PropType^.Kind in [tkLString,
  294.           {$IFNDEF RX_D3} tkLWString, {$ENDIF} tkWChar])
  295. {$ENDIF WIN32}
  296.       then
  297.         S := Trim(ReadString(Section, GetItemName(PropInfo^.Name), Def))
  298.       else S := '';
  299.       case PropInfo^.PropType^.Kind of
  300.         tkInteger: LoadIntegerProperty(S, PropInfo);
  301.         tkChar: LoadCharProperty(S, PropInfo);
  302.         tkEnumeration: LoadEnumProperty(S, PropInfo);
  303.         tkFloat: LoadFloatProperty(S, PropInfo);
  304. {$IFDEF WIN32}
  305.         tkWChar: LoadWCharProperty(S, PropInfo);
  306.         tkLString: LoadLStringProperty(S, PropInfo);
  307.   {$IFNDEF RX_D3} { - Delphi 2.0, C++Builder 1.0 }
  308.         tkLWString: LoadLStringProperty(S, PropInfo);
  309.   {$ENDIF}
  310.         tkVariant: LoadVariantProperty(S, PropInfo);
  311. {$ENDIF WIN32}
  312. {$IFDEF RX_D4}
  313.         tkInt64: LoadInt64Property(S, PropInfo);
  314. {$ENDIF}
  315.         tkString: LoadStringProperty(S, PropInfo);
  316.         tkSet: LoadSetProperty(S, PropInfo);
  317.         tkClass: LoadClassProperty(S, PropInfo);
  318.       end;
  319.     end;
  320.   except
  321.     { ignore any exception }
  322.   end;
  323. end;
  324. procedure TPropsStorage.StoreAnyProperty(PropInfo: PPropInfo);
  325. var
  326.   S: string;
  327. begin
  328.   if PropInfo <> nil then begin
  329.     case PropInfo^.PropType^.Kind of
  330.       tkInteger: S := StoreIntegerProperty(PropInfo);
  331.       tkChar: S := StoreCharProperty(PropInfo);
  332.       tkEnumeration: S := StoreEnumProperty(PropInfo);
  333.       tkFloat: S := StoreFloatProperty(PropInfo);
  334. {$IFDEF WIN32}
  335.       tkLString: S := StoreLStringProperty(PropInfo);
  336.   {$IFNDEF RX_D3} { - Delphi 2.0, C++Builder 1.0 }
  337.       tkLWString: S := StoreLStringProperty(PropInfo);
  338.   {$ENDIF}
  339.       tkWChar: S := StoreWCharProperty(PropInfo);
  340.       tkVariant: S := StoreVariantProperty(PropInfo);
  341. {$ENDIF WIN32}
  342. {$IFDEF RX_D4}
  343.       tkInt64: S := StoreInt64Property(PropInfo);
  344. {$ENDIF}
  345.       tkString: S := StoreStringProperty(PropInfo);
  346.       tkSet: S := StoreSetProperty(PropInfo);
  347.       tkClass: S := StoreClassProperty(PropInfo);
  348.       else Exit;
  349.     end;
  350.     if (S <> '') or (PropInfo^.PropType^.Kind in [tkString
  351.       {$IFDEF WIN32}, tkLString, {$IFNDEF RX_D3} tkLWString, {$ENDIF}
  352.       tkWChar {$ENDIF WIN32}]) then
  353.       WriteString(Section, GetItemName(PropInfo^.Name), Trim(S));
  354.   end;
  355. end;
  356. function TPropsStorage.StoreIntegerProperty(PropInfo: PPropInfo): string;
  357. begin
  358.   Result := IntToStr(GetOrdProp(FObject, PropInfo));
  359. end;
  360. function TPropsStorage.StoreCharProperty(PropInfo: PPropInfo): string;
  361. begin
  362.   Result := Char(GetOrdProp(FObject, PropInfo));
  363. end;
  364. function TPropsStorage.StoreEnumProperty(PropInfo: PPropInfo): string;
  365. begin
  366.   Result := GetEnumName(GetPropType(PropInfo), GetOrdProp(FObject, PropInfo));
  367. end;
  368. function TPropsStorage.StoreFloatProperty(PropInfo: PPropInfo): string;
  369. const
  370. {$IFDEF WIN32}
  371.   Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
  372. {$ELSE}
  373.   Precisions: array[TFloatType] of Integer = (7, 15, 18, 18);
  374. {$ENDIF}
  375. begin
  376.   Result := ReplaceStr(FloatToStrF(GetFloatProp(FObject, PropInfo), ffGeneral,
  377.     Precisions[GetTypeData(GetPropType(PropInfo))^.FloatType], 0), 
  378.     DecimalSeparator, '.');
  379. end;
  380. function TPropsStorage.StoreStringProperty(PropInfo: PPropInfo): string;
  381. begin
  382.   Result := GetStrProp(FObject, PropInfo);
  383. end;
  384. {$IFDEF WIN32}
  385. function TPropsStorage.StoreLStringProperty(PropInfo: PPropInfo): string;
  386. begin
  387.   Result := GetStrProp(FObject, PropInfo);
  388. end;
  389. function TPropsStorage.StoreWCharProperty(PropInfo: PPropInfo): string;
  390. begin
  391.   Result := Char(GetOrdProp(FObject, PropInfo));
  392. end;
  393. function TPropsStorage.StoreVariantProperty(PropInfo: PPropInfo): string;
  394. begin
  395.   Result := GetVariantProp(FObject, PropInfo);
  396. end;
  397. {$ENDIF}
  398. {$IFDEF RX_D4}
  399. function TPropsStorage.StoreInt64Property(PropInfo: PPropInfo): string;
  400. begin
  401.   Result := IntToStr(GetInt64Prop(FObject, PropInfo));
  402. end;
  403. {$ENDIF}
  404. function TPropsStorage.StoreSetProperty(PropInfo: PPropInfo): string;
  405. var
  406.   TypeInfo: PTypeInfo;
  407.   W: Cardinal;
  408.   I: Integer;
  409. begin
  410.   Result := '[';
  411.   W := GetOrdProp(FObject, PropInfo);
  412.   TypeInfo := GetTypeData(GetPropType(PropInfo))^.CompType{$IFDEF RX_D3}^{$ENDIF};
  413.   for I := 0 to SizeOf(TCardinalSet) * 8 - 1 do
  414.     if I in TCardinalSet(W) then begin
  415.       if Length(Result) <> 1 then Result := Result + ',';
  416.       Result := Result + GetEnumName(TypeInfo, I);
  417.     end;
  418.   Result := Result + ']';
  419. end;
  420. function TPropsStorage.StoreStringsProperty(PropInfo: PPropInfo): string;
  421. var
  422.   List: TObject;
  423.   I: Integer;
  424.   SectName: string;
  425. begin
  426.   Result := '';
  427.   List := TObject(GetOrdProp(Self.FObject, PropInfo));
  428.   SectName := Format('%s.%s', [Section, GetItemName(PropInfo^.Name)]);
  429.   EraseSection(SectName);
  430.   if (List is TStrings) and (TStrings(List).Count > 0) then begin
  431.     WriteString(SectName, sCount, IntToStr(TStrings(List).Count));
  432.     for I := 0 to TStrings(List).Count - 1 do
  433.       WriteString(SectName, Format(sItem, [I]), TStrings(List)[I]);
  434.   end;
  435. end;
  436. function TPropsStorage.StoreComponentProperty(PropInfo: PPropInfo): string;
  437. var
  438.   Comp: TComponent;
  439.   RootName: string;
  440. begin
  441.   Comp := TComponent(GetOrdProp(FObject, PropInfo));
  442.   if Comp <> nil then begin
  443.     Result := Comp.Name;
  444.     if (Comp.Owner <> nil) and (Comp.Owner <> FOwner) then begin
  445.       RootName := Comp.Owner.Name;
  446.       if RootName = '' then begin
  447.         RootName := Comp.Owner.ClassName;
  448.         if (RootName <> '') and (UpCase(RootName[1]) = 'T') then
  449.           Delete(RootName, 1, 1);
  450.       end;
  451.       Result := Format('%s.%s', [RootName, Result]);
  452.     end;
  453.   end
  454.   else Result := sNull;
  455. end;
  456. function TPropsStorage.StoreClassProperty(PropInfo: PPropInfo): string;
  457. var
  458.   Saver: TPropsStorage;
  459.   I: Integer;
  460.   Obj: TObject;
  461.   procedure StoreObjectProps(Obj: TObject; const APrefix, ASection: string);
  462.   var
  463.     I: Integer;
  464.     Props: TPropInfoList;
  465.   begin
  466.     with Saver do begin
  467.       AObject := Obj;
  468.       Prefix := APrefix;
  469.       Section := ASection;
  470.       FOnWriteString := Self.FOnWriteString;
  471.       FOnEraseSection := Self.FOnEraseSection;
  472.       Props := TPropInfoList.Create(AObject, tkProperties);
  473.       try
  474.         for I := 0 to Props.Count - 1 do StoreAnyProperty(Props.Items[I]);
  475.       finally
  476.         Props.Free;
  477.       end;
  478.     end;
  479.   end;
  480. begin
  481.   Result := '';
  482.   Obj := TObject(GetOrdProp(Self.FObject, PropInfo));
  483.   if (Obj <> nil) then begin
  484.     if Obj is TStrings then StoreStringsProperty(PropInfo)
  485. {$IFDEF WIN32}
  486.     else if Obj is TCollection then begin
  487.       EraseSection(Format('%s.%s', [Section, Prefix + PropInfo^.Name]));
  488.       Saver := CreateStorage;
  489.       try
  490.         WriteString(Section, Format('%s.%s', [Prefix + PropInfo^.Name, sCount]),
  491.           IntToStr(TCollection(Obj).Count));
  492.         for I := 0 to TCollection(Obj).Count - 1 do begin
  493.           StoreObjectProps(TCollection(Obj).Items[I],
  494.             Format(sItem, [I]) + sPropNameDelimiter,
  495.             Format('%s.%s', [Section, Prefix + PropInfo^.Name]));
  496.         end;
  497.       finally
  498.         Saver.Free;
  499.       end;
  500.     end
  501. {$ENDIF}
  502.     else if Obj is TComponent then begin
  503.       Result := StoreComponentProperty(PropInfo);
  504.       Exit;
  505.     end;
  506.   end;
  507.   Saver := CreateStorage;
  508.   try
  509.     with Saver do begin
  510.       StoreObjectProps(Obj, Self.Prefix + PropInfo^.Name, Self.Section);
  511.     end;
  512.   finally
  513.     Saver.Free;
  514.   end;
  515. end;
  516. procedure TPropsStorage.LoadIntegerProperty(const S: string; PropInfo: PPropInfo);
  517. begin
  518.   SetOrdProp(FObject, PropInfo, StrToIntDef(S, 0));
  519. end;
  520. procedure TPropsStorage.LoadCharProperty(const S: string; PropInfo: PPropInfo);
  521. begin
  522.   SetOrdProp(FObject, PropInfo, Integer(S[1]));
  523. end;
  524. procedure TPropsStorage.LoadEnumProperty(const S: string; PropInfo: PPropInfo);
  525. var
  526.   I: Integer;
  527.   EnumType: PTypeInfo;
  528. begin
  529.   EnumType := GetPropType(PropInfo);
  530.   with GetTypeData(EnumType)^ do
  531.     for I := MinValue to MaxValue do
  532.       if CompareText(GetEnumName(EnumType, I), S) = 0 then
  533.       begin
  534.         SetOrdProp(FObject, PropInfo, I);
  535.         Exit;
  536.       end;
  537. end;
  538. procedure TPropsStorage.LoadFloatProperty(const S: string; PropInfo: PPropInfo);
  539. begin
  540.   SetFloatProp(FObject, PropInfo, StrToFloat(ReplaceStr(S, '.',
  541.     DecimalSeparator)));
  542. end;
  543. {$IFDEF RX_D4}
  544. procedure TPropsStorage.LoadInt64Property(const S: string; PropInfo: PPropInfo);
  545. begin
  546.   SetInt64Prop(FObject, PropInfo, StrToInt64Def(S, 0));
  547. end;
  548. {$ENDIF}
  549. {$IFDEF WIN32}
  550. procedure TPropsStorage.LoadLStringProperty(const S: string; PropInfo: PPropInfo);
  551. begin
  552.   SetStrProp(FObject, PropInfo, S);
  553. end;
  554. procedure TPropsStorage.LoadWCharProperty(const S: string; PropInfo: PPropInfo);
  555. begin
  556.   SetOrdProp(FObject, PropInfo, Longint(S[1]));
  557. end;
  558. procedure TPropsStorage.LoadVariantProperty(const S: string; PropInfo: PPropInfo);
  559. begin
  560.   SetVariantProp(FObject, PropInfo, S);
  561. end;
  562. {$ENDIF}
  563. procedure TPropsStorage.LoadStringProperty(const S: string; PropInfo: PPropInfo);
  564. begin
  565.   SetStrProp(FObject, PropInfo, S);
  566. end;
  567. procedure TPropsStorage.LoadSetProperty(const S: string; PropInfo: PPropInfo);
  568. const
  569.   Delims = [' ', ',', '[', ']'];
  570. var
  571.   TypeInfo: PTypeInfo;
  572.   W: Cardinal;
  573.   I, N: Integer;
  574.   Count: Integer;
  575.   EnumName: string;
  576. begin
  577.   W := 0;
  578.   TypeInfo := GetTypeData(GetPropType(PropInfo))^.CompType{$IFDEF RX_D3}^{$ENDIF};
  579.   Count := WordCount(S, Delims);
  580.   for N := 1 to Count do begin
  581.     EnumName := ExtractWord(N, S, Delims);
  582.     try
  583.       I := GetEnumValue(TypeInfo, EnumName);
  584.       if I >= 0 then Include(TCardinalSet(W), I);
  585.     except
  586.     end;
  587.   end;
  588.   SetOrdProp(FObject, PropInfo, W);
  589. end;
  590. procedure TPropsStorage.LoadStringsProperty(const S: string; PropInfo: PPropInfo);
  591. var
  592.   List: TObject;
  593.   Temp: TStrings;
  594.   I, Cnt: Integer;
  595.   SectName: string;
  596. begin
  597.   List := TObject(GetOrdProp(Self.FObject, PropInfo));
  598.   if (List is TStrings) then begin
  599.     SectName := Format('%s.%s', [Section, GetItemName(PropInfo^.Name)]);
  600.     Cnt := StrToIntDef(Trim(ReadString(SectName, sCount, '0')), 0);
  601.     if Cnt > 0 then begin
  602.       Temp := TStringList.Create;
  603.       try
  604.         for I := 0 to Cnt - 1 do
  605.           Temp.Add(ReadString(SectName, Format(sItem, [I]), ''));
  606.         TStrings(List).Assign(Temp);
  607.       finally
  608.         Temp.Free;
  609.       end;
  610.     end;
  611.   end;
  612. end;
  613. procedure TPropsStorage.LoadComponentProperty(const S: string; PropInfo: PPropInfo);
  614. {$IFDEF WIN32}
  615. var
  616.   RootName, Name: string;
  617.   Root: TComponent;
  618.   P: Integer;
  619. begin
  620.   if Trim(S) = '' then Exit;
  621.   if CompareText(SNull, Trim(S)) = 0 then begin
  622.     SetOrdProp(FObject, PropInfo, Longint(nil));
  623.     Exit;
  624.   end;
  625.   P := Pos('.', S);
  626.   if P > 0 then begin
  627.     RootName := Trim(Copy(S, 1, P - 1));
  628.     Name := Trim(Copy(S, P + 1, MaxInt));
  629.   end
  630.   else begin
  631.     RootName := '';
  632.     Name := Trim(S);
  633.   end;
  634.   if RootName <> '' then Root := FindGlobalComponent(RootName)
  635.   else Root := FOwner;
  636.   if (Root <> nil) then
  637.     SetOrdProp(FObject, PropInfo, Longint(Root.FindComponent(Name)));
  638. end;
  639. {$ELSE}
  640. begin
  641.   if Trim(S) = '' then Exit;
  642.   if CompareText(SNull, Trim(S)) = 0 then begin
  643.     SetOrdProp(FObject, PropInfo, Longint(nil));
  644.     Exit;
  645.   end;
  646.   if (FOwner <> nil) then
  647.     SetOrdProp(FObject, PropInfo, Longint(FOwner.FindComponent(Trim(S))));
  648. end;
  649. {$ENDIF}
  650. procedure TPropsStorage.LoadClassProperty(const S: string; PropInfo: PPropInfo);
  651. var
  652.   Loader: TPropsStorage;
  653.   I: Integer;
  654. {$IFDEF WIN32}
  655.   Cnt: Integer;
  656.   Recreate: Boolean;
  657. {$ENDIF}
  658.   Obj: TObject;
  659.   procedure LoadObjectProps(Obj: TObject; const APrefix, ASection: string);
  660.   var
  661.     I: Integer;
  662.     Props: TPropInfoList;
  663.   begin
  664.     with Loader do begin
  665.       AObject := Obj;
  666.       Prefix := APrefix;
  667.       Section := ASection;
  668.       FOnReadString := Self.FOnReadString;
  669.       Props := TPropInfoList.Create(AObject, tkProperties);
  670.       try
  671.         for I := 0 to Props.Count - 1 do LoadAnyProperty(Props.Items[I]);
  672.       finally
  673.         Props.Free;
  674.       end;
  675.     end;
  676.   end;
  677. begin
  678.   Obj := TObject(GetOrdProp(Self.FObject, PropInfo));
  679.   if (Obj <> nil) then begin
  680.     if Obj is TStrings then LoadStringsProperty(S, PropInfo)
  681. {$IFDEF WIN32}
  682.     else if Obj is TCollection then begin
  683.       Loader := CreateStorage;
  684.       try
  685.         Cnt := TCollection(Obj).Count;
  686.         Cnt := StrToIntDef(ReadString(Section, Format('%s.%s',
  687.           [Prefix + PropInfo^.Name, sCount]), IntToStr(Cnt)), Cnt);
  688.         Recreate := TCollection(Obj).Count <> Cnt;
  689.         TCollection(Obj).BeginUpdate;
  690.         try
  691.           if Recreate then TCollection(Obj).Clear;
  692.           for I := 0 to Cnt - 1 do begin
  693.             if Recreate then TCollection(Obj).Add;
  694.             LoadObjectProps(TCollection(Obj).Items[I],
  695.               Format(sItem, [I]) + sPropNameDelimiter,
  696.               Format('%s.%s', [Section, Prefix + PropInfo^.Name]));
  697.           end;
  698.         finally
  699.           TCollection(Obj).EndUpdate;
  700.         end;
  701.       finally
  702.         Loader.Free;
  703.       end;
  704.     end
  705. {$ENDIF}
  706.     else if Obj is TComponent then begin
  707.       LoadComponentProperty(S, PropInfo);
  708.       Exit;
  709.     end;
  710.   end;
  711.   Loader := CreateStorage;
  712.   try
  713.     LoadObjectProps(Obj, Self.Prefix + PropInfo^.Name, Self.Section);
  714.   finally
  715.     Loader.Free;
  716.   end;
  717. end;
  718. procedure TPropsStorage.StoreProperties(PropList: TStrings);
  719. var
  720.   I: Integer;
  721.   Props: TPropInfoList;
  722. begin
  723.   Props := TPropInfoList.Create(AObject, tkProperties);
  724.   try
  725.     for I := 0 to PropList.Count - 1 do
  726.       StoreAnyProperty(Props.Find(PropList[I]));
  727.   finally
  728.     Props.Free;
  729.   end;
  730. end;
  731. procedure TPropsStorage.LoadProperties(PropList: TStrings);
  732. var
  733.   I: Integer;
  734.   Props: TPropInfoList;
  735. begin
  736.   Props := TPropInfoList.Create(AObject, tkProperties);
  737.   try
  738.     for I := 0 to PropList.Count - 1 do
  739.       LoadAnyProperty(Props.Find(PropList[I]));
  740.   finally
  741.     Props.Free;
  742.   end;
  743. end;
  744. function TPropsStorage.CreateInfoList(AComponent: TComponent; StoredList: TStrings): TStrings;
  745. var
  746.   I: Integer;
  747.   Obj: TComponent;
  748.   Props: TPropInfoList;
  749. begin
  750.   UpdateStoredList(AComponent, StoredList, False);
  751.   Result := TStringList.Create;
  752.   try
  753.     TStringList(Result).Sorted := True;
  754.     for I := 0 to StoredList.Count - 1 do begin
  755.       Obj := TComponent(StoredList.Objects[I]);
  756.       if Result.IndexOf(Obj.Name) < 0 then begin
  757.         Props := TPropInfoList.Create(Obj, tkProperties);
  758.         try
  759.           Result.AddObject(Obj.Name, Props);
  760.         except
  761.           Props.Free;
  762.           raise;
  763.         end;
  764.       end;
  765.     end;
  766.   except
  767.     Result.Free;
  768.     Result := nil;
  769.   end;
  770. end;
  771. procedure TPropsStorage.FreeInfoLists(Info: TStrings);
  772. var
  773.   I: Integer;
  774. begin
  775.   for I := Info.Count - 1 downto 0 do Info.Objects[I].Free;
  776.   Info.Free;
  777. end;
  778. procedure TPropsStorage.LoadObjectsProps(AComponent: TComponent; StoredList: TStrings);
  779. var
  780.   Info: TStrings;
  781.   I, Idx: Integer;
  782.   Props: TPropInfoList;
  783.   CompName, PropName: string;
  784. begin
  785.   Info := CreateInfoList(AComponent, StoredList);
  786.   if Info <> nil then
  787.   try
  788.     FOwner := AComponent;
  789.     for I := 0 to StoredList.Count - 1 do begin
  790.       if ParseStoredItem(StoredList[I], CompName, PropName) then begin
  791.         AObject := StoredList.Objects[I];
  792.         Prefix := TComponent(AObject).Name;
  793.         Idx := Info.IndexOf(Prefix);
  794.         if Idx >= 0 then begin
  795.           Prefix := Prefix + sPropNameDelimiter;
  796.           Props := TPropInfoList(Info.Objects[Idx]);
  797.           if Props <> nil then LoadAnyProperty(Props.Find(PropName));
  798.         end;
  799.       end;
  800.     end;
  801.   finally
  802.     FOwner := nil;
  803.     FreeInfoLists(Info);
  804.   end;
  805. end;
  806. procedure TPropsStorage.StoreObjectsProps(AComponent: TComponent; StoredList: TStrings);
  807. var
  808.   Info: TStrings;
  809.   I, Idx: Integer;
  810.   Props: TPropInfoList;
  811.   CompName, PropName: string;
  812. begin
  813.   Info := CreateInfoList(AComponent, StoredList);
  814.   if Info <> nil then
  815.   try
  816.     FOwner := AComponent;
  817.     for I := 0 to StoredList.Count - 1 do begin
  818.       if ParseStoredItem(StoredList[I], CompName, PropName) then begin
  819.         AObject := StoredList.Objects[I];
  820.         Prefix := TComponent(AObject).Name;
  821.         Idx := Info.IndexOf(Prefix);
  822.         if Idx >= 0 then begin
  823.           Prefix := Prefix + sPropNameDelimiter;
  824.           Props := TPropInfoList(Info.Objects[Idx]);
  825.           if Props <> nil then StoreAnyProperty(Props.Find(PropName));
  826.         end;
  827.       end;
  828.     end;
  829.   finally
  830.     FOwner := nil;
  831.     FreeInfoLists(Info);
  832.   end;
  833. end;
  834. function TPropsStorage.CreateStorage: TPropsStorage;
  835. begin
  836.   Result := TPropsStorage.Create;
  837. end;
  838. function TPropsStorage.ReadString(const ASection, Item, Default: string): string;
  839. begin
  840.   if Assigned(FOnReadString) then Result := FOnReadString(ASection, Item, Default)
  841.   else Result := '';
  842. end;
  843. procedure TPropsStorage.WriteString(const ASection, Item, Value: string);
  844. begin
  845.   if Assigned(FOnWriteString) then FOnWriteString(ASection, Item, Value);
  846. end;
  847. procedure TPropsStorage.EraseSection(const ASection: string);
  848. begin
  849.   if Assigned(FOnEraseSection) then FOnEraseSection(ASection);
  850. end;
  851. end.