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

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 Placemnt;
  10. {$I RX.INC}
  11. interface
  12. uses RTLConsts, Windows, Registry, Variants, Controls, Messages, Classes, Forms, IniFiles, Dialogs, VclUtils, RxHook;
  13. type
  14.   TPlacementOption = (fpState, fpPosition, fpActiveControl);
  15.   TPlacementOptions = set of TPlacementOption;
  16.   TPlacementOperation = (poSave, poRestore);
  17. {$IFDEF WIN32}
  18.   TPlacementRegRoot = (prCurrentUser, prLocalMachine, prCurrentConfig,
  19.     prClassesRoot, prUsers, prDynData);
  20. {$ENDIF}
  21.   TIniLink = class;
  22. { TWinMinMaxInfo }
  23.   TFormPlacement = class;
  24.   TWinMinMaxInfo = class(TPersistent)
  25.   private
  26.     FOwner: TFormPlacement;
  27.     FMinMaxInfo: TMinMaxInfo;
  28.     function GetMinMaxInfo(Index: Integer): Integer;
  29.     procedure SetMinMaxInfo(Index: Integer; Value: Integer);
  30.   public
  31.     function DefaultMinMaxInfo: Boolean;
  32.     procedure Assign(Source: TPersistent); override;
  33.   published
  34.     property MaxPosLeft: Integer index 0 read GetMinMaxInfo write SetMinMaxInfo default 0;
  35.     property MaxPosTop: Integer index 1 read GetMinMaxInfo write SetMinMaxInfo default 0;
  36.     property MaxSizeHeight: Integer index 2 read GetMinMaxInfo write SetMinMaxInfo default 0;
  37.     property MaxSizeWidth: Integer index 3 read GetMinMaxInfo write SetMinMaxInfo default 0;
  38.     property MaxTrackHeight: Integer index 4 read GetMinMaxInfo write SetMinMaxInfo default 0;
  39.     property MaxTrackWidth: Integer index 5 read GetMinMaxInfo write SetMinMaxInfo default 0;
  40.     property MinTrackHeight: Integer index 6 read GetMinMaxInfo write SetMinMaxInfo default 0;
  41.     property MinTrackWidth: Integer index 7 read GetMinMaxInfo write SetMinMaxInfo default 0;
  42.   end;
  43. { TFormPlacement }
  44.   TFormPlacement = class(TComponent)
  45.   private
  46.     FActive: Boolean;
  47.     FIniFileName: PString;
  48.     FIniSection: PString;
  49.     FIniFile: TIniFile;
  50.     FUseRegistry: Boolean;
  51. {$IFDEF WIN32}
  52.     FRegIniFile: TRegIniFile;
  53.     FRegistryRoot: TPlacementRegRoot;
  54. {$ENDIF WIN32}
  55.     FLinks: TList;
  56.     FOptions: TPlacementOptions;
  57.     FVersion: Integer;
  58.     FSaved: Boolean;
  59.     FRestored: Boolean;
  60.     FDestroying: Boolean;
  61.     FPreventResize: Boolean;
  62.     FWinMinMaxInfo: TWinMinMaxInfo;
  63.     FDefMaximize: Boolean;
  64.     FWinHook: TRxWindowHook;
  65.     FSaveFormShow: TNotifyEvent;
  66.     FSaveFormDestroy: TNotifyEvent;
  67.     FSaveFormCloseQuery: TCloseQueryEvent;
  68.     FOnSavePlacement: TNotifyEvent;
  69.     FOnRestorePlacement: TNotifyEvent;
  70.     procedure SetEvents;
  71.     procedure RestoreEvents;
  72.     procedure SetHook;
  73.     procedure ReleaseHook;
  74.     procedure CheckToggleHook;
  75.     function CheckMinMaxInfo: Boolean;
  76.     procedure MinMaxInfoModified;
  77.     procedure SetWinMinMaxInfo(Value: TWinMinMaxInfo);
  78.     function GetIniSection: string;
  79.     procedure SetIniSection(const Value: string);
  80.     function GetIniFileName: string;
  81.     procedure SetIniFileName(const Value: string);
  82.     function GetIniFile: TObject;
  83.     procedure SetPreventResize(Value: Boolean);
  84.     procedure UpdatePreventResize;
  85.     procedure UpdatePlacement;
  86.     procedure IniNeeded(ReadOnly: Boolean);
  87.     procedure IniFree;
  88.     procedure AddLink(ALink: TIniLink);
  89.     procedure NotifyLinks(Operation: TPlacementOperation);
  90.     procedure RemoveLink(ALink: TIniLink);
  91.     procedure WndMessage(Sender: TObject; var Msg: TMessage; var Handled: Boolean);
  92.     procedure FormShow(Sender: TObject);
  93.     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  94.     procedure FormDestroy(Sender: TObject);
  95.     function GetForm: TForm;
  96.   protected
  97.     procedure Loaded; override;
  98.     procedure Save; dynamic;
  99.     procedure Restore; dynamic;
  100.     procedure SavePlacement; virtual;
  101.     procedure RestorePlacement; virtual;
  102.     function DoReadString(const Section, Ident, Default: string): string; virtual;
  103.     procedure DoWriteString(const Section, Ident, Value: string); virtual;
  104.     property Form: TForm read GetForm;
  105.   public
  106.     constructor Create(AOwner: TComponent); override;
  107.     destructor Destroy; override;
  108.     procedure SaveFormPlacement;
  109.     procedure RestoreFormPlacement;
  110.     function ReadString(const Ident, Default: string): string;
  111.     procedure WriteString(const Ident, Value: string);
  112.     function ReadInteger(const Ident: string; Default: Longint): Longint;
  113.     procedure WriteInteger(const Ident: string; Value: Longint);
  114.     procedure EraseSections;
  115.     property IniFileObject: TObject read GetIniFile;
  116.     property IniFile: TIniFile read FIniFile;
  117. {$IFDEF WIN32}
  118.     property RegIniFile: TRegIniFile read FRegIniFile;
  119. {$ENDIF WIN32}
  120.   published
  121.     property Active: Boolean read FActive write FActive default True;
  122.     property IniFileName: string read GetIniFileName write SetIniFileName;
  123.     property IniSection: string read GetIniSection write SetIniSection;
  124.     property MinMaxInfo: TWinMinMaxInfo read FWinMinMaxInfo write SetWinMinMaxInfo;
  125.     property Options: TPlacementOptions read FOptions write FOptions default [fpState, fpPosition];
  126.     property PreventResize: Boolean read FPreventResize write SetPreventResize default False;
  127. {$IFDEF WIN32}
  128.     property RegistryRoot: TPlacementRegRoot read FRegistryRoot write FRegistryRoot default prCurrentUser;
  129. {$ENDIF WIN32}
  130.     property UseRegistry: Boolean read FUseRegistry write FUseRegistry default False;
  131.     property Version: Integer read FVersion write FVersion default 0;
  132.     property OnSavePlacement: TNotifyEvent read FOnSavePlacement
  133.       write FOnSavePlacement;
  134.     property OnRestorePlacement: TNotifyEvent read FOnRestorePlacement
  135.       write FOnRestorePlacement;
  136.   end;
  137. { TFormStorage }
  138. {$IFDEF RX_D3}
  139.   TStoredValues = class;
  140.   TStoredValue = class;
  141. {$ENDIF RX_D3}
  142.   TFormStorage = class(TFormPlacement)
  143.   private
  144.     FStoredProps: TStrings;
  145. {$IFDEF RX_D3}
  146.     FStoredValues: TStoredValues;
  147. {$ENDIF RX_D3}
  148.     procedure SetStoredProps(Value: TStrings);
  149. {$IFDEF RX_D3}
  150.     procedure SetStoredValues(Value: TStoredValues);
  151. {$ENDIF RX_D3}
  152.   protected
  153.     procedure Loaded; override;
  154.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  155.     procedure SavePlacement; override;
  156.     procedure RestorePlacement; override;
  157.     procedure SaveProperties; virtual;
  158.     procedure RestoreProperties; virtual;
  159.     procedure WriteState(Writer: TWriter); override;
  160.   public
  161.     constructor Create(AOwner: TComponent); override;
  162.     destructor Destroy; override;
  163. {$IFDEF WIN32}
  164.     procedure SetNotification;
  165. {$ENDIF WIN32}
  166.   published
  167.     property StoredProps: TStrings read FStoredProps write SetStoredProps;
  168. {$IFDEF RX_D3}
  169.     property StoredValues: TStoredValues read FStoredValues write SetStoredValues;
  170. {$ENDIF RX_D3}
  171.   end;
  172. { TIniLink }
  173.   TIniLink = class(TPersistent)
  174.   private
  175.     FStorage: TFormPlacement;
  176.     FOnSave: TNotifyEvent;
  177.     FOnLoad: TNotifyEvent;
  178.     function GetIniObject: TObject;
  179.     function GetRootSection: string;
  180.     procedure SetStorage(Value: TFormPlacement);
  181.   protected
  182.     procedure SaveToIni; virtual;
  183.     procedure LoadFromIni; virtual;
  184.   public
  185.     destructor Destroy; override;
  186.     property IniObject: TObject read GetIniObject;
  187.     property Storage: TFormPlacement read FStorage write SetStorage;
  188.     property RootSection: string read GetRootSection;
  189.     property OnSave: TNotifyEvent read FOnSave write FOnSave;
  190.     property OnLoad: TNotifyEvent read FOnLoad write FOnLoad;
  191.   end;
  192. {$IFDEF RX_D3}
  193. { TStoredValue }
  194.   TStoredValueEvent = procedure(Sender: TStoredValue; var Value: Variant) of object;
  195.   TStoredValue = class(TCollectionItem)
  196.   private
  197.     FName: string;
  198.     FValue: Variant;
  199.     FKeyString: string;
  200.     FOnSave: TStoredValueEvent;
  201.     FOnRestore: TStoredValueEvent;
  202.     function IsValueStored: Boolean;
  203.     function GetStoredValues: TStoredValues;
  204.   protected
  205.     function GetDisplayName: string; override;
  206.     procedure SetDisplayName(const Value: string); override;
  207.   public
  208.     constructor Create(Collection: TCollection); override;
  209.     procedure Assign(Source: TPersistent); override;
  210.     procedure Clear;
  211.     procedure Save; virtual;
  212.     procedure Restore; virtual;
  213.     property StoredValues: TStoredValues read GetStoredValues;
  214.   published
  215.     property Name: string read FName write SetDisplayName;
  216.     property Value: Variant read FValue write FValue stored IsValueStored;
  217.     property KeyString: string read FKeyString write FKeyString;
  218.     property OnSave: TStoredValueEvent read FOnSave write FOnSave;
  219.     property OnRestore: TStoredValueEvent read FOnRestore write FOnRestore;
  220.   end;
  221. { TStoredValues }
  222.   TStoredValues = class({$IFDEF RX_D4}TOwnedCollection{$ELSE}TCollection{$ENDIF})
  223.   private
  224.     FStorage: TFormPlacement;
  225.     function GetValue(const Name: string): TStoredValue;
  226.     procedure SetValue(const Name: string; StoredValue: TStoredValue);
  227.     function GetItem(Index: Integer): TStoredValue;
  228.     procedure SetItem(Index: Integer; StoredValue: TStoredValue);
  229.   public
  230. {$IFDEF RX_D4}
  231.     constructor Create(AOwner: TPersistent);
  232. {$ELSE}
  233.     constructor Create;
  234. {$ENDIF}
  235.     function IndexOf(const Name: string): Integer;
  236.     procedure SaveValues; virtual;
  237.     procedure RestoreValues; virtual;
  238.     property Storage: TFormPlacement read FStorage write FStorage;
  239.     property Items[Index: Integer]: TStoredValue read GetItem write SetItem; default;
  240.     property Values[const Name: string]: TStoredValue read GetValue write SetValue;
  241.   end;
  242. {$ENDIF RX_D3}
  243. implementation
  244. uses SysUtils,
  245. {$IFDEF RX_D3}
  246.   Consts,
  247. {$ENDIF RX_D3}
  248.   AppUtils, rxStrUtils, RxProps;
  249. const
  250. { The following string should not be localized }
  251.   siActiveCtrl = 'ActiveControl';
  252.   siVisible = 'Visible';
  253.   siVersion = 'FormVersion';
  254. { TFormPlacement }
  255. constructor TFormPlacement.Create(AOwner: TComponent);
  256. begin
  257.   inherited Create(AOwner);
  258.   FIniFileName := NullStr;
  259.   FIniSection := NullStr;
  260.   FActive := True;
  261.   if AOwner is TForm then FOptions := [fpState, fpPosition]
  262.   else FOptions := [];
  263.   FWinHook := TRxWindowHook.Create(Self);
  264.   FWinHook.AfterMessage := WndMessage;
  265.   FWinMinMaxInfo := TWinMinMaxInfo.Create;
  266.   FWinMinMaxInfo.FOwner := Self;
  267.   FLinks := TList.Create;
  268. end;
  269. destructor TFormPlacement.Destroy;
  270. begin
  271.   IniFree;
  272.   while FLinks.Count > 0 do RemoveLink(FLinks.Last);
  273.   FLinks.Free;
  274.   if not (csDesigning in ComponentState) then begin
  275.     ReleaseHook;
  276.     RestoreEvents;
  277.   end;
  278.   DisposeStr(FIniFileName);
  279.   DisposeStr(FIniSection);
  280.   FWinMinMaxInfo.Free;
  281.   inherited Destroy;
  282. end;
  283. procedure TFormPlacement.Loaded;
  284. var
  285.   Loading: Boolean;
  286. begin
  287.   Loading := csLoading in ComponentState;
  288.   inherited Loaded;
  289.   if not (csDesigning in ComponentState) then begin
  290.     if Loading then SetEvents;
  291.     CheckToggleHook;
  292.   end;
  293. end;
  294. procedure TFormPlacement.AddLink(ALink: TIniLink);
  295. begin
  296.   FLinks.Add(ALink);
  297.   ALink.FStorage := Self;
  298. end;
  299. procedure TFormPlacement.NotifyLinks(Operation: TPlacementOperation);
  300. var
  301.   I: Integer;
  302. begin
  303.   for I := 0 to FLinks.Count - 1 do
  304.     with TIniLink(FLinks[I]) do
  305.       case Operation of
  306.         poSave: SaveToIni;
  307.         poRestore: LoadFromIni;
  308.       end;
  309. end;
  310. procedure TFormPlacement.RemoveLink(ALink: TIniLink);
  311. begin
  312.   ALink.FStorage := nil;
  313.   FLinks.Remove(ALink);
  314. end;
  315. function TFormPlacement.GetForm: TForm;
  316. begin
  317.   if Owner is TCustomForm then Result := TForm(Owner as TCustomForm)
  318.   else Result := nil;
  319. end;
  320. procedure TFormPlacement.SetEvents;
  321. begin
  322.   if Owner is TCustomForm then begin
  323.     with TForm(Form) do begin
  324.       FSaveFormShow := OnShow;
  325.       OnShow := FormShow;
  326.       FSaveFormCloseQuery := OnCloseQuery;
  327.       OnCloseQuery := FormCloseQuery;
  328.       FSaveFormDestroy := OnDestroy;
  329.       OnDestroy := FormDestroy;
  330.       FDefMaximize := (biMaximize in BorderIcons);
  331.     end;
  332.     if FPreventResize then UpdatePreventResize;
  333.   end;
  334. end;
  335. procedure TFormPlacement.RestoreEvents;
  336. begin
  337.   if (Owner <> nil) and (Owner is TCustomForm) then
  338.     with TForm(Form) do begin
  339.       OnShow := FSaveFormShow;
  340.       OnCloseQuery := FSaveFormCloseQuery;
  341.       OnDestroy := FSaveFormDestroy;
  342.     end;
  343. end;
  344. procedure TFormPlacement.SetHook;
  345. begin
  346.   if not (csDesigning in ComponentState) and (Owner <> nil) and
  347.     (Owner is TCustomForm) then
  348.     FWinHook.WinControl := Form;
  349. end;
  350. procedure TFormPlacement.ReleaseHook;
  351. begin
  352.   FWinHook.WinControl := nil;
  353. end;
  354. procedure TFormPlacement.CheckToggleHook;
  355. begin
  356.   if CheckMinMaxInfo or PreventResize then SetHook else ReleaseHook;
  357. end;
  358. function TFormPlacement.CheckMinMaxInfo: Boolean;
  359. begin
  360.   Result := not FWinMinMaxInfo.DefaultMinMaxInfo;
  361. end;
  362. procedure TFormPlacement.MinMaxInfoModified;
  363. begin
  364.   UpdatePlacement;
  365.   if not (csLoading in ComponentState) then CheckToggleHook;
  366. end;
  367. procedure TFormPlacement.SetWinMinMaxInfo(Value: TWinMinMaxInfo);
  368. begin
  369.   FWinMinMaxInfo.Assign(Value);
  370. end;
  371. procedure TFormPlacement.WndMessage(Sender: TObject; var Msg: TMessage;
  372.   var Handled: Boolean);
  373. begin
  374.   if FPreventResize and (Owner is TCustomForm) then begin
  375.     case Msg.Msg of
  376.       WM_GETMINMAXINFO:
  377.         if Form.HandleAllocated and IsWindowVisible(Form.Handle) then begin
  378.           with TWMGetMinMaxInfo(Msg).MinMaxInfo^ do begin
  379.             ptMinTrackSize := Point(Form.Width, Form.Height);
  380.             ptMaxTrackSize := Point(Form.Width, Form.Height);
  381.           end;
  382.           Msg.Result := 1;
  383.         end;
  384.       WM_INITMENUPOPUP:
  385.         if TWMInitMenuPopup(Msg).SystemMenu then begin
  386.           if Form.Menu <> nil then
  387.             Form.Menu.DispatchPopup(TWMInitMenuPopup(Msg).MenuPopup);
  388.           EnableMenuItem(TWMInitMenuPopup(Msg).MenuPopup, SC_SIZE,
  389.             MF_BYCOMMAND or MF_GRAYED);
  390.           EnableMenuItem(TWMInitMenuPopup(Msg).MenuPopup, SC_MAXIMIZE,
  391.             MF_BYCOMMAND or MF_GRAYED);
  392.           Msg.Result := 1;
  393.         end;
  394.       WM_NCHITTEST:
  395.         begin
  396.           if Msg.Result in [HTLEFT, HTRIGHT, HTBOTTOM, HTBOTTOMRIGHT,
  397.             HTBOTTOMLEFT, HTTOP, HTTOPRIGHT, HTTOPLEFT]
  398.           then Msg.Result := HTNOWHERE;
  399.         end;
  400.     end;
  401.   end
  402.   else if (Msg.Msg = WM_GETMINMAXINFO) then begin
  403.     if CheckMinMaxInfo then begin
  404.       with TWMGetMinMaxInfo(Msg).MinMaxInfo^ do begin
  405.          if FWinMinMaxInfo.MinTrackWidth <> 0 then
  406.            ptMinTrackSize.X := FWinMinMaxInfo.MinTrackWidth;
  407.          if FWinMinMaxInfo.MinTrackHeight <> 0 then
  408.            ptMinTrackSize.Y := FWinMinMaxInfo.MinTrackHeight;
  409.          if FWinMinMaxInfo.MaxTrackWidth <> 0 then
  410.            ptMaxTrackSize.X := FWinMinMaxInfo.MaxTrackWidth;
  411.          if FWinMinMaxInfo.MaxTrackHeight <> 0 then
  412.            ptMaxTrackSize.Y := FWinMinMaxInfo.MaxTrackHeight;
  413.          if FWinMinMaxInfo.MaxSizeWidth <> 0 then
  414.            ptMaxSize.X := FWinMinMaxInfo.MaxSizeWidth;
  415.          if FWinMinMaxInfo.MaxSizeHeight <> 0 then
  416.            ptMaxSize.Y := FWinMinMaxInfo.MaxSizeHeight;
  417.          if FWinMinMaxInfo.MaxPosLeft <> 0 then
  418.            ptMaxPosition.X := FWinMinMaxInfo.MaxPosLeft;
  419.          if FWinMinMaxInfo.MaxPosTop <> 0 then
  420.            ptMaxPosition.Y := FWinMinMaxInfo.MaxPosTop;
  421.       end;
  422.     end
  423.     else begin
  424.       TWMGetMinMaxInfo(Msg).MinMaxInfo^.ptMaxPosition.X := 0;
  425.       TWMGetMinMaxInfo(Msg).MinMaxInfo^.ptMaxPosition.Y := 0;
  426.     end;
  427.     Msg.Result := 1;
  428.   end;
  429. end;
  430. procedure TFormPlacement.FormShow(Sender: TObject);
  431. begin
  432.   if Active then
  433.     try
  434.       RestoreFormPlacement;
  435.     except
  436.       Application.HandleException(Self);
  437.     end;
  438.   if Assigned(FSaveFormShow) then FSaveFormShow(Sender);
  439. end;
  440. procedure TFormPlacement.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  441. begin
  442.   if Assigned(FSaveFormCloseQuery) then
  443.     FSaveFormCloseQuery(Sender, CanClose);
  444.   if CanClose and Active and (Owner is TCustomForm) and (Form.Handle <> 0) then
  445.     try
  446.       SaveFormPlacement;
  447.     except
  448.       Application.HandleException(Self);
  449.     end;
  450. end;
  451. procedure TFormPlacement.FormDestroy(Sender: TObject);
  452. begin
  453.   if Active and not FSaved then begin
  454.     FDestroying := True;
  455.     try
  456.       SaveFormPlacement;
  457.     except
  458.       Application.HandleException(Self);
  459.     end;
  460.     FDestroying := False;
  461.   end;
  462.   if Assigned(FSaveFormDestroy) then FSaveFormDestroy(Sender);
  463. end;
  464. procedure TFormPlacement.UpdatePlacement;
  465. const
  466. {$IFDEF WIN32}
  467.   Metrics: array[bsSingle..bsSizeToolWin] of Word =
  468.     (SM_CXBORDER, SM_CXFRAME, SM_CXDLGFRAME, SM_CXBORDER, SM_CXFRAME);
  469. {$ELSE}
  470.   Metrics: array[bsSingle..bsDialog] of Word =
  471.     (SM_CXBORDER, SM_CXFRAME, SM_CXDLGFRAME);
  472. {$ENDIF}
  473. var
  474.   Placement: TWindowPlacement;
  475. begin
  476.   if (Owner <> nil) and (Owner is TCustomForm) and Form.HandleAllocated and
  477.   not (csLoading in ComponentState) then
  478.     if not (FPreventResize or CheckMinMaxInfo) then begin
  479.       Placement.Length := SizeOf(TWindowPlacement);
  480.       GetWindowPlacement(Form.Handle, @Placement);
  481.       if not IsWindowVisible(Form.Handle) then
  482.         Placement.ShowCmd := SW_HIDE;
  483.       if Form.BorderStyle <> bsNone then begin
  484.         Placement.ptMaxPosition.X := -GetSystemMetrics(Metrics[Form.BorderStyle]);
  485.         Placement.ptMaxPosition.Y := -GetSystemMetrics(Metrics[Form.BorderStyle] + 1);
  486.       end
  487.       else Placement.ptMaxPosition := Point(0, 0);
  488.       SetWindowPlacement(Form.Handle, @Placement);
  489.     end;
  490. end;
  491. procedure TFormPlacement.UpdatePreventResize;
  492. var
  493.   IsActive: Boolean;
  494. begin
  495.   if not (csDesigning in ComponentState) and (Owner is TCustomForm) then
  496.   begin
  497.     if FPreventResize then
  498.       FDefMaximize := (biMaximize in Form.BorderIcons);
  499.     IsActive := Active;
  500.     Active := False;
  501.     try
  502.       if (not FPreventResize) and FDefMaximize and
  503.         (Form.BorderStyle <> bsDialog) then
  504.         Form.BorderIcons := Form.BorderIcons + [biMaximize]
  505.       else Form.BorderIcons := Form.BorderIcons - [biMaximize];
  506.     finally
  507.       Active := IsActive;
  508.     end;
  509.     if not (csLoading in ComponentState) then CheckToggleHook;
  510.   end;
  511. end;
  512. procedure TFormPlacement.SetPreventResize(Value: Boolean);
  513. begin
  514.   if (Form <> nil) and (FPreventResize <> Value) then begin
  515.     FPreventResize := Value;
  516.     UpdatePlacement;
  517.     UpdatePreventResize;
  518.   end;
  519. end;
  520. function TFormPlacement.GetIniFile: TObject;
  521. begin
  522. {$IFDEF WIN32}
  523.   if UseRegistry then Result := FRegIniFile
  524.   else Result := FIniFile;
  525. {$ELSE}
  526.   Result := FIniFile;
  527. {$ENDIF WIN32}
  528. end;
  529. function TFormPlacement.GetIniFileName: string;
  530. begin
  531.   Result := FIniFileName^;
  532.   if (Result = '') and not (csDesigning in ComponentState) then begin
  533. {$IFDEF WIN32}
  534.     if UseRegistry then Result := GetDefaultIniRegKey
  535.     else Result := GetDefaultIniName;
  536. {$ELSE}
  537.     Result := GetDefaultIniName;
  538. {$ENDIF}
  539.   end;
  540. end;
  541. procedure TFormPlacement.SetIniFileName(const Value: string);
  542. begin
  543.   AssignStr(FIniFileName, Value);
  544. end;
  545. function TFormPlacement.GetIniSection: string;
  546. begin
  547.   Result := FIniSection^;
  548.   if (Result = '') and not (csDesigning in ComponentState) then
  549.     Result := GetDefaultSection(Owner);
  550. end;
  551. procedure TFormPlacement.SetIniSection(const Value: string);
  552. begin
  553.   AssignStr(FIniSection, Value);
  554. end;
  555. procedure TFormPlacement.Save;
  556. begin
  557.   if Assigned(FOnSavePlacement) then FOnSavePlacement(Self);
  558. end;
  559. procedure TFormPlacement.Restore;
  560. begin
  561.   if Assigned(FOnRestorePlacement) then FOnRestorePlacement(Self);
  562. end;
  563. procedure TFormPlacement.SavePlacement;
  564. begin
  565.   if Owner is TCustomForm then begin
  566. {$IFDEF WIN32}
  567.     if UseRegistry then begin
  568.       WriteFormPlacementReg(Form, FRegIniFile, IniSection);
  569.       if (fpActiveControl in Options) and (Form.ActiveControl <> nil) then
  570.         FRegIniFile.WriteString(IniSection, siActiveCtrl, Form.ActiveControl.Name);
  571.       FRegIniFile.WriteBool(IniSection, siVisible, FDestroying);
  572.     end
  573.     else begin
  574.       WriteFormPlacement(Form, FIniFile, IniSection);
  575.       if (fpActiveControl in Options) and (Form.ActiveControl <> nil) then
  576.         FIniFile.WriteString(IniSection, siActiveCtrl, Form.ActiveControl.Name);
  577.       FIniFile.WriteBool(IniSection, siVisible, FDestroying);
  578.     end;
  579. {$ELSE}
  580.     WriteFormPlacement(Form, FIniFile, IniSection);
  581.     if (fpActiveControl in Options) and (Form.ActiveControl <> nil) then
  582.       FIniFile.WriteString(IniSection, siActiveCtrl, Form.ActiveControl.Name);
  583.     FIniFile.WriteBool(IniSection, siVisible, FDestroying);
  584. {$ENDIF}
  585.   end;
  586.   NotifyLinks(poSave);
  587. end;
  588. procedure TFormPlacement.RestorePlacement;
  589. begin
  590.   if Owner is TCustomForm then begin
  591. {$IFDEF WIN32}
  592.     if UseRegistry then
  593.       ReadFormPlacementReg(Form, FRegIniFile, IniSection, fpState in Options,
  594.         fpPosition in Options)
  595.     else
  596. {$ENDIF}
  597.       ReadFormPlacement(Form, FIniFile, IniSection, fpState in Options,
  598.         fpPosition in Options);
  599.   end;
  600.   NotifyLinks(poRestore);
  601. end;
  602. procedure TFormPlacement.IniNeeded(ReadOnly: Boolean);
  603. begin
  604.   if IniFileObject = nil then begin
  605. {$IFDEF WIN32}
  606.     if UseRegistry then begin
  607.       FRegIniFile := TRegIniFile.Create(IniFileName);
  608. {$IFDEF RX_D5}
  609.       if ReadOnly then FRegIniFile.Access := KEY_READ;
  610. {$ENDIF}
  611.       case FRegistryRoot of
  612.         prLocalMachine:
  613.           FRegIniFile.RootKey := HKEY_LOCAL_MACHINE;
  614.         prClassesRoot: 
  615.           FRegIniFile.RootKey := HKEY_CLASSES_ROOT;
  616.         prCurrentConfig: 
  617.           FRegIniFile.RootKey := HKEY_CURRENT_CONFIG;
  618.         prUsers: 
  619.           FRegIniFile.RootKey := HKEY_USERS;
  620.         prDynData:
  621.           FRegIniFile.RootKey := HKEY_DYN_DATA;
  622.       end;
  623.     end
  624.     else
  625. {$ENDIF}
  626.     FIniFile := TIniFile.Create(IniFileName);
  627.   end;
  628. end;
  629. procedure TFormPlacement.IniFree;
  630. begin
  631.   if IniFileObject <> nil then begin
  632.     IniFileObject.Free;
  633.     FIniFile := nil;
  634. {$IFDEF WIN32}
  635.     FRegIniFile := nil;
  636. {$ENDIF}
  637.   end;
  638. end;
  639. function TFormPlacement.DoReadString(const Section, Ident,
  640.   Default: string): string;
  641. begin
  642.   if IniFileObject <> nil then
  643.     Result := IniReadString(IniFileObject, Section, Ident, Default)
  644.   else begin
  645.     IniNeeded(True);
  646.     try
  647.       Result := IniReadString(IniFileObject, Section, Ident, Default);
  648.     finally
  649.       IniFree;
  650.     end;
  651.   end;
  652. end;
  653. function TFormPlacement.ReadString(const Ident, Default: string): string;
  654. begin
  655.   Result := DoReadString(IniSection, Ident, Default);
  656. end;
  657. procedure TFormPlacement.DoWriteString(const Section, Ident, Value: string);
  658. begin
  659.   if IniFileObject <> nil then
  660.     IniWriteString(IniFileObject, Section, Ident, Value)
  661.   else begin
  662.     IniNeeded(False);
  663.     try
  664.       IniWriteString(IniFileObject, Section, Ident, Value);
  665.     finally
  666.       IniFree;
  667.     end;
  668.   end;
  669. end;
  670. procedure TFormPlacement.WriteString(const Ident, Value: string);
  671. begin
  672.   DoWriteString(IniSection, Ident, Value);
  673. end;
  674. function TFormPlacement.ReadInteger(const Ident: string; Default: Longint): Longint;
  675. begin
  676.   if IniFileObject <> nil then
  677.     Result := IniReadInteger(IniFileObject, IniSection, Ident, Default)
  678.   else begin
  679.     IniNeeded(True);
  680.     try
  681.       Result := IniReadInteger(IniFileObject, IniSection, Ident, Default);
  682.     finally
  683.       IniFree;
  684.     end;
  685.   end;
  686. end;
  687. procedure TFormPlacement.WriteInteger(const Ident: string; Value: Longint);
  688. begin
  689.   if IniFileObject <> nil then
  690.     IniWriteInteger(IniFileObject, IniSection, Ident, Value)
  691.   else begin
  692.     IniNeeded(False);
  693.     try
  694.       IniWriteInteger(IniFileObject, IniSection, Ident, Value);
  695.     finally
  696.       IniFree;
  697.     end;
  698.   end;
  699. end;
  700. procedure TFormPlacement.EraseSections;
  701. var
  702.   Lines: TStrings;
  703.   I: Integer;
  704. begin
  705.   if IniFileObject = nil then begin
  706.     IniNeeded(False);
  707.     try
  708.       Lines := TStringList.Create;
  709.       try
  710.         IniReadSections(IniFileObject, Lines);
  711.         for I := 0 to Lines.Count - 1 do begin
  712.           if (Lines[I] = IniSection) or
  713.             (IsWild(Lines[I], IniSection + '.*', False) or
  714.             IsWild(Lines[I], IniSection + '*', False)) then
  715.             IniEraseSection(IniFileObject, Lines[I]);
  716.         end;
  717.       finally
  718.         Lines.Free;
  719.       end;
  720.     finally
  721.       IniFree;
  722.     end;
  723.   end;
  724. end;
  725. procedure TFormPlacement.SaveFormPlacement;
  726. begin
  727.   if FRestored or not Active then begin
  728.     IniNeeded(False);
  729.     try
  730.       WriteInteger(siVersion, FVersion);
  731.       SavePlacement;
  732.       Save;
  733.       FSaved := True;
  734.     finally
  735.       IniFree;
  736.     end;
  737.   end;
  738. end;
  739. procedure TFormPlacement.RestoreFormPlacement;
  740. var
  741.   cActive: TComponent;
  742. begin
  743.   FSaved := False;
  744.   IniNeeded(True);
  745.   try
  746.     if ReadInteger(siVersion, 0) >= FVersion then begin
  747.       RestorePlacement;
  748.       FRestored := True;
  749.       Restore;
  750.       if (fpActiveControl in Options) and (Owner is TCustomForm) then begin
  751.         cActive := Form.FindComponent(IniReadString(IniFileObject,
  752.           IniSection, siActiveCtrl, ''));
  753.         if (cActive <> nil) and (cActive is TWinControl) and
  754.           TWinControl(cActive).CanFocus then
  755.             Form.ActiveControl := TWinControl(cActive);
  756.       end;
  757.     end;
  758.     FRestored := True;
  759.   finally
  760.     IniFree;
  761.   end;
  762.   UpdatePlacement;
  763. end;
  764. { TWinMinMaxInfo }
  765. procedure TWinMinMaxInfo.Assign(Source: TPersistent);
  766. begin
  767.   if Source is TWinMinMaxInfo then begin
  768.     FMinMaxInfo := TWinMinMaxInfo(Source).FMinMaxInfo;
  769.     if FOwner <> nil then FOwner.MinMaxInfoModified;
  770.   end
  771.   else inherited Assign(Source);
  772. end;
  773. function TWinMinMaxInfo.GetMinMaxInfo(Index: Integer): Integer;
  774. begin
  775.   with FMinMaxInfo do begin
  776.     case Index of
  777.       0: Result := ptMaxPosition.X;
  778.       1: Result := ptMaxPosition.Y;
  779.       2: Result := ptMaxSize.Y;
  780.       3: Result := ptMaxSize.X;
  781.       4: Result := ptMaxTrackSize.Y;
  782.       5: Result := ptMaxTrackSize.X;
  783.       6: Result := ptMinTrackSize.Y;
  784.       7: Result := ptMinTrackSize.X;
  785.       else Result := 0;
  786.     end;
  787.   end;
  788. end;
  789. procedure TWinMinMaxInfo.SetMinMaxInfo(Index: Integer; Value: Integer);
  790. begin
  791.   if GetMinMaxInfo(Index) <> Value then begin
  792.     with FMinMaxInfo do begin
  793.       case Index of
  794.         0: ptMaxPosition.X := Value;
  795.         1: ptMaxPosition.Y := Value;
  796.         2: ptMaxSize.Y := Value;
  797.         3: ptMaxSize.X := Value;
  798.         4: ptMaxTrackSize.Y := Value;
  799.         5: ptMaxTrackSize.X := Value;
  800.         6: ptMinTrackSize.Y := Value;
  801.         7: ptMinTrackSize.X := Value;
  802.       end;
  803.     end;
  804.     if FOwner <> nil then FOwner.MinMaxInfoModified;
  805.   end;
  806. end;
  807. function TWinMinMaxInfo.DefaultMinMaxInfo: Boolean;
  808. begin
  809.   with FMinMaxInfo do begin
  810.     Result := not ((ptMinTrackSize.X <> 0) or (ptMinTrackSize.Y <> 0) or
  811.       (ptMaxTrackSize.X <> 0) or (ptMaxTrackSize.Y <> 0) or
  812.       (ptMaxSize.X <> 0) or (ptMaxSize.Y <> 0) or
  813.       (ptMaxPosition.X <> 0) or (ptMaxPosition.Y <> 0));
  814.   end;
  815. end;
  816. { TFormStorage }
  817. constructor TFormStorage.Create(AOwner: TComponent);
  818. begin
  819.   inherited Create(AOwner);
  820.   FStoredProps := TStringList.Create;
  821. {$IFDEF RX_D3}
  822.   FStoredValues := TStoredValues.Create{$IFDEF RX_D4}(Self){$ENDIF RX_D4};
  823.   FStoredValues.Storage := Self;
  824. {$ENDIF RX_D3}
  825. end;
  826. destructor TFormStorage.Destroy;
  827. begin
  828.   FStoredProps.Free;
  829.   FStoredProps := nil;
  830. {$IFDEF RX_D3}
  831.   FStoredValues.Free;
  832.   FStoredValues := nil;
  833. {$ENDIF RX_D3}
  834.   inherited Destroy;
  835. end;
  836. {$IFDEF WIN32}
  837. procedure TFormStorage.SetNotification;
  838. var
  839.   I: Integer;
  840.   Component: TComponent;
  841. begin
  842.   for I := FStoredProps.Count - 1 downto 0 do begin
  843.     Component := TComponent(FStoredProps.Objects[I]);
  844.     if Component <> nil then Component.FreeNotification(Self);
  845.   end;
  846. end;
  847. {$ENDIF WIN32}
  848. procedure TFormStorage.SetStoredProps(Value: TStrings);
  849. begin
  850.   FStoredProps.Assign(Value);
  851. {$IFDEF WIN32}
  852.   SetNotification;
  853. {$ENDIF}
  854. end;
  855. {$IFDEF RX_D3}
  856. procedure TFormStorage.SetStoredValues(Value: TStoredValues);
  857. begin
  858.   FStoredValues.Assign(Value);
  859. end;
  860. {$ENDIF RX_D3}
  861. procedure TFormStorage.Loaded;
  862. begin
  863.   inherited Loaded;
  864.   UpdateStoredList(Owner, FStoredProps, True);
  865. end;
  866. procedure TFormStorage.WriteState(Writer: TWriter);
  867. begin
  868.   UpdateStoredList(Owner, FStoredProps, False);
  869.   inherited WriteState(Writer);
  870. end;
  871. procedure TFormStorage.Notification(AComponent: TComponent; Operation: TOperation);
  872. var
  873.   I: Integer;
  874.   Component: TComponent;
  875. begin
  876.   inherited Notification(AComponent, Operation);
  877.   if not (csDestroying in ComponentState) and (Operation = opRemove) and
  878.     (FStoredProps <> nil) then
  879.     for I := FStoredProps.Count - 1 downto 0 do begin
  880.       Component := TComponent(FStoredProps.Objects[I]);
  881.       if Component = AComponent then FStoredProps.Delete(I);
  882.     end;
  883. end;
  884. procedure TFormStorage.SaveProperties;
  885. begin
  886.   with TPropsStorage.Create do
  887.   try
  888.     Section := IniSection;
  889.     OnWriteString := DoWriteString;
  890. {$IFDEF WIN32}
  891.     if UseRegistry then OnEraseSection := FRegIniFile.EraseSection
  892.     else OnEraseSection := FIniFile.EraseSection;
  893. {$ELSE}
  894.     OnEraseSection := FIniFile.EraseSection;
  895. {$ENDIF WIN32}
  896.     StoreObjectsProps(Owner, FStoredProps);
  897.   finally
  898.     Free;
  899.   end;
  900. end;
  901. procedure TFormStorage.RestoreProperties;
  902. begin
  903.   with TPropsStorage.Create do
  904.   try
  905.     Section := IniSection;
  906.     OnReadString := DoReadString;
  907.     try
  908.       LoadObjectsProps(Owner, FStoredProps);
  909.     except
  910.       { ignore any exceptions }
  911.     end;
  912.   finally
  913.     Free;
  914.   end;
  915. end;
  916. procedure TFormStorage.SavePlacement;
  917. begin
  918.   inherited SavePlacement;
  919.   SaveProperties;
  920. {$IFDEF RX_D3}
  921.   StoredValues.SaveValues;
  922. {$ENDIF}
  923. end;
  924. procedure TFormStorage.RestorePlacement;
  925. begin
  926.   inherited RestorePlacement;
  927.   FRestored := True;
  928.   RestoreProperties;
  929. {$IFDEF RX_D3}
  930.   StoredValues.RestoreValues;
  931. {$ENDIF}
  932. end;
  933. { TIniLink }
  934. destructor TIniLink.Destroy;
  935. begin
  936.   FOnSave := nil;
  937.   FOnLoad := nil;
  938.   SetStorage(nil);
  939.   inherited Destroy;
  940. end;
  941. function TIniLink.GetIniObject: TObject;
  942. begin
  943.   if Assigned(FStorage) then Result := FStorage.IniFileObject
  944.   else Result := nil;
  945. end;
  946. function TIniLink.GetRootSection: string;
  947. begin
  948.   if Assigned(FStorage) then Result := FStorage.FIniSection^
  949.   else Result := '';
  950.   if Result <> '' then Result := Result + '';
  951. end;
  952. procedure TIniLink.SetStorage(Value: TFormPlacement);
  953. begin
  954.   if FStorage <> Value then begin
  955.     if FStorage <> nil then FStorage.RemoveLink(Self);
  956.     if Value <> nil then Value.AddLink(Self);
  957.   end;
  958. end;
  959. procedure TIniLink.SaveToIni;
  960. begin
  961.   if Assigned(FOnSave) then FOnSave(Self);
  962. end;
  963. procedure TIniLink.LoadFromIni;
  964. begin
  965.   if Assigned(FOnLoad) then FOnLoad(Self);
  966. end;
  967. {$IFDEF RX_D3}
  968. { TStoredValue }
  969. constructor TStoredValue.Create(Collection: TCollection);
  970. begin
  971.   inherited Create(Collection);
  972.   FValue := Unassigned;
  973. end;
  974. procedure TStoredValue.Assign(Source: TPersistent);
  975. begin
  976.   if (Source is TStoredValue) and (Source <> nil) then begin
  977.     if VarIsEmpty(TStoredValue(Source).FValue) then
  978.       Clear
  979.     else
  980.       Value := TStoredValue(Source).FValue;
  981.     Name := TStoredValue(Source).Name;
  982.     KeyString := TStoredValue(Source).KeyString;
  983.   end;
  984. end;
  985. function TStoredValue.GetDisplayName: string;
  986. begin
  987.   if FName = '' then
  988.     Result := inherited GetDisplayName
  989.   else
  990.     Result := FName;
  991. end;
  992. procedure TStoredValue.SetDisplayName(const Value: string);
  993. begin
  994.   if (Value <> '') and (AnsiCompareText(Value, FName) <> 0) and
  995.     (Collection is TStoredValues) and (TStoredValues(Collection).IndexOf(Value) >= 0) then
  996.     raise Exception.Create(SDuplicateString);
  997.   FName := Value;
  998.   inherited;
  999. end;
  1000. function TStoredValue.GetStoredValues: TStoredValues;
  1001. begin
  1002.   if Collection is TStoredValues then
  1003.     Result := TStoredValues(Collection)
  1004.   else
  1005.     Result := nil;
  1006. end;
  1007. procedure TStoredValue.Clear;
  1008. begin
  1009.   FValue := Unassigned;
  1010. end;
  1011. function TStoredValue.IsValueStored: Boolean;
  1012. begin
  1013.   Result := not VarIsEmpty(FValue);
  1014. end;
  1015. procedure TStoredValue.Save;
  1016. var
  1017.   SaveValue: Variant;
  1018.   SaveStrValue: string;
  1019. begin
  1020.   SaveValue := Value;
  1021.   if Assigned(FOnSave) then
  1022.     FOnSave(Self, SaveValue);
  1023.   SaveStrValue := VarToStr(SaveValue);
  1024.   if KeyString <> '' then
  1025.     SaveStrValue := XorEncode(KeyString, SaveStrValue);
  1026.   StoredValues.Storage.WriteString(Name, SaveStrValue);
  1027. end;
  1028. procedure TStoredValue.Restore;
  1029. var
  1030.   RestoreValue: Variant;
  1031.   RestoreStrValue, DefaultStrValue: string;
  1032. begin
  1033.   DefaultStrValue := VarToStr(Value);
  1034.   if KeyString <> '' then
  1035.     DefaultStrValue := XorEncode(KeyString, DefaultStrValue);
  1036.   RestoreStrValue := StoredValues.Storage.ReadString(Name, DefaultStrValue);
  1037.   if KeyString <> '' then
  1038.     RestoreStrValue := XorDecode(KeyString, RestoreStrValue);
  1039.   RestoreValue := RestoreStrValue;
  1040.   if Assigned(FOnRestore) then
  1041.     FOnRestore(Self, RestoreValue);
  1042.   Value := RestoreValue;  
  1043. end;
  1044. { TStoredValues }
  1045. {$IFDEF RX_D4}
  1046. constructor TStoredValues.Create(AOwner: TPersistent);
  1047. begin
  1048.   inherited Create(AOwner, TStoredValue);
  1049. end;
  1050. {$ELSE}
  1051. constructor TStoredValues.Create;
  1052. begin
  1053.   inherited Create(TStoredValue);
  1054. end;
  1055. {$ENDIF}
  1056. function TStoredValues.IndexOf(const Name: string): Integer;
  1057. begin
  1058.   for Result := 0 to Count - 1 do
  1059.     if AnsiCompareText(Items[Result].Name, Name) = 0 then Exit;
  1060.   Result := -1;
  1061. end;
  1062. function TStoredValues.GetItem(Index: Integer): TStoredValue;
  1063. begin
  1064.   Result := TStoredValue(inherited Items[Index]);
  1065. end;
  1066. procedure TStoredValues.SetItem(Index: Integer; StoredValue: TStoredValue);
  1067. begin
  1068.   inherited SetItem(Index, TCollectionItem(StoredValue));
  1069. end;
  1070. function TStoredValues.GetValue(const Name: string): TStoredValue;
  1071. var
  1072.   I: Integer;
  1073. begin
  1074.   I := IndexOf(Name);
  1075.   if I < 0 then
  1076.     Result := nil
  1077.   else
  1078.     Result := Items[I];
  1079. end;
  1080. procedure TStoredValues.SetValue(const Name: string; StoredValue: TStoredValue);
  1081. var
  1082.   I: Integer;
  1083. begin
  1084.   I := IndexOf(Name);
  1085.   if I >= 0 then
  1086.     Items[I].Assign(StoredValue);
  1087. end;
  1088. procedure TStoredValues.SaveValues;
  1089. var
  1090.   I: Integer;
  1091. begin
  1092.   for I := 0 to Count - 1 do
  1093.     Items[I].Save;
  1094. end;
  1095. procedure TStoredValues.RestoreValues;
  1096. var
  1097.   I: Integer;
  1098. begin
  1099.   for I := 0 to Count - 1 do
  1100.     Items[I].Restore;
  1101. end;
  1102. {$ENDIF RX_D3}
  1103. end.