home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 March / Chip_1998-03_cd.bin / zkuste / delphi / WhiteAnts / CMPNAMES.ZIP / CMPNAMES.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-02-14  |  21.9 KB  |  744 lines

  1. {
  2. +----------------------------------------------------------------------------+
  3. |                                      ⌐  ⌐                                  |
  4. |                                    ⌐⌐ ⌐ ⌐ ⌐                                |
  5. |                                 ⌐⌐⌐ ⌐   ⌐  ⌐                               |
  6. |                                 ⌐⌐    ⌐ ⌐   ⌐                              |
  7. |                  ⌐             ⌐⌐     ⌐  ⌐                                 |
  8. |                 ⌐ ⌐            ⌐⌐⌐    ⌐⌐  ⌐                                |
  9. |             ⌐⌐  ⌐  ⌐      ⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐  ⌐                                    |
  10. |            ⌐  ⌐⌐  ⌐⌐      ⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐                                  |
  11. |            ⌐ ⌐⌐⌐ ⌐⌐⌐⌐⌐⌐ ⌐⌐⌐ ⌐   ⌐⌐⌐⌐⌐⌐⌐⌐                                   |
  12. |           ⌐ ⌐⌐ ⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐ ⌐   ⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐      Copyright ⌐ 1996-1997 by:  |
  13. |           ⌐ ⌐⌐⌐⌐⌐⌐ ⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐⌐  ⌐ ⌐⌐⌐⌐⌐ ⌐⌐                                 |
  14. |          ⌐ ⌐⌐⌐⌐⌐⌐⌐   ⌐⌐⌐⌐⌐ ⌐⌐⌐⌐    ⌐⌐ ⌐⌐ ⌐      WHITE ANTS SYSTEMHOUSE BV  |
  15. |         ⌐  ⌐⌐⌐⌐⌐⌐⌐ ⌐⌐⌐ ⌐⌐⌐ ⌐⌐ ⌐       ⌐⌐⌐⌐      Geleen 12                  |
  16. |         ⌐ ⌐⌐⌐⌐⌐⌐⌐    ⌐   ⌐⌐   ⌐⌐⌐       ⌐       8032 GB Zwolle             |
  17. |           ⌐⌐⌐⌐⌐⌐     ⌐            ⌐ ⌐           Netherlands                |
  18. |      ⌐⌐⌐  ⌐⌐⌐⌐⌐      ⌐     ⌐⌐     ⌐  ⌐                                     |
  19. |            ⌐⌐       ⌐              ⌐  ⌐⌐⌐ ⌐     Tel. +31 38 453 86 31      |
  20. |      ⌐              ⌐              ⌐            Fax. +31 38 453 41 22      |
  21. |      ⌐             ⌐               ⌐⌐                                      |
  22. |    ⌐              ⌐                  ⌐⌐         www.whiteants.com          |
  23. |  ⌐⌐              ⌐                     ⌐ ⌐      support@whiteants.com      |
  24. |                 ⌐                                                          |
  25. +----------------------------------------------------------------------------+
  26.   file     : CmpNames
  27.   version  : 1.01
  28.   comment  : 
  29.   date     : 14-02-1997
  30.   time     : 13:57:59
  31.   author   : G.Beuze, R.Post
  32.   compiler : Delphi 1.0
  33. +----------------------------------------------------------------------------+
  34. | DISCLAIMER:                                                                |
  35. | THIS SOURCE IS FREEWARE. YOU ARE ALLOWED TO USE IT IN YOUR OWN PROJECTS    |
  36. | WITHOUT ANY RESTRICTIONS, BUT YOU ARE NOT ALLOWED TO SELL IT IN ANY WAY.   |
  37. | THERE IS NO WARRANTY AT ALL - YOU USE IT ON YOUR OWN RISC. WHITE ANTS DOES |
  38. | NOT ASSUME ANY RESPONSIBILITY FOR ANY DAMAGE OR ANY LOOSE OF TIME OR MONEY |
  39. | DUE THE USE OF ANY PART OF THIS SOURCE CODE.                               |
  40. +----------------------------------------------------------------------------+
  41.  
  42.   Description:
  43. This unit contains the TRenamer class which is used to apply
  44. naming convention to components dropped on a form during design time.
  45. TRenamer uses the classes TNameRule and TNameRuleList which are also
  46. declared in this unit. 
  47.  
  48. Although this unit is only active when installed in the component library
  49. it is not visible in the VCL since there are no components registered 
  50. from within this unit.
  51.  
  52. The name rules are read from the file NAMERULE.INI which should be placed in the
  53. COMPLIB.DCL directory. A log file NAMERULE.LOG is written to the same directory
  54. to inform you of recognized rules, the default rule and components to which
  55. they apply.
  56.  
  57. The idea of applying naming conventions and some basic mechanisms were taken 
  58. from Ray Lischners book "Secrets of Delhi 2.0". We at White Ants basically added 
  59. the designer wrapper interface and the ini-files.
  60.  
  61. Caution:
  62. - Do not instantiate a TRenamer class yourself by calling TRenamer.Create.
  63. - TRenamer grabs the Delphi executable's Screen.OnActiveFormChange.
  64. - TRenamer interferes with delphi's Form designer. Be cautions to install
  65.   this unit if you have any other units installed in the VCL which
  66.   also interact with or are depending on Delphi's FormDesigner. You''ll get a 
  67.   warning if this unit detects such an error. This should   normally not be the 
  68.   case, at White Ants we enjoy working (troublefree) using this unit.
  69. }
  70.  
  71. unit CmpNames;
  72. {MMWIN:ENDEXPAND}
  73.  
  74. interface
  75.  
  76. function CheckRule(const Rule: string): Integer;
  77.  
  78. procedure Register;
  79.  
  80. implementation
  81.  
  82. uses 
  83.   WinTypes, WinProcs, SysUtils, Classes, Controls, Forms, TypInfo, ExtCtrls, 
  84.   DsgnIntf, LibMain, IniFiles, Dialogs,                 { standard VCL units }
  85.   DsgnWrap, Containr, StrUtils, FileUtil, TextStrm;     { WAS units }
  86.  
  87. type
  88.   TNameRule = class (TObject)
  89.   private
  90.     FName: PString;
  91.     FRule: PString;
  92.   protected
  93.     function GetName: string;
  94.     function GetRule: string;
  95.     procedure SetName(const Value: String);
  96.     procedure SetRule(const Value: String);
  97.   public
  98.     constructor Create(const aName, aRule: string);
  99.     destructor Destroy; override;
  100.     property Name: string read GetName write SetName;
  101.     property Rule: string read GetRule write SetRule;
  102.   end;
  103.  
  104.   TNameRuleList = class (TCollection)
  105.   private
  106.     FDefaultRule: string;
  107.   protected
  108.     function GetNameRules(Index: Integer): TNameRule;
  109.   public
  110.     constructor Create;
  111.     destructor Destroy; override;
  112.     function Compare(Key1, Key2: Pointer): Integer; override;
  113.     function FindRule(Component: TComponent): string;
  114.     function KeyOf(Instance: Pointer): Pointer; override;
  115.     procedure LoadFromFile(const FileName: string);
  116.     property DefaultRule: string read FDefaultRule write FDefaultRule;
  117.     property NameRules[Index: Integer]: TNameRule read GetNameRules;
  118.   end;
  119.  
  120.   TRenamer = class (TComponent)
  121.   private
  122.     FActiveForm: TForm;
  123.     FDesigner: TDesignerDecorator;
  124.     FFileName: string;
  125.     FList: TList;
  126.     FPrevActiveFormChange: TNotifyEvent;
  127.     FRules: TNameRuleList;
  128.     FScreenHooked: Boolean;
  129.     FTimer: TTimer;
  130.     procedure Log;
  131.     procedure UpdateTimer;
  132.   protected
  133.     procedure ActiveFormChange(Sender: TObject);
  134.     function ApplyRule(Component: TComponent; const Rule: string): string;
  135.     procedure DesignerNotification(Sender: TObject; AComponent: TComponent; Operation: 
  136.         TOperation);
  137.     procedure DesignerUnhookError(Sender: TObject);
  138.     procedure DesignerValidateRename(Sender: TObject; AComponent: TComponent; const 
  139.         CurName, NewName: string);
  140.     function FilterName(const Orig: string): string;
  141.     function GetPropertyValue(Component: TComponent; AName: String): string;
  142.     function IsreservedWord(const AName: string): Boolean;
  143.     function RemoveTag(const Fmt: string): string;
  144.     procedure SetActiveForm(Value: TForm);
  145.     procedure SetFileName(const Value: String);
  146.     procedure SetPropValue(aObject: TObject; const aProp, aValue: string);
  147.     function TestName(Component: TComponent; const AName: string): Boolean;
  148.     procedure TimerTick(Sender: TObject);
  149.     function UniqueName(Component: TComponent): string;
  150.     procedure UnwireDesigner;
  151.     procedure UpdateActiveForm;
  152.     procedure WireDesigner;
  153.   public
  154.     constructor Create(AOwner: TComponent); override;
  155.     destructor Destroy; override;
  156.     property ActiveForm: TForm read FActiveForm write SetActiveForm;
  157.     property Designer: TDesignerDecorator read FDesigner;
  158.     property Rules: TNameRuleList read FRules;
  159.   published
  160.     property FileName: string read FFileName write SetFileName;
  161.   end;
  162.  
  163.  
  164. const 
  165.   FRenamer: TRenamer = nil;
  166.   RuleFilename = 'NameRule.ini';
  167.   LogFileName = 'NameRule.Log';
  168.  
  169. { Some reserved words (not an extensive list, see Delphi's language guides }
  170.   MAX_RES_WORD = 24;
  171.   SomeResWords : array[1..MAX_RES_WORD] of PChar = 
  172.     ('array',    'case',     'class',    'const',    'constructor', 'destructor',
  173.      'file',     'function', 'inline',   'interface','label',       'library',
  174.      'object',   'procedure','program',  'property', 'record',      'set',
  175.      'string',   'then',     'threadvar','type',     'unit',        'with');
  176.  
  177. procedure Register;
  178. begin
  179.   FRenamer := TRenamer.Create(nil);
  180. end;
  181.  
  182. const
  183.   AlphaNumerics = ['a'..'z', 'A'..'Z', '_', '0'..'9'];
  184.   Letters       = ['a'..'z', 'A'..'Z', '_'];
  185.  
  186. function CheckRule(const Rule: string): Integer;
  187. begin
  188.   { Result returns the position at which an error was found, 
  189.     or 0 if the rule is OK }
  190.   Result := 1;
  191.   if (Length(Rule) <= 0) or not (Rule[1] in (Letters + ['%'])) then
  192.     Exit;
  193.   while Result <= Length(Rule) do
  194.   begin
  195.     if Rule[Result] = '%' then
  196.       begin
  197.         if Result = Length(Rule) then
  198.           Exit;
  199.         if not (Rule[Result+1] in ['n', 'N', 't', 'T']) then
  200.           Exit;
  201.         Inc(Result);
  202.       end
  203.       else if not (Rule[Result] in AlphaNumerics) then
  204.         Exit;
  205.     Inc(Result);
  206.   end;
  207.   Result := 0;
  208. end;
  209.  
  210.  
  211. {
  212. *************************************** TNameRule ****************************************
  213. }
  214. constructor TNameRule.Create(const aName, aRule: string);
  215. begin
  216.   inherited Create;
  217.   SetName(aName);
  218.   SetRule(aRule);
  219. end;
  220.  
  221. destructor TNameRule.Destroy;
  222. begin
  223.   DisposeStr(FName);
  224.   DisposeStr(FRule);
  225.   inherited Destroy;
  226. end;
  227.  
  228. function TNameRule.GetName: string;
  229. begin
  230.   Result := StringValue(FName);
  231. end;
  232.  
  233. function TNameRule.GetRule: string;
  234. begin
  235.   Result := StringValue(FRule);
  236. end;
  237.  
  238. procedure TNameRule.SetName(const Value: String);
  239. begin
  240.   AssignStr(FName, Value);
  241. end;
  242.  
  243. procedure TNameRule.SetRule(const Value: String);
  244. begin
  245.   AssignStr(FRule, Value);
  246. end;
  247.  
  248. {
  249. ************************************* TNameRuleList **************************************
  250. }
  251. constructor TNameRuleList.Create;
  252. begin
  253.   inherited Create;
  254.   CanSort := True;
  255.   OwnesItems := True;
  256.   Sorted := True;
  257.   Duplicates := CONTAINR.dupAccept;
  258.   DefaultRule := '%t%N';
  259. end;
  260.  
  261. destructor TNameRuleList.Destroy;
  262. begin
  263.   inherited Destroy;
  264. end;
  265.  
  266. function TNameRuleList.Compare(Key1, Key2: Pointer): Integer;
  267. begin
  268.   Result := CompareText(StringValue(PString(Key1)), StringValue(PString(Key2)));
  269. end;
  270.  
  271. function TNameRuleList.FindRule(Component: TComponent): string;
  272. var
  273.   Index: Integer;
  274.   Name: string;
  275. begin
  276.   Name := Component.ClassName;
  277.   if FindKey(@Name, Index) then
  278.     Result := NameRules[Index].Rule
  279.   else
  280.     Result := DefaultRule;
  281. end;
  282.  
  283. function TNameRuleList.GetNameRules(Index: Integer): TNameRule;
  284. begin
  285.   Result := TNameRule(Items[Index]);
  286. end;
  287.  
  288. function TNameRuleList.KeyOf(Instance: Pointer): Pointer;
  289. begin
  290.   Result := TNameRule(Instance).FName;
  291. end;
  292.  
  293. procedure TNameRuleList.LoadFromFile(const FileName: string);
  294. var
  295.   IniFile: TIniFile;
  296.   I: Integer;
  297.   FSection: TStringList;
  298.   procedure EntryToRule(Entry: string);
  299.   var P: Integer;
  300.       Rule, Name: String;
  301.   begin
  302.     Entry := DelWhiteSpace(Entry);
  303.     P := Pos('=', Entry);
  304.     if P > 0 then
  305.     begin
  306.       Rule := Copy(Entry, P + 1, 255);
  307.       Name := Copy(Entry, 1, P - 1);
  308.       if IsValidIdent(Name) and (CheckRule(Rule) = 0) then
  309.         if CompareText( 'Default', Name) = 0 then
  310.           DefaultRule := Rule
  311.         else
  312.           Add(TNameRule.Create(Name, Rule));
  313.     end;
  314.   end;
  315. begin
  316.   Clear;
  317.   if FileExists (FileName) then
  318.   begin
  319.     IniFile := TIniFile.Create(FileName);
  320.     FSection := TStringList.Create;
  321.     try
  322.       IniFile.ReadSectionValues('NameRules', FSection);
  323.       for I := 0 to FSection.Count -1 do
  324.         EntryToRule(FSection[I]);
  325.     finally
  326.       FSection.Free;
  327.       IniFile.Free;
  328.     end;
  329.   end;
  330. end;
  331.  
  332. {
  333. **************************************** TRenamer ****************************************
  334. }
  335. constructor TRenamer.Create(AOwner: TComponent);
  336. begin
  337.   inherited Create(AOwner);
  338.   FDesigner := TDesignerDecorator.Create;
  339.   FList := TList.Create;
  340.   FRules := TNameRuleList.Create;
  341.   FTimer := TTimer.Create(Self);
  342.   WireDesigner;
  343.   FileName := CommandPath + RuleFileName;
  344.   FTimer.OnTimer := TimerTick;
  345.   FTimer.Interval := 55;
  346.   { Use the first tick to log the current rules }
  347.   FTimer.Enabled := True;
  348.   { hook on to the screen }
  349.   FPrevActiveFormChange := Screen.OnActiveFormChange;
  350.   Screen.OnActiveFormChange := ActiveFormChange;
  351.   FScreenHooked := True;
  352. end;
  353.  
  354. destructor TRenamer.Destroy;
  355. begin
  356.   try
  357.     if FScreenHooked then
  358.       Screen.OnActiveFormChange := FPrevActiveFormChange;
  359.   except
  360.     { Screen alreasy gone, therefore no need to unhook and we can ignore EGPFaults }
  361.     on EGPFault do;
  362.   end;
  363.   FTimer.Enabled := False;
  364.   FList.Clear;
  365.   UnwireDesigner;
  366.   FDesigner.Free;
  367.   FList.Free;
  368.   FRules.Free;
  369.   inherited Destroy;
  370. end;
  371.  
  372. procedure TRenamer.ActiveFormChange(Sender: TObject);
  373. begin
  374.   if Assigned(FPrevActiveFormChange) then FPrevActiveFormChange(Sender);
  375.   UpdateActiveForm;
  376. end;
  377.  
  378. function TRenamer.ApplyRule(Component: TComponent; const Rule: string): string;
  379. var
  380.   Optional: Boolean;
  381.   Fmt: string;
  382.   I, J: Integer;
  383. begin
  384.   Optional := False;
  385.   Fmt := '';
  386.   Result := '';
  387.   I := 1;
  388.   while I < Length(Rule) do
  389.   begin
  390.     if (Rule[I] <> '%') or (I = Length(Rule)) then
  391.       AppendStr(Fmt, Rule[I])
  392.     else
  393.     begin
  394.       Inc(I);
  395.       case Rule[I] of
  396.       'n': { unique number }
  397.         AppendStr(Fmt, '%d');
  398.       'N': { optional unique number }
  399.         begin
  400.           AppendStr(Fmt, '%d');
  401.           Optional := True;
  402.         end;
  403.       't': { type name without the leading T }
  404.         if Component.ClassName[1] in ['t', 'T'] then
  405.           AppendStr(Fmt, Copy(Component.ClassName, 2, 255))
  406.         else
  407.           AppendStr(Fmt, Component.ClassName);
  408.       'T': { complete type name }
  409.         AppendStr(Fmt, Component.ClassName);
  410.       else
  411.         AppendStr(Fmt, '%' + Rule[I]);
  412.       end;
  413.     end;
  414.     Inc(I);
  415.   end; { while }
  416.   
  417.   { Remove all invalid characters from the name. }
  418.   Fmt := FilterName(Fmt);
  419.   
  420.   { If there is no %d in the format, then append it, but mark it as optional. }
  421.   if Pos('%d', Fmt) = 0 then
  422.   begin
  423.     AppendStr(Fmt, '%d');
  424.     Optional := True;
  425.   end;
  426.   
  427.   { Now try to generate a unique name. If the %d is optional, first try
  428.     without it. Then try successive numbers, starting with 1, until a
  429.     unique name is found. If there is no way to create a unique name,
  430.     then raise an exception. ( Imagine 32K components on a form! ) }
  431.   if Optional then
  432.   begin
  433.     Result := RemoveTag(Fmt);
  434.     if TestName(Component, Result) then
  435.       Exit;
  436.   end;
  437.   
  438.   for I := 1 to High(Integer) do
  439.   begin
  440.     Result := Format(Fmt, [I]);
  441.     if TestName(Component, Result) then
  442.       Exit;
  443.   end;
  444.   
  445.   raise Exception.CreateFmt('Unable to apply naming rules for %s', [Component.ClassName]);
  446. end;
  447.  
  448. procedure TRenamer.DesignerNotification(Sender: TObject; AComponent: TComponent; 
  449.     Operation: TOperation);
  450. begin
  451.   if Operation = opRemove then
  452.   begin
  453.     FList.Remove(AComponent);
  454.     UpdateTimer;
  455.   end;
  456. end;
  457.  
  458. procedure TRenamer.DesignerUnhookError(Sender: TObject);
  459. begin
  460.   Application.MessageBox(
  461.      'Name Rule designer unhook error. Remove the unit CMPNAMES fomr your VCL',
  462.       nil, MB_ICONHAND or MB_OK);
  463. end;
  464.  
  465. procedure TRenamer.DesignerValidateRename(Sender: TObject; AComponent: TComponent; const 
  466.     CurName, NewName: string);
  467.   function StandardName: Boolean;
  468.   begin
  469.     Result := (CompareText(Copy(AComponent.ClassName, 2, 255), GetTemplate(NewName)) = 0);
  470.   end;
  471. begin
  472.   { do NOT trigger on insertion, instead trigger on the IDE renaming a component
  473.     which results in a ValidateRename call }
  474.   if (Length(CurName) = 0) and (Length(NewName) > 0) and StandardName then
  475.   { trigger }
  476.     if FList.IndexOf(AComponent) = -1 then
  477.     begin
  478.       FList.Add(AComponent);
  479.       UpdateTimer;
  480.     end;
  481. end;
  482.  
  483. function TRenamer.FilterName(const Orig: string): string;
  484. var
  485.   I: Integer;
  486. begin
  487.   Result := '';
  488.   for I := 1 to Length(Orig) do
  489.     if (Orig[I] = '%') and (I < Length(Orig)) and (Orig[I+1] = 'd') then
  490.       AppendStr(Result, Orig[I])
  491.     else
  492.       if Orig[I] in AlphaNumerics then AppendStr(Result, Orig[I]);
  493.   if (Length(Result) = 0) or not (Result[1] in Letters) then
  494.     Result := '_' + Result;
  495. end;
  496.  
  497. function TRenamer.GetPropertyValue(Component: TComponent; AName: String): string;
  498. var
  499.   PropInfo: PPropInfo;
  500. begin
  501.   Result := '';
  502.   PropInfo := GetPropInfo(Component.ClassInfo, AName);
  503.   if PropInfo = nil then Exit;
  504.   with PropInfo^ do
  505.     case PropType^.Kind of
  506.     {$IFDEF WIN32}
  507.       tkLString,
  508.     {$ENDIF}
  509.       tkString:
  510.         Result := GetStrProp(Component, PropInfo);
  511.       tkInteger:
  512.         Result := IntToStr(GetOrdProp(Component, PropInfo));
  513.       tkChar:
  514.         Result := Chr(GetOrdProp(Component, PropInfo));
  515.       else
  516.         Exit;
  517.       end;
  518. end;
  519.  
  520. function TRenamer.IsreservedWord(const AName: string): Boolean;
  521. var
  522.   Ident: array[0..255] of Char;
  523.   I: Integer;
  524. begin
  525.   StrPCopy(Ident, LowerCase(AName));
  526.   for I := 1 to MAX_RES_WORD do
  527.     if StrComp(Ident, SomeResWords[I]) = 0 then
  528.     begin
  529.       Result := True;
  530.       Exit;
  531.     end;
  532.   Result := False;
  533. end;
  534.  
  535. procedure TRenamer.Log;
  536. var
  537.   T: TTextFile;
  538.   ModuleNum, CompNum: Integer;
  539.   CompName: String[63];
  540.   Index: Integer;
  541.   Ruled, Unruled: TStringList;
  542.   const IsLogged: Boolean = False;
  543. begin
  544.   if IsLogged then Exit;
  545.   IsLogged := True;
  546.   try
  547.     try
  548.       T := TTextFile.Create(CommandPath + LogFileName, tmCreate);
  549.       try
  550.         T.WriteLine('[Default rule]');
  551.         T.WriteLnFmt('Default=%s', [FRules.DefaultRule]);
  552.         T.Newline;
  553.   
  554.         Ruled := TStringList.Create;
  555.         Unruled := TStringList.Create;
  556.         try
  557.           Ruled.Sorted := True;
  558.           Unruled.Sorted := True;
  559.   
  560.           with AppBuilder.GetToolServices do
  561.             for ModuleNum := 0 to GetModuleCount - 1 do
  562.               for CompNum := 0 to GetComponentCount(ModuleNum) - 1 do
  563.               begin
  564.                 CompName := GetComponentName(ModuleNum, CompNum);
  565.                 if FRules.FindKey(@CompName, Index) then
  566.                   Ruled.Add(Format('%s=%s', [CompName, FRules.NameRules[Index].Rule]))
  567.                 else
  568.                   Unruled.Add(Format('%s=%s', [CompName, FRules.DefaultRule]));
  569.               end;
  570.   
  571.           T.WriteLine('[Components to which a name rule applies]');
  572.           for Index := 0 to Ruled.Count-1 do T.WriteLine(Ruled[Index]);
  573.   
  574.           T.NewLine;
  575.   
  576.           T.WriteLine('[Components to which the default name rule applies]');
  577.           for Index := 0 to Unruled.Count-1 do T.WriteLine(Unruled[Index]);
  578.   
  579.         finally
  580.           Ruled.Free;
  581.           Unruled.Free;
  582.         end;
  583.       finally
  584.         T.Free;
  585.       end;
  586.     except
  587.       Application.MessageBox('Error logging name rules', nil, MB_ICONHAND or MB_OK);
  588.     end;
  589.   finally
  590.     UpdateTimer;
  591.   end;
  592. end;
  593.  
  594. function TRenamer.RemoveTag(const Fmt: string): string;
  595. var
  596.   Index: Integer;
  597. begin
  598.   Index := Pos('%d', Fmt);
  599.   if Index = 0 then
  600.     Result := Fmt
  601.   else
  602.     Result := Copy(Fmt, 1, Index - 1) + Copy(Fmt, Index + 2, 255);
  603. end;
  604.  
  605. procedure TRenamer.SetActiveForm(Value: TForm);
  606. var
  607.   Str: string;
  608. begin
  609.   if Value <> FActiveForm then
  610.   begin
  611.     { do not affect components any more: clear list }
  612.     FList.Clear;
  613.     FTimer.Enabled := False;
  614.     FActiveForm := Value;
  615.     Designer.Hook(FActiveForm);
  616.   end;
  617. end;
  618.  
  619. procedure TRenamer.SetFileName(const Value: String);
  620. begin
  621.   if FFileName <> Value then
  622.   begin
  623.     FFileName := Value;
  624.     FRules.LoadFromFile(FFileName);
  625.   end;
  626. end;
  627.  
  628. procedure TRenamer.SetPropValue(aObject: TObject; const aProp, aValue: string);
  629. var
  630.   PropInfo: PPropInfo;
  631. begin
  632.   PropInfo := GetPropInfo(aObject.ClassInfo, aProp);
  633.   if PropInfo <> nil then
  634.     SetStrProp(aObject, PropInfo, aValue);
  635. end;
  636.  
  637. function TRenamer.TestName(Component: TComponent; const AName: string): Boolean;
  638. var
  639.   Cmp: TComponent;
  640. begin
  641.   if Component.Owner = nil then
  642.     Cmp := nil
  643.   else
  644.     Cmp := Component.Owner.FindComponent(AName);
  645.   Result := IsValidIdent(AName) and not IsReservedWord(AName) and
  646.             ((Cmp = nil) or (Cmp = Component));
  647. end;
  648.  
  649. procedure TRenamer.TimerTick(Sender: TObject);
  650. var
  651.   Modified: Boolean;
  652.   I: Integer;
  653.   NewName: string;
  654.   Comp: TComponent;
  655.   DefaultCaption: string;
  656. begin
  657.   FTimer.Enabled := False;
  658.   Log;
  659.   Modified := False;
  660.   try
  661.     for I := 0 to FList.Count - 1 do
  662.     begin
  663.       NewName := UniqueName(FList[I]);
  664.       try
  665.         if Length(NewName) > 0 then
  666.         begin
  667.           Comp := TComponent(FList[I]);
  668.           Comp.Name := NewName;
  669.           if (Comp is TControl) and (csSetCaption in TControl(Comp).ControlStyle) then
  670.           begin
  671.             DefaultCaption := Comp.ClassName;
  672.             if DefaultCaption[1] in ['t', 'T'] then
  673.               Delete(DefaultCaption, 1, 1);
  674.             if CompareText(GetTemplate(GetPropertyValue(Comp, 'Caption')),
  675.                            DefaultCaption) = 0 then
  676.             begin
  677.               SetPropValue(TObject(FList[I]), 'Caption', NewName);
  678.               SetPropValue(TObject(FList[I]), 'Text', NewName);
  679.             end;
  680.           end;
  681.           Modified := True;
  682.         end;
  683.       finally
  684.         FList[I] := nil;
  685.       end;
  686.     end;
  687.   finally
  688.     FList.Pack;
  689.     if Modified then FDesigner.Modified;
  690.     UpdateTimer;
  691.   end;
  692. end;
  693.  
  694. function TRenamer.UniqueName(Component: TComponent): string;
  695. begin
  696.   Result := FRules.FindRule( Component);
  697.   if Length( Result) > 0 then
  698.     Result := ApplyRule( Component, Result);
  699. end;
  700.  
  701. procedure TRenamer.UnwireDesigner;
  702. begin
  703.   FDesigner.OnNotification := nil;
  704.   FDesigner.OnValidateRename := nil;
  705.   FDesigner.OnUnhookError := nil;
  706. end;
  707.  
  708. procedure TRenamer.UpdateActiveForm;
  709. var
  710.   F: TForm;
  711. begin
  712.   F := Screen.ActiveForm;
  713.   if Assigned(F) and (csDesigning in F.ComponentState)  then
  714.     ActiveForm := F
  715.   else
  716.     ActiveForm := nil;
  717. end;
  718.  
  719. procedure TRenamer.UpdateTimer;
  720. begin
  721.   FTimer.Enabled := FList.Count > 0;
  722. end;
  723.  
  724. procedure TRenamer.WireDesigner;
  725. begin
  726.   FDesigner.OnNotification := DesignerNotification;
  727.   FDesigner.OnValidateRename := DesignerValidateRename;
  728.   FDesigner.OnUnhookError := DesignerUnhookError;
  729. end;
  730.  
  731.  
  732. procedure Terminate; far;
  733. begin
  734.   FRenamer.Free;
  735. end;
  736.  
  737. initialization
  738. {
  739.   RegisterStreamable(TNameRuleList);
  740. }
  741.   AddExitProc(Terminate);
  742. end.
  743.  
  744.