Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a component at designtime determine the project directory

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.

like image 421
Heinz Z. Avatar asked Mar 12 '10 15:03

Heinz Z.


Video Answer


3 Answers

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.
like image 153
Heinz Z. Avatar answered Sep 26 '22 02:09

Heinz Z.


Starting with delphi 7, the ToolsAPI unit defines a getActiveProject function which returns the IOTAProject interface of the current project.

The fileName property of IOTAProject returns the full path of the main source file of the project (typically the .dpr file).

So, in many cases, it's possible to use a simple instruction such as:

if csDesigning in componentState then
    appFolderPath := extractFilePath( getActiveProject.fileName ) 
else
    appFolderPath := extractFilePath( application.exeName );

(and there's no need of using two units as in Heinz's example above)

like image 29
jes Avatar answered Sep 24 '22 02:09

jes


A component cannot access your source path, because a component is placed in your application and run as a part of your application out of Delphi IDE.

If you want to have access to project path, or automate any process inside IDE; you have to write an IDE expert using OpenTools API, not a component.

like image 42
vcldeveloper Avatar answered Sep 24 '22 02:09

vcldeveloper