Angus Robertson 574 Posted August 10 When you drop a component on a form, the IDE automatically adds the unit to the uses clause. Is there a way for that component to get the IDE to also add a second unit on which it is dependent? Angus Share this post Link to post
msohn 28 Posted August 10 (edited) Yes there is. Have a look at TSelectionEditor and its RequiresUnits method: https://docwiki.embarcadero.com/Libraries/Alexandria/en/DesignEditors.TSelectionEditor Many 3rd party products do this (e.g. DevExpress) especially when components have event handlers containing types that are defined in another unit. Because adding such an event handler will otherwise break compiling and the user going on a hunt for the unit. Edited August 10 by msohn Share this post Link to post
Angus Robertson 574 Posted August 10 That is exactly what I need, and for that reason, but this if for dozens of existing components and I assume they would need to be changed to be derived from TSelectionEditor. I also need compatibility with Delphi 2007 and later, ideally. Angus Share this post Link to post
Uwe Raabe 2058 Posted August 10 1 minute ago, Angus Robertson said: but this if for dozens of existing components and I assume they would need to be changed to be derived from TSelectionEditor. No, the actual components don't have to be derived from TSelectionEditor. That would probably be near to impossible, as it would require to use design-time code in the application. Instead you need to register a TSelectionEditor descendant for each of these components and implement the RequiresUnits as appropriate. Share this post Link to post
Angus Robertson 574 Posted August 10 Thanks Uwe, will try this next week. Angus Share this post Link to post
Remy Lebeau 1400 Posted August 10 (edited) Yes, TSelectionEditor is the way to go. When a unit is saved or compiled, the IDE first invokes any registered TSelectionEditor classes relevant to that unit, calling their RequiredUnits() methods to update the 'uses' clause. Indy registers several TSelectionEditor classes for a few specific cases. But, I want to point out 1 editor in particular: TIdBaseComponentSelectionEditor. It is registered for TIdBaseComponent, which all Indy components are derived from. TIdBaseComponentSelectionEditor iterates all Indy components on a Form, using RTTI to look for any event handlers that are assigned to those components, and then to determine the types of any parameters and return values of those event handlers, and the unit names that those types belong to. It then reports those units to the IDE to add to the 'uses' clause. Now, one would think this is something that the IDE itself should handle automatically for all components, but it doesn't, or at least not completely. Which is why TIdBaseComponentSelectionEditor was created, instead of having to define a separate TSelectionEditor for each individual component that needs it. I mention this because Indy has a LOT of components, so it makes sense to handle something like this in a central place. So, if you don't want to write a bunch of smaller editors for multiple components in your library, you might consider a similar approach (although handling RTTI differences across multiple IDE versions can be a bit of a task). Edited August 10 by Remy Lebeau 1 Share this post Link to post
Angus Robertson 574 Posted August 10 ICS now only needs to add two units to meet almost all event handler type needs. Users of old compilers can not always get the same features as newer compilers, so may have to add uses manually, as everyone has for 25 years. There is an argument for only supporting new compilers, but I still have a commercial application using Delphi 2007, so support for that will not be dropped any time soon Angus Share this post Link to post
Angus Robertson 574 Posted August 12 Added a few lines to the ICS design package registration unit, and two extra units are now being added automatically when components are dropped on forms, or those forms are accessed in the IDE. Would not have been possible without a Stack Overflow answer by Remy Lebeau, Aug 19, 2020: Have your design-time package implement a class that inherits from TSelectionEditor and overrides its virtual RequiresUnits() method, and then register that class for your component using RegisterSelectionEditor(). This way, whenever you place your component onto a Form/Frame/DataModule Designer at design-time, any additional units you report from RequiresUnits() will be added automatically to that unit's uses clause when the unit is saved. uses ..., DesignIntf; type TWebBrowserWrapperSelectionEditor = class(TSelectionEditor) public procedure RequiresUnits(Proc: TGetStrProc); override; end; procedure TWebBrowserWrapperSelectionEditor.RequiresUnits(Proc: TGetStrProc); begin inherited RequiresUnits(Proc); // call Proc() for each additional unit you want added... Proc('MyWrapperUnit'); Proc('MyUtilityUnit'); end; procedure Register; begin RegisterComponents('My Wrappers', [TWebBrowserWrapper]); RegisterSelectionEditor(TWebBrowserWrapper, TWebBrowserWrapperSelectionEditor); end; Angus Share this post Link to post