lazarus/examples/fpdocmanager/fmain.pas
2012-04-09 08:24:59 +00:00

655 lines
16 KiB
ObjectPascal

unit fMain;
(* Documentation manager GUI.
View/Edit configuration, packages
Add/Import packages
Create/Update skeletons
Create documentation (final, test)
*)
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, SynHighlighterXML, SynEdit, Forms, Controls,
Graphics, Dialogs, Menus, StdCtrls, ComCtrls, ExtCtrls,
uManager;
type
{ TMain }
TMain = class(TForm)
buMakeDoc: TButton;
buNewProfile: TButton;
buRefresh: TButton;
buShowLog: TButton;
buTest: TButton;
cbFormat: TComboBox;
cbProfile: TComboBox;
edDescrDir: TEdit;
edDescrLaz: TEdit;
edLog: TEdit;
edOutput: TEdit;
edOS: TEdit;
edCPU: TEdit;
edLang: TEdit;
edMoDir: TEdit;
edDefOut: TEdit;
edUnit: TEdit;
GroupBox1: TGroupBox;
gbAltDir: TGroupBox;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
edBackend: TMemo;
Label8: TLabel;
Label9: TLabel;
optUpd: TCheckGroup;
Panel1: TPanel;
StatusBar1: TStatusBar;
swAll: TRadioButton;
swOutput: TRadioButton;
swDefOut: TRadioButton;
swDocOpts: TCheckGroup;
Label1: TLabel;
dlgSelLpk: TOpenDialog;
edINI: TMemo;
lbPackages: TComboBox;
lbUnits: TListBox;
MainMenu1: TMainMenu;
MenuItem1: TMenuItem;
mnImportLpk: TMenuItem;
mnPackage: TMenuItem;
mnConfig: TMenuItem;
MenuItem3: TMenuItem;
mnExit: TMenuItem;
dlgSelRoot: TSelectDirectoryDialog;
swShowUpdate: TCheckBox;
swSingle: TRadioButton;
swSortNodes: TCheckBox;
ViewFinal: TTabSheet;
ViewINI: TTabSheet;
Units: TPageControl;
edXML: TSynEdit;
SynXMLSyn1: TSynXMLSyn;
ViewXML: TTabSheet;
ViewUnits: TTabSheet;
procedure buMakeDocClick(Sender: TObject);
procedure buNewProfileClick(Sender: TObject);
procedure buRefreshClick(Sender: TObject);
procedure buTestClick(Sender: TObject);
procedure cbFormatSelect(Sender: TObject);
procedure cbProfileSelect(Sender: TObject);
procedure edLogChange(Sender: TObject);
procedure edOSExit(Sender: TObject);
procedure edXMLExit(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
procedure FormCreate(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure lbBackendExit(Sender: TObject);
procedure lbPackagesClick(Sender: TObject);
procedure lbUnitsClick(Sender: TObject);
procedure lbUnitsDblClick(Sender: TObject);
procedure mnConfigClick(Sender: TObject);
procedure mnExitClick(Sender: TObject);
procedure mnImportLpkClick(Sender: TObject);
procedure optUpdItemClick(Sender: TObject; Index: integer);
procedure swShowUpdateChange(Sender: TObject);
procedure swSingleClick(Sender: TObject);
private
LogName: string;
LogFile: TStream;
Profile: string;
procedure ProjectsChanged(Sender: TObject);
procedure LogToFile(Sender: TObject; const msg: string);
procedure LogToMsgBox(Sender: TObject; const msg: string);
procedure LogStart;
procedure LogDone;
procedure ShowUpdate;
{$IFDEF v0}
procedure OnParseImport(Sender: TObject; var ASource, ALink: string);
{$ELSE}
{$ENDIF}
procedure SaveOptions;
procedure GetOptions;
procedure GetEngines;
procedure GetProfile;
procedure SelectFormat(AFmt: string);
procedure FormatSelected;
public
CurPkg: TDocPackage;
CurUnit: string;
procedure UpdateDocs;
end;
var
Main: TMain;
implementation
uses
fConfig, fLogView, fUpdateView,
//dwlinear,
fEditor,
dWriter;
{$R *.lfm}
{ TMain }
procedure TMain.FormCreate(Sender: TObject);
var
r: TRect;
s: string;
l: TStringList;
begin
{$IFDEF FCLAdds}
{$ELSE}
gbAltDir.Visible := False;
{$ENDIF}
Manager := TFPDocManager.Create(self);
Manager.OnChange := @ProjectsChanged;
if not Manager.LoadConfig(GetCurrentDir) then begin
//query root directory
if not dlgSelRoot.Execute then
exit;
if not Manager.LoadConfig(dlgSelRoot.FileName, True) then begin
//InitConfig(dlgSelRoot.FileName); ?
mnConfigClick(self); //does an UpdateDocs
exit; //nothing to init from?
end;
end;
//init...
if Manager.Config.SectionExists('GUI') then begin
s := Manager.Config.ReadString('GUI', 'position', '');
if s <> '' then begin
l := TStringList.Create;
try
l.DelimitedText := s;
if l.Count = 4 then begin
//SetBounds(l[0], l[1], );
r.Left := StrToInt(l[0]);
r.Top := StrToInt(l[1]);
r.Right := StrToInt(l[2]);
r.Bottom:= StrToInt(l[3]);
BoundsRect := r;
end;
finally
l.Free;
end;
end;
end;
//UpdateDocs; //package objects seem to be missing?
GetEngines;
end;
procedure TMain.FormResize(Sender: TObject);
var
r: TRect;
begin
r := BoundsRect;
Manager.Config.WriteString('GUI', 'position', Format('%d,%d,%d,%d',[r.Left, r.Top, r.Right, r.Bottom]));
end;
// --------------- events ------------------
procedure TMain.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
//is this really required?
CanClose := True; //make compiler happy
//Manager.SaveConfig; //what if fails?
end;
procedure TMain.mnExitClick(Sender: TObject);
begin
Close;
end;
procedure TMain.swShowUpdateChange(Sender: TObject);
begin
if swShowUpdate.Checked then
ShowUpdate;
end;
procedure TMain.LogStart;
begin
Screen.Cursor := crHourGlass;
if LogName = '' then
edLog.Text := Manager.RootDir + 'doclog.txt';
LogFile.Free;
LogFile := TFileStream.Create(LogName, fmCreate); //fmWrite
Manager.OnLog := @LogToFile;
StatusBar1.SimpleText := 'Starting ...';
end;
procedure TMain.LogDone;
begin
if not assigned(LogFile) then
exit;
FreeAndNil(LogFile);
Manager.OnLog := @LogToMsgBox;
//view messages
LogView.Caption := 'View ' + LogName;
LogView.edLog.Lines.LoadFromFile(LogName); //direct log???
LogView.Show;
Screen.Cursor := crDefault;
end;
procedure TMain.ShowUpdate;
var
v: TUpdateView;
fn: string;
begin
if not swShowUpdate.Checked then
exit;
if lbUnits.ItemIndex < 0 then
exit;
fn := 'upd.' + edUnit.Text + '.xml';
if not FileExists(fn) then
exit;
//problem with files kept open???
if UpdateView = nil then
v := TUpdateView.Create(self)
else
v := UpdateView;
v.Caption := 'Update of ' + edUnit.Text;
v.edUpdate.Lines.LoadFromFile(fn);
v.Show;
end;
procedure TMain.LogToFile(Sender: TObject; const msg: string);
var
s: string;
begin
if assigned(LogFile) then begin
s := msg + LineEnding;
LogFile.WriteBuffer(s[1], Length(s));
//give immediate feedback
StatusBar1.SimpleText := msg;
Application.ProcessMessages;
end
else
LogToMsgBox(Sender, msg);
end;
procedure TMain.LogToMsgBox(Sender: TObject; const msg: string);
begin
ShowMessage(msg);
end;
{$IFDEF v0}
procedure TMain.OnParseImport(Sender: TObject; var ASource, ALink: string);
var
i: integer;
pn: string;
begin
(* Provide ASource-->content file, ALink depends on format.
ASource can be a package name (only), or a CSV spec.
Sender is Manager.
An extended model could store a list of required packages,
and provide the list of imports.
*)
i := Pos(',', ASource);
if i > 0 then
exit; //default format, handled by caller
pn := ExtractFileNameOnly(ASource);
ASource := Manager.RootDir + pn + '.xct';
//if Manager.Options.??? - where's the output format?
ALink := '../' + pn + '/';
end;
{$ELSE}
{$ENDIF}
type
SkelOpts = (
soDecl, soOverrides, soErrors, soSeeAlso, soArgs, soResults,
soPriv, soProt, soClassSep
);
procedure TMain.SaveOptions;
begin
Manager.Options.WriteDeclaration := not optUpd.Checked[ord(soDecl)];
Manager.Options.DisableOverride := optUpd.Checked[ord(soOverrides)];
Manager.Options.DisableErrors := optUpd.Checked[ord(soErrors)];
Manager.Options.DisableSeealso := optUpd.Checked[ord(soSeeAlso)];
Manager.Options.DisableArguments := optUpd.Checked[ord(soArgs)];
Manager.Options.DisableFunctionResults := optUpd.Checked[ord(soResults)];
Manager.Options.ShowPrivate := not optUpd.Checked[ord(soPriv)];
Manager.Options.DisableProtected := optUpd.Checked[ord(soProt)];
Manager.Options.EmitClassSeparator := not optUpd.Checked[ord(soClassSep)];
Manager.Options.SortNodes := swSortNodes.Checked;
Manager.Options.Modified := True; //assume!
//Backend
//if cbFormat.Caption = '' then exit; //no valid options
if cbFormat.ItemIndex < 0 then
SelectFormat('html');
Manager.Options.Backend := cbFormat.Items.Names[cbFormat.ItemIndex];
Manager.Options.StopOnParseError := swDocOpts.Checked[0];
Manager.Options.WarnNoNode := swDocOpts.Checked[1];
Manager.Options.HideProtected := swDocOpts.Checked[2];
Manager.Options.ShowPrivate := swDocOpts.Checked[3];
Manager.Options.InterfaceOnly := swDocOpts.Checked[4];
Manager.Options.DontTrim := swDocOpts.Checked[5];
Manager.Options.Verbose := swDocOpts.Checked[6];
Manager.Options.OSTarget := edOS.Text;
Manager.Options.CPUTarget := edCPU.Text;
Manager.Options.Language := edLang.Text;
Manager.Options.MoDir := edMoDir.Text;
Manager.Options.BackendFromPairs(edBackend.Lines);
end;
procedure TMain.GetOptions;
begin
optUpd.Checked[ord(soDecl)] := not Manager.Options.WriteDeclaration;
optUpd.Checked[ord(soOverrides)] := Manager.Options.DisableOverride;
optUpd.Checked[ord(soErrors)] := Manager.Options.DisableErrors;
optUpd.Checked[ord(soSeeAlso)] := Manager.Options.DisableSeealso;
optUpd.Checked[ord(soArgs)] := Manager.Options.DisableArguments;
optUpd.Checked[ord(soResults)] := Manager.Options.DisableFunctionResults;
optUpd.Checked[ord(soPriv)] := not Manager.Options.ShowPrivate;
optUpd.Checked[ord(soProt)] := Manager.Options.DisableProtected;
optUpd.Checked[ord(soClassSep)] := not Manager.Options.EmitClassSeparator;
swSortNodes.Checked := Manager.Options.SortNodes;
//backend
if Profile = '' then begin
Profile:=Manager.Profile;
cbProfile.Items.CommaText := Manager.Profiles;
cbProfile.Caption := Profile;
end;
GetProfile;
end;
procedure TMain.GetProfile;
begin
//if Profile = AName then exit; //nothing changed?
//Manager.Profile := AName;
//cbFormat.Caption := Manager.Options.Backend; //select from CB?
SelectFormat(Manager.Options.Backend);
swDocOpts.Checked[0] := Manager.Options.StopOnParseError;
swDocOpts.Checked[1] := Manager.Options.WarnNoNode;
swDocOpts.Checked[2] := Manager.Options.HideProtected;
swDocOpts.Checked[3] := Manager.Options.ShowPrivate;
swDocOpts.Checked[4] := Manager.Options.InterfaceOnly;
swDocOpts.Checked[5] := Manager.Options.DontTrim;
//these should be global options?
edOS.Text := Manager.Options.OSTarget;
edCPU.Text := Manager.Options.CPUTarget;
edLang.Text := Manager.Options.Language;
edMoDir.Text := Manager.Options.MoDir;
//backend options
Manager.Options.BackendToPairs(edBackend.Lines);
end;
procedure TMain.edLogChange(Sender: TObject);
begin
LogName:=edLog.Text;
end;
procedure TMain.edOSExit(Sender: TObject);
var
ed: TEdit absolute Sender;
begin
if ed.Modified then begin
SaveOptions;
ed.Modified := False;
end;
end;
procedure TMain.lbBackendExit(Sender: TObject);
begin
//Modified never True???
if edBackend.Modified then begin
SaveOptions;
edBackend.Modified := False;
end;
end;
procedure TMain.cbFormatSelect(Sender: TObject);
begin
SaveOptions;
FormatSelected;
end;
procedure TMain.SelectFormat(AFmt: string);
var
i: integer;
begin
i := cbFormat.Items.IndexOfName(AFmt);
if i < 0 then
i := cbFormat.Items.Count - 1;
cbFormat.ItemIndex := i;
FormatSelected;
end;
procedure TMain.FormatSelected;
var
s: string;
begin
if assigned(Manager.Package) then
s := Manager.RootDir + Manager.Package.Name
else
s := '';
edDefOut.Text := s;
end;
procedure TMain.GetEngines;
begin
//should separate: writers (format) and settings!
dWriter.EnumWriters(cbFormat.Items);
cbProfile.Items.CommaText := Manager.Profiles;
cbProfile.Caption := Manager.Profile; //select???
cbProfileSelect(cbProfile);
end;
procedure TMain.ProjectsChanged(Sender: TObject);
begin
UpdateDocs; //immediately or delayed (OnIdle?)
end;
procedure TMain.UpdateDocs;
var
i: integer;
begin
lbPackages.Clear;
for i := 0 to Manager.Packages.Count - 1 do begin
if (Manager.Packages.ValueFromIndex[i] <> '')
and (Manager.Packages.Objects[i] <> nil) then
lbPackages.AddItem(Manager.Packages.Names[i], Manager.Packages.Objects[i]);
end;
end;
procedure TMain.mnConfigClick(Sender: TObject);
begin
Manager.BeginUpdate;
if not assigned(CfgWizard) then
CfgWizard := TCfgWizard.Create(self);
if CfgWizard.ShowModal <> mrCancel then begin
//all done
end;
Manager.EndUpdate;
end;
// ---------------- pages ------------------
procedure TMain.lbPackagesClick(Sender: TObject);
var
i: integer;
pkg: TDocPackage;
fn: string;
begin
i := lbPackages.ItemIndex; //clicked?
pkg := lbPackages.Items.Objects[i] as TDocPackage;
if pkg = nil then
exit; //not really created?
Manager.Package := pkg;
edDefOut.Text := Manager.RootDir + pkg.Name;
fn := pkg.ProjectFile; //initialized where?
edDescrDir.Text := pkg.DescrDir; //value?
edDescrLaz.Text := pkg.AltDir;
if fn <> '' then begin
if FileExists(fn) then
edXML.Lines.LoadFromFile(fn)
else
edXML.Lines.Clear;
end;
fn := pkg.IniFileName;
if FileExists(fn) then
edINI.Lines.LoadFromFile(fn);
//load units...
lbUnits.Items.BeginUpdate;
lbUnits.Clear;
{$IFDEF old}
for i := 0 to pkg.Units.Count - 1 do begin
//fn := Manager.UnitName(pkg.Inputs, i);
fn := pkg.Units.Names[i];
lbUnits.AddItem(fn, nil);
end;
{$ELSE}
pkg.EnumUnits(lbUnits.Items);
{$ENDIF}
lbUnits.Sorted := True;
lbUnits.Items.EndUpdate;
//remember selection
CurPkg := pkg;
CurUnit:='';
end;
procedure TMain.mnImportLpkClick(Sender: TObject);
var
pkName: string;
begin
if not dlgSelLpk.Execute then
exit;
pkName:=dlgSelLpk.FileName;
Manager.ImportLpk(pkName);
end;
procedure TMain.optUpdItemClick(Sender: TObject; Index: integer);
begin
SaveOptions;
end;
procedure TMain.edXMLExit(Sender: TObject);
begin
if edXML.Modified then begin
case MessageDlg('Project was changed', 'Save changes?',
mtConfirmation, mbYesNoCancel, 0) of
mrYes: edXML.Lines.SaveToFile(CurPkg.ProjectFile);
mrNo: exit;
else
edXML.SetFocus;
end;
end;
end;
// ------------------- actions ----------------------
procedure TMain.lbUnitsClick(Sender: TObject);
var
i: integer;
begin
i := lbUnits.ItemIndex;
if i < 0 then
CurUnit := ''
else
CurUnit := lbUnits.Items[i];
edUnit.Text := CurUnit; //further depends on swSingle
swSingle.Checked := True; //assume test single unit
ShowUpdate;
end;
procedure TMain.lbUnitsDblClick(Sender: TObject);
var
u: string;
begin
//edit unit description in LazDE form
//setup unit
//CurUnit := lbUnits.Items[lbUnits.ItemIndex]; - already set
u := Manager.Package.DescrFileName(CurUnit);
//create form
ModuleEditor := TModuleEditor.CreateFor(u, self);
//show it
ModuleEditor.Show;
end;
procedure TMain.swSingleClick(Sender: TObject);
begin
edUnit.Enabled := swSingle.Checked;
end;
(* FPDoc dry run, with logfile
*)
procedure TMain.buTestClick(Sender: TObject);
var
u: string;
begin
LogStart;
if swSingle.Checked then
u := CurUnit
else
u := '';
Manager.TestRun(CurPkg, u);
LogDone;
end;
procedure TMain.cbProfileSelect(Sender: TObject);
begin
Profile:=cbProfile.Caption;
Manager.Profile := Profile;
GetProfile;
end;
procedure TMain.buRefreshClick(Sender: TObject);
var
u: string;
begin
LogStart;
if swSingle.Checked then
u := CurUnit
else
u := '';
try
try
Manager.Update(CurPkg, u);
except
on e: Exception do
LogToFile(self, e.Message);
end;
finally
LogDone;
end;
end;
procedure TMain.buNewProfileClick(Sender: TObject);
begin
Profile := cbProfile.Caption;
if Profile = '' then
exit; //need name
if cbProfile.Items.IndexOf(Profile) < 0 then begin
cbProfile.AddItem(Profile, nil);
Manager.AddProfile(Profile);
end;
end;
procedure TMain.buMakeDocClick(Sender: TObject);
var
res: boolean;
begin
LogStart;
if swDefOut.Checked then
res := Manager.MakeDoc(Manager.Package, '', edDefOut.Text)
else
res := Manager.MakeDoc(Manager.Package, '', edOutput.Text);
LogDone;
if res then
StatusBar1.SimpleText := 'Done :-)'
else
StatusBar1.SimpleText := 'There were errors, see log';
end;
end.