cmdlinecfg:

* minimized TCmdLineLayoutInfo class public section;
* updated the TCmdLineScrollBoxControl loader to use %%other switch; using hash list to check of used/unused controls;
* updated readme.txt description for UI layout controls;
* updated IDE package to make the dialog look close to the existing compiler options;
* updated testguibuild to be able to load a certain section only;
* added smaller sample files for testguibuild, modified conf.coptui to have %%other switch, where all "non-default" compiler options would go;

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2806 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
skalogryz
2013-10-12 17:15:48 +00:00
parent c63c5bb6b7
commit 33dadcd154
15 changed files with 474 additions and 148 deletions

View File

@ -3,8 +3,7 @@ unit cmdlinecfgui;
interface interface
uses uses
Classes, SysUtils, Classes, SysUtils, contnrs, cmdlinecfg;
cmdlinecfg;
type type
{ TCmdLineLayoutInfo } { TCmdLineLayoutInfo }
@ -15,6 +14,7 @@ type
{ TLayoutSection } { TLayoutSection }
TLayoutElementType = (letSwitch, letSection); TLayoutElementType = (letSwitch, letSection);
TLayoutElementTypes = set of TLayoutElementType;
TLayoutSection = class(TObject) TLayoutSection = class(TObject)
//level : integer; // number of "dots" in the name //level : integer; // number of "dots" in the name
@ -27,22 +27,17 @@ type
Elements : array of TLayoutSection; Elements : array of TLayoutSection;
ElemCount : integer; ElemCount : integer;
function AddElement(const AName: string; AElementType: TLayoutElementType): TLayoutSection; function AddElement(const AName: string; AElementType: TLayoutElementType): TLayoutSection;
constructor Create(const AName: string = ''; AElementType: TLayoutElementType = letSection);
destructor Destroy; override; destructor Destroy; override;
property Name: string read fName; property Name: string read fName;
property ElementType: TLayoutElementType read fElementType; property ElementType: TLayoutElementType read fElementType;
end; end;
TCmdLineLayoutInfo = class(TObject) TCmdLineLayoutInfo = class(TObject)
private
fSections: TStringList;
fValidOrder: Boolean;
function DoGetSection(const SectName: String; Forced: Boolean = true): TLayoutSection;
public public
RootElement : TLayoutSection;
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
function AddSection(const Section: string): TLayoutSection;
function GetSection(const Section: string): TLayoutSection;
//function GetSwitches(const Section: string; Dst: TStrings): Boolean;
end; end;
{ TCmdLineUIControl } { TCmdLineUIControl }
@ -53,14 +48,94 @@ type
protected protected
procedure ValueChanged; virtual; procedure ValueChanged; virtual;
public public
procedure Init(cfg: TCmdLineCfg; layout: TCmdLineLayoutInfo); virtual; abstract; procedure Init(cfg: TCmdLineCfg; layout: TCmdLineLayoutInfo; const ASection : string = ''); virtual; abstract;
procedure SetValues(list: TList {of TCmdLineOptionValue}); virtual; abstract; procedure SetValues(list: TList {of TCmdLineOptionValue}); virtual; abstract;
procedure Serialize(list: TList {of TCmdLineOptionValue}); virtual; abstract; procedure Serialize(list: TList {of TCmdLineOptionValue}); virtual; abstract;
property OnValueChanged: TNotifyEvent read FValueChanged write fValueChanged; property OnValueChanged: TNotifyEvent read FValueChanged write fValueChanged;
end; end;
function LayoutFindElement(aparent: TLayoutSection; const Name: string; LookFor: TLayoutElementTypes = [letSection] ): TLayoutSection;
procedure LayoutEnumElement(aparent: TLayoutSection; list: TList; LookFor: TLayoutElementTypes = [letSection] );
procedure LayoutGetUnused(cmd: TCmdLineCfg; layout: TLayoutSection; list: TList);
implementation implementation
procedure LayoutGetSwitches(root: TLayoutSection; hash: TFPHashObjectList);
var
sct : TList;
i : Integer;
j : Integer;
el : TLayoutSection;
sel : TLayoutSection;
begin
sct:=TList.Create;
try
sct.Add(root);
j:=0;
while j<sct.Count do begin
el:=TLayoutSection(sct[j]);
for i:=0 to el.ElemCount-1 do begin
sel:=el.Elements[i];
if sel.ElementType = letSection then
sct.Add(sel)
else begin
hash.Add(sel.Name, sel);
end;
end;
inc(j);
end;
finally
sct.Free;
end;
end;
procedure LayoutEnumElement(aparent: TLayoutSection; list: TList;
LookFor: TLayoutElementTypes);
var
i : integer;
begin
if not Assigned(list) or not Assigned(aparent) or (LookFor = []) then Exit;
for i:=0 to aparent.ElemCount-1 do begin
if aparent.Elements[i].ElementType in LookFor then
list.Add(aparent.Elements[i]);
end;
end;
procedure LayoutGetUnused(cmd: TCmdLineCfg; layout: TLayoutSection; list: TList);
var
i : Integer;
hash : TFPHashObjectList;
opt : TCmdLineCfgOption;
begin
if not Assigned(cmd) or not Assigned(layout) or not Assigned(list) then Exit;
hash := TFPHashObjectList.Create(false);
try
LayoutGetSwitches(layout, hash);
for i:=0 to cmd.Options.Count-1 do begin
opt:=TCmdLineCfgOption(cmd.Options[i]);
if not Assigned(hash.Find(opt.Name)) then begin
list.Add(opt);
end;
end;
finally
hash.Free;
end;
end;
function LayoutFindElement(aparent: TLayoutSection; const Name: string; LookFor: TLayoutElementTypes = [letSection]): TLayoutSection;
var
i : integer;
nm : string;
begin
Result:=nil;
if not Assigned(aparent) or (LookFor = []) then Exit;
nm:=AnsiLowerCase(Name);
for i:=0 to aparent.ElemCount-1 do
if (aparent.Elements[i].fElementType in LookFor) and (AnsiLowerCase(aparent.Elements[i].Name)=nm) then
Result:=aparent.Elements[i];
end;
{ TLayoutSection } { TLayoutSection }
function TLayoutSection.AddElement(const AName: string; AElementType: TLayoutElementType): TLayoutSection; function TLayoutSection.AddElement(const AName: string; AElementType: TLayoutElementType): TLayoutSection;
@ -69,14 +144,20 @@ begin
if ElemCount=0 then SetLength(Elements, 2) if ElemCount=0 then SetLength(Elements, 2)
else SetLength(Elements, ElemCount*2); else SetLength(Elements, ElemCount*2);
end; end;
Result:=TLayoutSection.Create; Result:=TLayoutSection.Create(AName, AElementType);
Result.fName:=AName;
Result.fElementType:=AElementType;
Result.Display:=Aname; Result.Display:=Aname;
Elements[ElemCount]:=Result; Elements[ElemCount]:=Result;
inc(ElemCount); inc(ElemCount);
end; end;
constructor TLayoutSection.Create(const AName: string;
AElementType: TLayoutElementType);
begin
inherited Create;
fName:=AName;
fElementType:=AElementType;
end;
destructor TLayoutSection.Destroy; destructor TLayoutSection.Destroy;
var var
i : integer; i : integer;
@ -86,7 +167,7 @@ begin
end; end;
{ TCmdLineLayoutInfo } { TCmdLineLayoutInfo }
{
function TCmdLineLayoutInfo.DoGetSection(const SectName: String; Forced: Boolean): TLayoutSection; function TCmdLineLayoutInfo.DoGetSection(const SectName: String; Forced: Boolean): TLayoutSection;
var var
i : integer; i : integer;
@ -101,18 +182,17 @@ begin
end else end else
Result:=TLayoutSection(fSections.Objects[i]); Result:=TLayoutSection(fSections.Objects[i]);
end; end;
}
constructor TCmdLineLayoutInfo.Create; constructor TCmdLineLayoutInfo.Create;
begin begin
fSections:=TStringList.Create; RootElement:=TLayoutSection.Create;
fSections.OwnsObjects:=true; RootElement.fName:='';
AddSection(''); RootElement.fElementType:=letSection;
end; end;
destructor TCmdLineLayoutInfo.Destroy; destructor TCmdLineLayoutInfo.Destroy;
begin begin
fSections.Clear; // need to call clear explicitly, since FREE doesn't free objects (even if owned) RootElement.Free;
fSections.Free;
inherited Destroy; inherited Destroy;
end; end;
@ -121,7 +201,7 @@ end;
begin begin
GetSection(Section).fswitches.Add(SwitchOrName); GetSection(Section).fswitches.Add(SwitchOrName);
end;} end;}
{
function TCmdLineLayoutInfo.AddSection(const Section: string): TLayoutSection; function TCmdLineLayoutInfo.AddSection(const Section: string): TLayoutSection;
begin begin
Result:=DoGetSection(Section, true); Result:=DoGetSection(Section, true);
@ -131,7 +211,7 @@ function TCmdLineLayoutInfo.GetSection(const Section: string): TLayoutSection;
begin begin
Result:=DoGetSection(Section, false); Result:=DoGetSection(Section, false);
end; end;
}
{function TCmdLineLayoutInfo.GetSections(Dst: TStrings): Boolean; {function TCmdLineLayoutInfo.GetSections(Dst: TStrings): Boolean;
var var
i : Integer; i : Integer;

View File

@ -45,7 +45,7 @@ begin
st:=TSectionIterator.Create; st:=TSectionIterator.Create;
try try
st.lt:=lt; st.lt:=lt;
st.sc:=lt.GetSection(''); st.sc:=lt.RootElement;
core.Iterate( st.Iterate, st) core.Iterate( st.Iterate, st)
finally finally
st.Free; st.Free;

View File

@ -28,13 +28,15 @@ type
TCmdLineScrollBoxControl = class(TCmdLineUIControl) TCmdLineScrollBoxControl = class(TCmdLineUIControl)
private private
fScrollBox : TScrollBox;
fCfg : TCmdLineCfg; fCfg : TCmdLineCfg;
fControls : TList; fControls : TList;
fOptToCtrl : TFPHashObjectList; fOptToCtrl : TFPHashObjectList;
fParent : TWinControl;
fOtherMet : Boolean;
protected protected
flayout: TCmdLineLayoutInfo; flayout: TCmdLineLayoutInfo;
fusedoptlist: TStringList; fusedoptlist: TFPHashObjectList;
procedure OnChange(Sender: TObject); procedure OnChange(Sender: TObject);
procedure OnCndChange(Sender: TObject); procedure OnCndChange(Sender: TObject);
procedure RevaluateConditions; procedure RevaluateConditions;
@ -45,21 +47,13 @@ type
public public
constructor Create(AParent: TWinControl); constructor Create(AParent: TWinControl);
destructor Destroy; override; destructor Destroy; override;
procedure Init(cfg: TCmdLineCfg; layout: TCmdLineLayoutInfo); override; procedure Init(cfg: TCmdLineCfg; layout: TCmdLineLayoutInfo; const ASection: string = ''); override;
procedure SetValues(list: TList {of TCmdLineOptionValue}); override; procedure SetValues(list: TList {of TCmdLineOptionValue}); override;
procedure Serialize(list: TList {of TCmdLineOptionValue}); override; procedure Serialize(list: TList {of TCmdLineOptionValue}); override;
end; end;
procedure ReleaseScrollBox(box: TCmdLineScrollBoxControl);
implementation implementation
procedure ReleaseScrollBox(box: TCmdLineScrollBoxControl);
begin
if not Assigned(box) then Exit;
box.fScrollBox.Free;
end;
{ TControlInfo } { TControlInfo }
constructor TControlInfo.Create(aopt: TCmdLineCfgOption; actrl: TControl); constructor TControlInfo.Create(aopt: TCmdLineCfgOption; actrl: TControl);
@ -215,6 +209,7 @@ var
k : Integer; k : Integer;
box : TGroupBox; box : TGroupBox;
by : integer; by : integer;
opt : TCmdLineCfgOption;
begin begin
if not Assigned(sct) then begin if not Assigned(sct) then begin
Result:=VOffset; Result:=VOffset;
@ -247,10 +242,15 @@ begin
end else end else
y:=AllocForSection(AParent, y, ls ); y:=AllocForSection(AParent, y, ls );
end else begin end else begin
k:=fusedoptlist.IndexOf(ls.Name); if (AnsiLowerCase(ls.Name)='%%other') and not fOtherMet then begin
if (k>=0) then begin LayoutGetUnused( fCfg, flayout.RootElement, l );
l.Add( fusedoptlist.Objects[k] ); fOtherMet := true;
fusedoptlist.Delete(k); end else begin
k := fusedoptlist.FindIndexOf(ls.Name);
if k>=0 then begin
l.Add( fusedoptlist.Items[k] );
fusedoptlist.Delete(k);
end;
end; end;
end; end;
end; end;
@ -275,10 +275,7 @@ end;
constructor TCmdLineScrollBoxControl.Create(AParent: TWinControl); constructor TCmdLineScrollBoxControl.Create(AParent: TWinControl);
begin begin
inherited Create; inherited Create;
fScrollBox := TScrollBox.Create(AParent); fParent:=AParent;
fScrollBox.Align:=alClient;
fScrollBox.Parent:=AParent;
fScrollBox.VertScrollBar.Tracking:=true;
fControls:=TList.Create; fControls:=TList.Create;
fOptToCtrl:=TFPHashObjectList.Create(true); fOptToCtrl:=TFPHashObjectList.Create(true);
end; end;
@ -291,7 +288,7 @@ begin
inherited Destroy; inherited Destroy;
end; end;
procedure TCmdLineScrollBoxControl.Init(cfg: TCmdLineCfg; layout: TCmdLineLayoutInfo); procedure TCmdLineScrollBoxControl.Init(cfg: TCmdLineCfg; layout: TCmdLineLayoutInfo; const ASection: string = '');
var var
i : Integer; i : Integer;
opt : TCmdLineCfgOption; opt : TCmdLineCfgOption;
@ -299,6 +296,8 @@ var
l : TList; l : TList;
nm : string; nm : string;
y : Integer; y : Integer;
sct : TLayoutSection;
sctnm : string;
begin begin
if not Assigned(cfg) then Exit; if not Assigned(cfg) then Exit;
fCfg:=cfg; fCfg:=cfg;
@ -306,26 +305,31 @@ begin
list.CaseSensitive:=true; // must be case sensitive list.CaseSensitive:=true; // must be case sensitive
l:=TList.Create; l:=TList.Create;
fOptToCtrl.Clear; fOptToCtrl.Clear;
fusedoptlist:=list;
fusedoptlist:=TFPHashObjectList.Create(false);
flayout:=layout; flayout:=layout;
try try
y:=24; y:=0;
for i:=0 to cfg.Options.Count-1 do begin for i:=0 to cfg.Options.Count-1 do begin
opt:=TCmdLineCfgOption(cfg.Options[i]); opt:=TCmdLineCfgOption(cfg.Options[i]);
nm:=opt.Name; nm:=opt.Name;
if nm='' then nm:=opt.Key; if nm='' then nm:=opt.Key;
list.AddObject(nm, cfg.Options[i]); list.AddObject(nm, cfg.Options[i]);
fusedoptlist.Add(nm, cfg.Options[i]);
end; end;
if not Assigned(layout) then begin
if Assigned(layout) then y:=AllocForSection(fScrollBox, y, layout.GetSection('')); for i:=0 to list.Count-1 do l.Add(list.Objects[i]);
if Assigned(layout) then begin AllocControls(fParent, y, l);
y:=AllocHeaderLabel(fScrollBox, y, 'Other'); end else begin
fOtherMet:=false;
sctnm:=ASection;
sct:=layout.RootElement;
if ASection<>'' then sct:=LayoutFindElement(sct, sctnm);
if Assigned(sct) then
y:=AllocForSection(fParent, y, sct, sctnm<>'');
end; end;
l.Clear;
for i:=0 to list.Count-1 do
l.Add(list.Objects[i]);
AllocControls(fScrollBox, y, l);
finally finally
fusedoptlist.Free;
fusedoptlist:=nil; fusedoptlist:=nil;
flayout:=nil; flayout:=nil;
l.Free; l.Free;
@ -340,6 +344,7 @@ var
i : Integer; i : Integer;
mlt : TFPHashList; mlt : TFPHashList;
isPath : Boolean; isPath : Boolean;
ci : TControlInfo;
const const
Delims : array [Boolean] of string = (' ', ';'); Delims : array [Boolean] of string = (' ', ';');
begin begin
@ -350,7 +355,9 @@ begin
for i:=0 to list.Count-1 do begin for i:=0 to list.Count-1 do begin
vl:=TCmdLineOptionValue(list[i]); vl:=TCmdLineOptionValue(list[i]);
if not Assigned(vl.Option) then Continue; if not Assigned(vl.Option) then Continue;
ctrl:=TControlInfo(fOptToCtrl.Find(vl.Option.Name)).ctrl; ci:=TControlInfo(fOptToCtrl.Find(vl.Option.Name));
if not Assigned(ci) then Continue;
ctrl:=ci.ctrl;
if not Assigned(ctrl) then Continue; if not Assigned(ctrl) then Continue;
if ctrl is TComboBox then SetValueComboBox(vl.Option, vl.Value, TComboBoX(ctrl)) if ctrl is TComboBox then SetValueComboBox(vl.Option, vl.Value, TComboBoX(ctrl))
else if ctrl is TCheckBox then SetValueCheckBox(vl.Option, vl.Value, TCheckBox(ctrl)) else if ctrl is TCheckBox then SetValueCheckBox(vl.Option, vl.Value, TCheckBox(ctrl))

View File

@ -17,7 +17,7 @@
<CompilerPath Value="$(CompPath)"/> <CompilerPath Value="$(CompPath)"/>
</Other> </Other>
</CompilerOptions> </CompilerOptions>
<Files Count="13"> <Files Count="12">
<Item1> <Item1>
<Filename Value="optviewform.pas"/> <Filename Value="optviewform.pas"/>
<UnitName Value="optviewform"/> <UnitName Value="optviewform"/>
@ -27,50 +27,46 @@
<UnitName Value="cmdlinelclctrlsbox"/> <UnitName Value="cmdlinelclctrlsbox"/>
</Item2> </Item2>
<Item3> <Item3>
<Filename Value="..\cmdlinelclpropgrid.pas"/>
<UnitName Value="cmdlinelclpropgrid"/>
</Item3>
<Item4>
<Filename Value="..\cmdlinelclutils.pas"/> <Filename Value="..\cmdlinelclutils.pas"/>
<UnitName Value="cmdlinelclutils"/> <UnitName Value="cmdlinelclutils"/>
</Item4> </Item3>
<Item5> <Item4>
<Filename Value="..\cmdlinecfg.pas"/> <Filename Value="..\cmdlinecfg.pas"/>
<UnitName Value="cmdlinecfg"/> <UnitName Value="cmdlinecfg"/>
</Item5> </Item4>
<Item6> <Item5>
<Filename Value="..\cmdlinecfgjson.pas"/> <Filename Value="..\cmdlinecfgjson.pas"/>
<UnitName Value="cmdlinecfgjson"/> <UnitName Value="cmdlinecfgjson"/>
</Item6> </Item5>
<Item7> <Item6>
<Filename Value="..\cmdlinecfgparser.pas"/> <Filename Value="..\cmdlinecfgparser.pas"/>
<UnitName Value="cmdlinecfgparser"/> <UnitName Value="cmdlinecfgparser"/>
</Item7> </Item6>
<Item8> <Item7>
<Filename Value="..\cmdlinecfgui.pas"/> <Filename Value="..\cmdlinecfgui.pas"/>
<UnitName Value="cmdlinecfgui"/> <UnitName Value="cmdlinecfgui"/>
</Item8> </Item7>
<Item9> <Item8>
<Filename Value="..\cmdlinecfguijson.pas"/> <Filename Value="..\cmdlinecfguijson.pas"/>
<UnitName Value="cmdlinecfguijson"/> <UnitName Value="cmdlinecfguijson"/>
</Item9> </Item8>
<Item10> <Item9>
<Filename Value="..\cmdlinecfgutils.pas"/> <Filename Value="..\cmdlinecfgutils.pas"/>
<UnitName Value="cmdlinecfgutils"/> <UnitName Value="cmdlinecfgutils"/>
</Item10> </Item9>
<Item11> <Item10>
<Filename Value="..\cmdlinefpccond.pas"/> <Filename Value="..\cmdlinefpccond.pas"/>
<UnitName Value="cmdlinefpccond"/> <UnitName Value="cmdlinefpccond"/>
</Item11> </Item10>
<Item12> <Item11>
<Filename Value="cfgcompoptreg.pas"/> <Filename Value="cfgcompoptreg.pas"/>
<HasRegisterProc Value="True"/> <HasRegisterProc Value="True"/>
<UnitName Value="cfgcompoptreg"/> <UnitName Value="cfgcompoptreg"/>
</Item12> </Item11>
<Item13> <Item12>
<Filename Value="optviewform.lfm"/> <Filename Value="optviewform.lfm"/>
<Type Value="LFM"/> <Type Value="LFM"/>
</Item13> </Item12>
</Files> </Files>
<Type Value="DesignTime"/> <Type Value="DesignTime"/>
<RequiredPkgs Count="3"> <RequiredPkgs Count="3">

View File

@ -7,10 +7,9 @@ unit cfgcompopt;
interface interface
uses uses
optviewform, cmdlinelclctrlsbox, cmdlinelclpropgrid, cmdlinelclutils, optviewform, cmdlinelclctrlsbox, cmdlinelclutils, cmdlinecfg,
cmdlinecfg, cmdlinecfgjson, cmdlinecfgparser, cmdlinecfgui, cmdlinecfgjson, cmdlinecfgparser, cmdlinecfgui, cmdlinecfguijson,
cmdlinecfguijson, cmdlinecfgutils, cmdlinefpccond, cfgcompoptreg, cmdlinecfgutils, cmdlinefpccond, cfgcompoptreg, LazarusPackageIntf;
LazarusPackageIntf;
implementation implementation

View File

@ -1,46 +1,73 @@
object OptView: TOptView object OptView: TOptView
Left = 359 Left = 571
Height = 240 Height = 240
Top = 214 Top = 171
Width = 320 Width = 320
Caption = 'OptView' Caption = 'OptView'
ClientHeight = 240 ClientHeight = 240
ClientWidth = 320 ClientWidth = 320
OnDestroy = FormDestroy OnDestroy = FormDestroy
OnShow = FormShow OnShow = FormShow
LCLVersion = '1.1' LCLVersion = '1.3'
object Panel1: TPanel object Panel1: TPanel
Left = 0 Left = 0
Height = 190 Height = 200
Top = 0 Top = 0
Width = 320 Width = 320
Align = alClient Align = alClient
Caption = 'Panel1' ClientHeight = 200
ClientWidth = 320
TabOrder = 0 TabOrder = 0
object ListBox1: TListBox
Left = 1
Height = 198
Top = 1
Width = 130
Align = alLeft
ItemHeight = 0
OnClick = ListBox1Click
OnSelectionChange = ListBox1SelectionChange
TabOrder = 0
end
object Splitter1: TSplitter
Left = 131
Height = 198
Top = 1
Width = 5
end
object Panel3: TPanel
Left = 136
Height = 198
Top = 1
Width = 183
Align = alClient
BevelOuter = bvNone
TabOrder = 2
end
end end
object Panel2: TPanel object Panel2: TPanel
Left = 0 Left = 0
Height = 50 Height = 40
Top = 190 Top = 200
Width = 320 Width = 320
Align = alBottom Align = alBottom
Caption = 'Panel2' ClientHeight = 40
ClientHeight = 50
ClientWidth = 320 ClientWidth = 320
TabOrder = 1 TabOrder = 1
OnResize = Panel2Resize
object btnOk: TButton object btnOk: TButton
Left = 33 Left = 72
Height = 25 Height = 25
Top = 15 Top = 8
Width = 75 Width = 75
Caption = 'Ok' Caption = 'Ok'
ModalResult = 1 ModalResult = 1
TabOrder = 0 TabOrder = 0
end end
object btnCancel: TButton object btnCancel: TButton
Left = 115 Left = 152
Height = 25 Height = 25
Top = 15 Top = 8
Width = 75 Width = 75
Caption = 'Cancel' Caption = 'Cancel'
ModalResult = 2 ModalResult = 2

View File

@ -7,26 +7,40 @@ interface
uses uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
LCLIntf, LCLIntf,
StdCtrls, LazIDEIntf, IDEOptionsIntf, ProjectIntf, CompOptsIntf, cmdlinecfg, StdCtrls, LazIDEIntf, IDEOptionsIntf, ProjectIntf, CompOptsIntf, cmdlinecfg
cmdlinecfgjson, cmdlinecfgui, cmdlinecfguijson, cmdlinelclctrlsbox, cmdlinelazcompopt; //, cmdlinecfgjson
, cmdlinecfgui
//, cmdlinecfguijson
, cmdlinelclctrlsbox, cmdlinelazcompopt;
type type
TOptionsBox = record
box : TScrollBox;
cmd : TCmdLineScrollBoxControl;
end;
{ TOptView } { TOptView }
TOptView = class(TForm) TOptView = class(TForm)
btnOk: TButton; btnOk: TButton;
btnCancel: TButton; btnCancel: TButton;
ListBox1: TListBox;
Panel1: TPanel; Panel1: TPanel;
Panel2: TPanel; Panel2: TPanel;
Panel3: TPanel;
Splitter1: TSplitter;
procedure FormDestroy(Sender: TObject); procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject); procedure FormShow(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure ListBox1SelectionChange(Sender: TObject; User: boolean);
procedure Panel2Resize(Sender: TObject);
private private
{ private declarations } { private declarations }
cmd : TCmdLineScrollBoxControl; sections : array of TOptionsBox;
cfg : TCmdLineCfg; cfg : TCmdLineCfg;
layout : TCmdLineLayoutInfo; layout : TCmdLineLayoutInfo;
procedure InitOpts(acfg: TCmdLineCfg; alayout: TCmdLineLayoutInfo); procedure InitOpts(acfg: TCmdLineCfg; alayout: TCmdLineLayoutInfo);
procedure ClearSections(clearboxes: Boolean = true);
public public
{ public declarations } { public declarations }
function ShowForOpts(opt: TLazCompilerOptions): Integer; function ShowForOpts(opt: TLazCompilerOptions): Integer;
@ -46,20 +60,19 @@ implementation
function ReviewOpts(acfg: TCmdLineCfg; alayout: TCmdLineLayoutInfo; opt: TLazCompilerOptions = nil): Integer; function ReviewOpts(acfg: TCmdLineCfg; alayout: TCmdLineLayoutInfo; opt: TLazCompilerOptions = nil): Integer;
begin begin
if not Assigned(OptView) then OptView:=TOptView.Create(Application); if not Assigned(OptView) then OptView:=TOptView.Create(Application);
OptView.Caption:='Review Compiler Options';
if (OptView.cfg<>acfg) or (OptView.layout<>alayout) then if (OptView.cfg<>acfg) or (OptView.layout<>alayout) then
OptView.InitOpts(acfg, alayout); OptView.InitOpts(acfg, alayout);
if not Assigned(opt) and Assigned(LazarusIDE.ActiveProject) then if not Assigned(opt) and Assigned(LazarusIDE.ActiveProject) then
opt:=LazarusIDE.ActiveProject.LazCompilerOptions; opt:=LazarusIDE.ActiveProject.LazCompilerOptions;
if Assigned(OptView.cmd) and Assigned(opt) then if Assigned(opt) then Result:=OptView.ShowForOpts(opt)
Result:=OptView.ShowForOpts(opt) else Result:=mrCancel;
else
Result:=mrCancel;
end; end;
procedure TOptView.FormDestroy(Sender: TObject); procedure TOptView.FormDestroy(Sender: TObject);
begin begin
cmd.Free; ClearSections(false);
end; end;
procedure TOptView.FormShow(Sender: TObject); procedure TOptView.FormShow(Sender: TObject);
@ -67,14 +80,74 @@ begin
end; end;
procedure TOptView.InitOpts(acfg: TCmdLineCfg; alayout: TCmdLineLayoutInfo); procedure TOptView.ListBox1Click(Sender: TObject);
begin begin
ReleaseScrollBox(cmd);
cmd.Free; end;
procedure TOptView.ListBox1SelectionChange(Sender: TObject; User: boolean);
var
i : Integer;
idx: integer;
begin
idx:=ListBox1.ItemIndex;
if (idx>=0) and (idx<length(sections)) then begin
sections[idx].box.BringToFront;
sections[idx].box.Show;
for i:=0 to length(sections)-1 do
if i<>idx then sections[i].box.Hide;
end;
end;
procedure TOptView.Panel2Resize(Sender: TObject);
var
w: integer;
begin
w:=Self.Width div 2;
btnOk.Left:=w - btnOk.Width - 2;
btnCancel.Left:=w+2;
end;
procedure TOptView.InitOpts(acfg: TCmdLineCfg; alayout: TCmdLineLayoutInfo);
var
lt : TList;
i : Integer;
ls : TLayoutSection;
begin
ClearSections;
cfg:=acfg; cfg:=acfg;
layout:=alayout; layout:=alayout;
cmd:=TCmdLineScrollBoxControl.Create(Panel1); //cmd:=
cmd.Init(cfg, layout); lt:=TList.Create;
try
LayoutEnumElement( layout.RootElement, lt);
SetLength(sections, lt.Count);
for i:=0 to lt.Count-1 do begin
ls:=TLayoutSection(lt[i]);
ListBox1.AddItem( ls.Display, ls);
sections[i].box:=TScrollBox.Create(Panel3);
sections[i].box.Visible:=false;
sections[i].box.Parent:=Panel3;
sections[i].box.Align:=alClient;
sections[i].cmd:=TCmdLineScrollBoxControl.Create(sections[i].box);
sections[i].cmd.Init(cfg, layout, ls.Name);
end;
finally
lt.Free;
end;
end;
procedure TOptView.ClearSections(clearboxes: Boolean);
var
i : integer;
begin
for i:=0 to length(sections)-1 do begin
sections[i].cmd.Free;
if clearboxes then sections[i].box.Free;
end;
SetLength(sections,0);
end; end;
function TOptView.ShowForOpts(opt: TLazCompilerOptions): Integer; function TOptView.ShowForOpts(opt: TLazCompilerOptions): Integer;
@ -85,13 +158,14 @@ begin
list := TList.Create; list := TList.Create;
try try
LazCompOptToVals(opt, cfg, list); LazCompOptToVals(opt, cfg, list);
cmd.SetValues(list); for i:=0 to length(sections)-1 do sections[i].cmd.SetValues(list);
for i:=0 to list.Count-1 do TObject(list[i]).Free; for i:=0 to list.Count-1 do TObject(list[i]).Free;
Result:=ShowModal; Result:=ShowModal;
if Result=mrOK then begin if Result=mrOK then begin
list.Clear; list.Clear;
cmd.Serialize(list); for i:=0 to length(sections)-1 do
sections[i].cmd.Serialize(list);
ValsToLazCompOpt(list, opt); ValsToLazCompOpt(list, opt);
for i:=0 to list.Count-1 do TObject(list[i]).Free; for i:=0 to list.Count-1 do TObject(list[i]).Free;
end; end;

View File

@ -1,5 +1,32 @@
Command Line Configuration Command Line Configuration
== Source files ==
cmdlinecfg.pas - the core unit defining the primary class for configuration
cmdlinecfgutils.pas - utility functions
cmdlinecfgparser.pas - the unit for parsing input strings into command lines
and mapping them to classes of cmdlinecfg.
cmdlinecfgjson.pas - the json format reader of command-line configurations
=== User Interface ===
cmdlinecfgui.pas - core unit for UI controller of command-line options
cmdlinecfguijson.pas - json read of UI controller info.
cmdlinelclctrlsbox.pas - LCL-based consols list UI controller
cmdlinelclpropgrid.pas - LCL-based propery grid UI controller
cmdlinelclutils.pas - the function contains a number of utility functions
for allocating LCL controls based on the information about command-line option
=== Lazarus specific ===
cmdlinelazcompopt.pas - Lazarus IDE specific file, that converts a set of cmdlinecfg classes
to Lazarus project
=== Condition checks ===
cmdlinefpccond.pas - the utility function for verification of FPC specific conditions (cpu/os)
(doesn't depend on cmdlinecfg.pas)
see "FPC Condition" below
== JSON Storage == == JSON Storage ==
@ -80,6 +107,8 @@ Example of JSON Storage:
] ]
} }
== FPC Condition == == FPC Condition ==
Free Pascal Compiler condition define for what target (CPU, CPU-OS) the option or value of an option Free Pascal Compiler condition define for what target (CPU, CPU-OS) the option or value of an option
@ -98,4 +127,56 @@ If an option is available for multple platforms, each condition has to be comma
i386,x86_64,arm-linux i386,x86_64,arm-linux
== UI controller ==
UI controller is an abstraction layer, that does the representation of the command-line utils to an user.
The core class is:
TCmdLineUIControl
method
procedure Init(cfg: TCmdLineCfg; layout: TCmdLineLayoutInfo; ASection: string);
- method accepts the description of the command-line options
and optional layout information;
method must initialize (create) all necessary UI controls;
the place to initialize controls must be defined in the method constructor
* if layout information is passed, the controller should use it to represent the user interface
* if Asection is not an empty string and layout is passed, controller should
initialize controls for this section only.
Futher operations for "SetValue" and "Serialize" should be limited
to the command-line options, contained in the layout of the passed section.
if layout information is not passed, section should be ignored
* Since it's possible that a new command-line option is introduced
prior to update of the user interface information,
a layout information can specify switch "%%other" (name is case-insesitive)
where all switches should go, that don't have a specific location within the layout information.
if "%%other" switch is not introduced by the layout, these command-line options that are not part of the layout
must not be shown.
if multiple "%%other" switches are declared, the first met should be used
procedure SetValues(list: TList);
- method should initialized UI controls to the values passed in the list
the list will contain objects TCmdLineOptionValue class.
the methods must not retain or free any of the objects
procedure Serialize(list: TList);
- method should gather the values from the user interface
method should not check the existense of TCmdLineOptionValue in the passed list
instead it must only ADD serialized TCmdLineOptionValue values
events
OnValueChanged: TNotifyEvent - the event should be triggered every time a value is changed by a user;
the even must not be triggered during handling of SetValues method
The supplemental classes:
TCmdLineLayoutInfo - the class contains a description of how to represent command-line utils.
any implementation of TCmdLineUIControl must be able to work without
any TCmdLineLayoutInfo provided.
TLayoutSection - the description of a certain section of "command-line configurations".
typically command-line options are grouped into sections
=== GUI Hints ===
hideempty - if the there're no command-line options to be displayed, the section should be hidden

