unit cmdlinecfgui; interface uses Classes, SysUtils, contnrs, cmdlinecfg; type { TCmdLineLayoutInfo } // Section names are assumed to be . separated. // Anything after to . is expected to be a "sub section" of the section. { TLayoutSection } TLayoutElementType = (letSwitch, letSection); TLayoutElementTypes = set of TLayoutElementType; TLayoutSection = class(TObject) //level : integer; // number of "dots" in the name public fName : string; fElementType: TLayoutElementType; public Display : string; GUIHint : string; Elements : array of TLayoutSection; ElemCount : integer; function AddElement(const AName: string; AElementType: TLayoutElementType): TLayoutSection; constructor Create(const AName: string = ''; AElementType: TLayoutElementType = letSection); destructor Destroy; override; property Name: string read fName; property ElementType: TLayoutElementType read fElementType; end; TCmdLineLayoutInfo = class(TObject) public RootElement : TLayoutSection; constructor Create; destructor Destroy; override; end; { TCmdLineUIControl } TCmdLineUIControl = class(TObject) private FValueChanged: TNotifyEvent; protected procedure ValueChanged; virtual; public procedure Init(cfg: TCmdLineCfg; layout: TCmdLineLayoutInfo; const ASection : string = ''); virtual; abstract; procedure SetValues(list: TList {of TCmdLineOptionValue}); virtual; abstract; procedure Serialize(list: TList {of TCmdLineOptionValue}); virtual; abstract; property OnValueChanged: TNotifyEvent read FValueChanged write fValueChanged; 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 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 } function TLayoutSection.AddElement(const AName: string; AElementType: TLayoutElementType): TLayoutSection; begin if ElemCount = length(Elements) then begin if ElemCount=0 then SetLength(Elements, 2) else SetLength(Elements, ElemCount*2); end; Result:=TLayoutSection.Create(AName, AElementType); Result.Display:=Aname; Elements[ElemCount]:=Result; inc(ElemCount); end; constructor TLayoutSection.Create(const AName: string; AElementType: TLayoutElementType); begin inherited Create; fName:=AName; fElementType:=AElementType; end; destructor TLayoutSection.Destroy; var i : integer; begin for i:=0 to ElemCount-1 do Elements[i].Free; inherited Destroy; end; { TCmdLineLayoutInfo } { function TCmdLineLayoutInfo.DoGetSection(const SectName: String; Forced: Boolean): TLayoutSection; var i : integer; begin i:=fSections.IndexOf(SectName); if (i<0) and Forced then begin Result:=TLayoutSection.Create; fSections.AddObject(SectName, Result); fValidOrder:=false; // a new section has been added, it might ruin the order end else if (i<0) and not Forced then begin Result:=nil; end else Result:=TLayoutSection(fSections.Objects[i]); end; } constructor TCmdLineLayoutInfo.Create; begin RootElement:=TLayoutSection.Create; RootElement.fName:=''; RootElement.fElementType:=letSection; end; destructor TCmdLineLayoutInfo.Destroy; begin RootElement.Free; inherited Destroy; end; {procedure TCmdLineLayoutInfo.AddSwitch(const Section: string; const SwitchOrName: string); begin GetSection(Section).fswitches.Add(SwitchOrName); end;} { function TCmdLineLayoutInfo.AddSection(const Section: string): TLayoutSection; begin Result:=DoGetSection(Section, true); end; function TCmdLineLayoutInfo.GetSection(const Section: string): TLayoutSection; begin Result:=DoGetSection(Section, false); end; } {function TCmdLineLayoutInfo.GetSections(Dst: TStrings): Boolean; var i : Integer; begin if not fValidOrder then begin SortSections; fValidOrder:=true; end; Dst.BeginUpdate; try for i:=0 to fSections.Count-1 do Dst.Add(fSections[i]); finally Dst.EndUpdate; end; Result:=True; end;} {function TCmdLineLayoutInfo.GetSwitches(const Section: string; Dst: TStrings): Boolean; var sct : TLayoutSection; begin sct:=GetSection(Section); Result:=Assigned(Sct); if not Result then Exit; Dst.AddStrings(sct.fswitches); end;} { TCmdLineUIControl } procedure TCmdLineUIControl.ValueChanged; begin if Assigned(fValueChanged) then fValueChanged(Self); end; end.