dexed/src/ce_project.pas

292 lines
7.3 KiB
Plaintext

unit ce_project;
{$mode objfpc}{$H+}
interface
// TODO: configuration templates
uses
Classes, SysUtils, ce_dmdwrap;
type
(*****************************************************************************
* Represents a D project.
*
* It includes all the options defined in ce_dmdwrap, organized in
* a collection to allow multiples configurations.
*
* Basically it' s designed to provide the options for the dmd process.
*)
TCEProject = class(TComponent)
private
fOnChange: TNotifyEvent;
fModified: boolean;
fFilename: string;
fBasePath: string;
fOptsColl: TCollection;
fSrcs, fSrcsCop: TStringList;
fConfIx: Integer;
fChangedCount: NativeInt;
procedure doChanged;
procedure subMemberChanged(sender : TObject);
procedure setOptsColl(const aValue: TCollection);
procedure setFname(const aValue: string);
procedure setSrcs(const aValue: TStringList);
procedure setConfIx(aValue: Integer);
function getConfig(const ix: integer): TCompilerConfiguration;
function getCurrConf: TCompilerConfiguration;
procedure readerPropNoFound(Reader: TReader; Instance: TPersistent;
var PropName: string; IsPath: boolean; var Handled, Skip: Boolean);
procedure readerError(Reader: TReader; const Message: string;
var Handled: Boolean);
published
property OptionsCollection: TCollection read fOptsColl write setOptsColl;
property Sources: TStringList read fSrcs write setSrcs; // 'read' should return a copy to avoid abs/rel errors
property ConfigurationIndex: Integer read fConfIx write setConfIx;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
procedure beforeChanged;
procedure afterChanged;
procedure reset;
function getAbsoluteSourceName(const aIndex: integer): string;
function getAbsoluteFilename(const aFilename: string): string;
procedure addSource(const aFilename: string);
function addConfiguration: TCompilerConfiguration;
procedure getOpts(const aList: TStrings);
procedure saveToFile(const aFilename: string);
procedure loadFromFile(const aFilename: string);
//
property configuration[ix: integer]: TCompilerConfiguration read getConfig;
property currentConfiguration: TCompilerConfiguration read getCurrConf;
property fileName: string read fFilename write setFname;
property onChange: TNotifyEvent read fOnChange write fOnChange;
property modified: boolean read fModified;
end;
implementation
uses
ce_common, dialogs;
constructor TCEProject.create(aOwner: TComponent);
begin
inherited create(aOwner);
fSrcs := TStringList.Create;
fSrcs.OnChange := @subMemberChanged;
fSrcsCop := TStringList.Create;
fOptsColl := TCollection.create(TCompilerConfiguration);
reset;
fModified := false;
end;
destructor TCEProject.destroy;
begin
fOnChange := nil;
fSrcs.free;
fSrcsCop.Free;
fOptsColl.free;
inherited;
end;
function TCEProject.addConfiguration: TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Add);
result.onChanged := @subMemberChanged;
end;
procedure TCEProject.setOptsColl(const aValue: TCollection);
var
i: nativeInt;
begin
fOptsColl.Assign(aValue);
for i:= 0 to fOptsColl.Count-1 do
Configuration[i].onChanged := @subMemberChanged;
end;
procedure TCEProject.addSource(const aFilename: string);
var
relSrc, absSrc: string;
begin
for relSrc in fSrcs do
begin
absSrc := expandFilenameEx(fBasePath,relsrc);
if aFilename = absSrc then exit;
end;
fSrcs.Add(ExtractRelativepath(fBasePath,aFilename));
end;
procedure TCEProject.setFname(const aValue: string);
var
oldAbs, newRel, oldBase: string;
i: NativeInt;
begin
if fFilename = aValue then exit;
//
beforeChanged;
fFilename := aValue;
oldBase := fBasePath;
fBasePath := extractFilePath(fFilename);
//
for i:= 0 to fSrcs.Count-1 do
begin
oldAbs := expandFilenameEx(oldBase,fSrcs[i]);
newRel := ExtractRelativepath(fBasePath, oldAbs);
fSrcs[i] := newRel;
end;
//
afterChanged;
end;
procedure TCEProject.setSrcs(const aValue: TStringList);
begin
beforeChanged;
fSrcs.Assign(aValue);
patchPlateformPaths(fSrcs);
afterChanged;
end;
procedure TCEProject.setConfIx(aValue: Integer);
begin
if fConfIx = aValue then exit;
beforeChanged;
if aValue < 0 then aValue := 0;
if aValue > fOptsColl.Count-1 then aValue := fOptsColl.Count-1;
fConfIx := aValue;
afterChanged;
end;
procedure TCEProject.subMemberChanged(sender : TObject);
begin
beforeChanged;
fModified := true;
afterChanged;
end;
procedure TCEProject.beforeChanged;
begin
Inc(fChangedCount);
end;
procedure TCEProject.afterChanged;
begin
Dec(fChangedCount);
if fChangedCount > 0 then
begin
{$IFDEF DEBUG}
writeln('project update count > 0');
{$ENDIF}
exit;
end;
fChangedCount := 0;
doChanged;
end;
procedure TCEProject.doChanged;
{$IFDEF DEBUG}
var
lst: TStringList;
{$ENDIF}
begin
fModified := true;
if assigned(fOnChange) then fOnChange(Self);
{$IFDEF DEBUG}
lst := TStringList.Create;
try
lst.Add('---------begin----------');
getOpts(lst);
lst.Add('---------end-----------');
writeln(lst.Text);
finally
lst.Free;
end;
{$ENDIF}
end;
function TCEProject.getConfig(const ix: integer): TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Items[ix]);
result.onChanged := @subMemberChanged;
end;
function TCEProject.getCurrConf: TCompilerConfiguration;
begin
result := TCompilerConfiguration(fOptsColl.Items[fConfIx]);
end;
procedure TCEProject.reset;
var
defConf: TCompilerConfiguration;
begin
beforeChanged;
fConfIx := 0;
fOptsColl.Clear;
defConf := addConfiguration;
defConf.name := 'default';
fSrcs.Clear;
fFilename := '';
afterChanged;
fModified := false;
end;
procedure TCEProject.getOpts(const aList: TStrings);
var
rel, abs: string;
begin
if fConfIx = -1 then exit;
for rel in fSrcs do if rel <> '' then
begin
abs := expandFilenameEx(fBasePath,rel);
aList.Add(abs); // process.inc ln 249. double quotes are added anyway if there's a space...
end;
TCompilerConfiguration(fOptsColl.Items[fConfIx]).getOpts(aList);
end;
function TCEProject.getAbsoluteSourceName(const aIndex: integer): string;
begin
if aIndex < 0 then exit('');
if aIndex > fSrcs.Count-1 then exit('');
result := expandFileNameEx(fBasePath, fSrcs.Strings[aIndex]);
end;
function TCEProject.getAbsoluteFilename(const aFilename: string): string;
begin
result := expandFileNameEx(fBasePath, aFilename);
end;
procedure TCEProject.saveToFile(const aFilename: string);
begin
saveCompToTxtFile(self, aFilename);
fModified := false;
end;
procedure TCEProject.loadFromFile(const aFilename: string);
begin
Filename := aFilename;
loadCompFromTxtFile(self, aFilename, @readerPropNoFound, @readerError);
patchPlateformPaths(fSrcs);
doChanged;
fModified := false;
end;
procedure TCEProject.readerPropNoFound(Reader: TReader; Instance: TPersistent;
var PropName: string; IsPath: boolean; var Handled, Skip: Boolean);
begin
// continue loading: this method grants the project compat. in case of drastic changes.
Skip := true;
Handled := true;
end;
procedure TCEProject.readerError(Reader: TReader; const Message: string;
var Handled: Boolean);
begin
Handled := true;
end;
initialization
RegisterClasses([TCEProject]);
end.