I write a component which should store some information relative to the project directory. Every time a property of my component is changed it should write a file. So how can a component determine the current project directory at design time.
Thanks in advance
EDIT:
I want to generate a delphi source file every time a property of my component is changed, so that I always get the latest version when I compile my code. Think of it as a kind of code generator.
At the moment I set whole path and filename where the source should be stored but I prefer a relative path to the project (or the form/datamodule which contains my component) to make it easier to copy the project on different developer machines.
Thanks for the hints. Open Tools API is the way to go and using the Open Tools API from a component on a form at designtime is possible.
So here is my solution:
I need two units, one for the component and one for registering the component and the code which use the Open Tools API.
Here comes the component unit:
unit TestLabels;
interface
uses
SysUtils, Classes, Windows, Controls, StdCtrls;
type
TTestLabel = class(TLabel)
private
FTestProperty: Boolean;
procedure SetTestProperty(const Value: Boolean);
procedure Changed;
published
property TestProperty: Boolean read FTestProperty write SetTestProperty;
end;
var
OnGetUnitPath: TFunc;
implementation
{ TTestLabel }
procedure TTestLabel.Changed;
begin
if not (csDesigning in ComponentState) then
Exit; // I only need the path at designtime
if csLoading in ComponentState then
Exit; // at this moment you retrieve the unit path which was current before
if not Assigned(OnGetUnitPath) then
Exit;
// only for demonstration
Caption := OnGetUnitPath;
MessageBox(0, PChar(ExtractFilePath(OnGetUnitPath)), 'Path of current unit', 0);
end;
procedure TTestLabel.SetTestProperty(const Value: Boolean);
begin
if FTestProperty Value then
begin
FTestProperty := Value;
Changed;
end;
end;
end.
Here is the unit for registering the component and the call to the Open Tools API:
unit TestLabelsReg;
interface
uses
SysUtils, Classes, Controls, StdCtrls, TestLabels;
procedure register;
implementation
uses
ToolsAPI;
function GetCurrentUnitPath: String;
var
ModuleServices: IOTAModuleServices;
Module: IOTAModule;
SourceEditor: IOTASourceEditor;
idx: integer;
begin
Result := '';
SourceEditor := nil;
if SysUtils.Supports(BorlandIDEServices, IOTAModuleServices,
ModuleServices) then
begin
Module := ModuleServices.CurrentModule;
if System.Assigned(Module) then
begin
idx := Module.GetModuleFileCount - 1;
// Iterate over modules till we find a source editor or list exhausted
while (idx >= 0) and not SysUtils.Supports(Module.GetModuleFileEditor(idx), IOTASourceEditor, SourceEditor) do
System.Dec(idx);
// Success if list wasn't ehausted.
if idx >= 0 then
Result := ExtractFilePath(SourceEditor.FileName);
end;
end;
end;
procedure register;
begin
RegisterComponents('Samples', [TTestLabel]);
TestLabels.OnGetUnitPath := GetCurrentUnitPath;
end;
end.