View File

@ -44,4 +44,7 @@
"display": "Verbosity", "display": "Verbosity",
"switches": ["-ve","-vw", "-vn","-vh","-vi","-vp","-vc","-vx","-v0","-vd","-vu","-vt","-vl","-vb","-va","-l","-Se"] "switches": ["-ve","-vw", "-vn","-vh","-vi","-vp","-vc","-vx","-v0","-vd","-vu","-vt","-vl","-vb","-va","-l","-Se"]
} }
,"other": {
"display": "Other", "switches": ["%%other"]
}
} }

View File

@ -1,19 +1,19 @@
object Form1: TForm1 object Form1: TForm1
Left = 411 Left = 411
Height = 319 Height = 339
Top = 197 Top = 197
Width = 425 Width = 441
Caption = 'Form1' Caption = 'Form1'
ClientHeight = 319 ClientHeight = 339
ClientWidth = 425 ClientWidth = 441
OnCreate = FormCreate OnCreate = FormCreate
OnDestroy = FormDestroy OnDestroy = FormDestroy
LCLVersion = '1.1' LCLVersion = '1.3'
object Memo1: TMemo object Memo1: TMemo
Left = 0 Left = 0
Height = 90 Height = 90
Top = 179 Top = 199
Width = 425 Width = 441
Align = alBottom Align = alBottom
Lines.Strings = ( Lines.Strings = (
'Memo1' 'Memo1'
@ -24,36 +24,20 @@ object Form1: TForm1
Cursor = crVSplit Cursor = crVSplit
Left = 0 Left = 0
Height = 5 Height = 5
Top = 174 Top = 194
Width = 425 Width = 441
Align = alBottom Align = alBottom
ResizeAnchor = akBottom ResizeAnchor = akBottom
end end
object Label1: TLabel
Left = 47
Height = 13
Top = 44
Width = 31
Caption = 'Label1'
ParentColor = False
end
object Edit1: TEdit
Left = 105
Height = 21
Top = 46
Width = 191
TabOrder = 2
Text = 'Edit1'
end
object Panel1: TPanel object Panel1: TPanel
Left = 0 Left = 0
Height = 50 Height = 50
Top = 269 Top = 289
Width = 425 Width = 441
Align = alBottom Align = alBottom
ClientHeight = 50 ClientHeight = 50
ClientWidth = 425 ClientWidth = 441
TabOrder = 3 TabOrder = 2
object toOpt: TButton object toOpt: TButton
Left = 8 Left = 8
Height = 25 Height = 25
@ -64,4 +48,15 @@ object Form1: TForm1
TabOrder = 0 TabOrder = 0
end end
end end
object ScrollBox1: TScrollBox
Left = 0
Height = 196
Top = 0
Width = 440
HorzScrollBar.Page = 436
VertScrollBar.Page = 192
VertScrollBar.Tracking = True
Anchors = [akTop, akLeft, akRight, akBottom]
TabOrder = 3
end
end end

View File

@ -5,8 +5,8 @@ unit mainform;
interface interface
uses uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ValEdit, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs
StdCtrls, ExtCtrls ,StdCtrls, ExtCtrls
,cmdlinecfg , cmdlinelclctrlsbox, cmdlinecfgjson //, patheditor ,cmdlinecfg , cmdlinelclctrlsbox, cmdlinecfgjson //, patheditor
,cmdlinecfgui, cmdlinecfguijson ,cmdlinecfgui, cmdlinecfguijson
,cmdlinecfgparser; ,cmdlinecfgparser;
@ -16,9 +16,8 @@ type
{ TForm1 } { TForm1 }
TForm1 = class(TForm) TForm1 = class(TForm)
ScrollBox1: TScrollBox;
toOpt: TButton; toOpt: TButton;
Edit1: TEdit;
Label1: TLabel;
Memo1: TMemo; Memo1: TMemo;
Panel1: TPanel; Panel1: TPanel;
Splitter1: TSplitter; Splitter1: TSplitter;
@ -30,6 +29,7 @@ type
ctrl : TCmdLineScrollBoxControl; ctrl : TCmdLineScrollBoxControl;
cfg : TCmdLineCfg; cfg : TCmdLineCfg;
lt : TCmdLineLayoutInfo; lt : TCmdLineLayoutInfo;
sct : string; // desired section
public public
{ public declarations } { public declarations }
procedure OnValueChanged(Sender: TObject); procedure OnValueChanged(Sender: TObject);
@ -47,17 +47,36 @@ implementation
procedure TForm1.FormCreate(Sender: TObject); procedure TForm1.FormCreate(Sender: TObject);
begin begin
{cmdlinelclutils.ADirsDialogs:=DummyEditPaths; {cmdlinelclutils.ADirsDialogs:=DummyEditPaths;
cmdlinelclutils.AFilesDialogs:=DummyEditPaths;} cmdlinelclutils.AFilesDialogs:=DummyEditPaths;
}
ctrl:=TCmdLineScrollBoxControl.Create(Self); {fScrollBox := TScrollBox.Create(AParent);
fScrollBox.Align:=alClient;
fScrollBox.Parent:=AParent;
fScrollBox.VertScrollBar.Tracking:=true;}
Memo1.Clear;
if ParamCount=0 then begin
Memo1.Lines.Add('Please pass the following information through the command-line: ');
Memo1.Lines.Add(' 1. json file for command-lines');
Memo1.Lines.Add(' (optional) 2. layout information json file ');
Memo1.Lines.Add(' (optional) 3. name of the section that you would need to render');
end;
ctrl:=TCmdLineScrollBoxControl.Create(ScrollBox1);
if ParamCount>0 then begin if ParamCount>0 then begin
cfg:=TCmdLineCfg.Create; cfg:=TCmdLineCfg.Create;
CmdLineCfgJSONReadFile(ParamStr(1), cfg); CmdLineCfgJSONReadFile(ParamStr(1), cfg);
if ParamCOunt>1 then begin if ParamCOunt>1 then begin
lt:=TCmdLineLayoutInfo.Create; lt:=TCmdLineLayoutInfo.Create;
CmdLineUIJSONReadFile(PAramStr(2), lt); CmdLineUIJSONReadFile(ParamStr(2), lt);
end; end;
ctrl.Init(cfg, lt); if ParamCount>2 then
sct:=ParamStr(3);
Self.Caption:=Paramstr(1);
if sct<>'' then Self.Caption:=Self.Caption+'.'+sct;
ctrl.Init(cfg, lt, sct);
ctrl.OnValueChanged:=OnValueChanged; ctrl.OnValueChanged:=OnValueChanged;
end; end;
end; end;

View File

@ -0,0 +1,21 @@
{
"executable":"sample",
"version":"1.0",
"testkey":"-iV",
"testValue":"1.0",
"options": [
{"key":"-a", "display":"This is option A" }
,{"key":"-b", "display":"This option controls B"}
,{"key":"-c", "display":"C is controlled by this checkbox" }
,{ "key":"-d%value%", "display":"This is drop down values - one of many"
,"options": [
{"value": "1", "display":"One"}
,{"value": "2", "display":"Two"}
,{"value": "3", "display":"Three"}
,{"value": "4", "display":"Four"}
,{"value": "5", "display":"Five"}
]
}
,{"key":"-z", "display":"Z is the last control not in sample.ui" }
]
}

View File

@ -0,0 +1,10 @@
{
"primary": {
"display": "Primary Part",
"switches": ["-a","-d"]
}
,"secondary": {
"display": "Secondary Part",
"switches": ["-b","-c"]
}
}

View File

@ -0,0 +1,15 @@
{
"primary": {
"display": "Primary Part",
"switches": ["-a","-d"]
}
,"secondary": {
"display": "Secondary Part",
"switches": ["-b","-c"]
}
,"other": {
"display": "Other",
"hint": "hideempty",
"switches": ["%%other"]
}
}

View File

@ -9,7 +9,6 @@
<Title Value="project1"/> <Title Value="project1"/>
<ResourceType Value="res"/> <ResourceType Value="res"/>
<UseXPManifest Value="True"/> <UseXPManifest Value="True"/>
<Icon Value="0"/>
</General> </General>
<i18n> <i18n>
<EnableI18N LFM="False"/> <EnableI18N LFM="False"/>