lazarus/ide/idewindowhelp.pas
juha 7f7e7ada81 Format and clean uses sections.
git-svn-id: trunk@58629 -
2018-07-25 13:38:35 +00:00

507 lines
13 KiB
ObjectPascal

{
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. *
* *
***************************************************************************
Author: Mattias Gaertner
Abstract:
Help for IDE windows (controls).
}
unit IDEWindowHelp;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
// LCL
LCLProc, Controls, Dialogs, HelpIntfs,
// LazUtils
LazFileUtils, LazConfigStorage,
// IdeIntf
IDEDialogs,
// IDE
EnvironmentOpts, IDEOptionDefs, LazarusIDEStrConsts;
type
{ TIWHelpNode }
TIWHelpNode = class
private
FIsRoot: boolean;
FItems: TFPList;// list of TIWHelpNode
FHasHelp: Boolean;
FName: string;
FParent: TIWHelpNode;
FPath: string;
function GetChilds(Index: integer): TIWHelpNode;
function GetCount: integer;
procedure SetHasHelp(const AValue: Boolean);
procedure SetIsRoot(const AValue: boolean);
procedure SetName(const AValue: string);
procedure SetPath(const AValue: string);
procedure DoRemove(AChild: TIWHelpNode);
public
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure Assign(Source: TIWHelpNode);
function AddChild(const ChildName: string = '';
const ChildPath: string = ''): TIWHelpNode;
procedure Load(Config: TConfigStorage; const CfgPath: string);
procedure Save(Config: TConfigStorage; const CfgPath: string);
function FindByName(const ChildName: string): TIWHelpNode;
procedure DeleteLeavesWithoutHelp;
function GetFullPath: string;
public
property HasHelp: Boolean read FHasHelp write SetHasHelp;
property IsRoot: boolean read FIsRoot write SetIsRoot;// skip parent paths, except path of the top node
property Name: string read FName write SetName;
property Path: string read FPath write SetPath;
property Parent: TIWHelpNode read FParent;
property Count: integer read GetCount;
property Children[Index: integer]: TIWHelpNode read GetChilds; default;
end;
{ TIWHelpTree }
TIWHelpTree = class
private
FRoot: TIWHelpNode;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure Assign(Source: TIWHelpTree);
procedure Load(Config: TConfigStorage; const Path: string);
procedure Save(Config: TConfigStorage; const Path: string);
function ControlHasValidNamePath(AControl: TControl): Boolean;
function FindNodeForControl(AControl: TControl;
CreateIfNotExists: Boolean = false): TIWHelpNode;
procedure WriteDebugReport;
procedure DeleteLeavesWithoutHelp;
procedure InvokeHelp(AControl: TControl);
function CreateURL(AControl: TControl): string;
public
property Root: TIWHelpNode read FRoot;
end;
const
IDEWindowHelpTreeFile = 'docs/IDEWindowHelpTree.xml';
var
IDEWindowHelpNodes: TIWHelpTree = nil;
function GetIDEWindowHelpFilename: string;
procedure LoadIDEWindowHelp;
procedure SaveIDEWindowHelp;
implementation
function GetIDEWindowHelpFilename: string;
begin
Result:=AppendPathDelim(EnvironmentOptions.GetParsedLazarusDirectory)
+GetForcedPathDelims(IDEWindowHelpTreeFile);
end;
procedure LoadIDEWindowHelp;
var
Filename: String;
Config: TXMLOptionsStorage;
begin
if IDEWindowHelpNodes=nil then
IDEWindowHelpNodes:=TIWHelpTree.Create;
Filename:=GetIDEWindowHelpFilename;
try
Config:=TXMLOptionsStorage.Create(Filename,true);
if Config=nil then exit;
try
IDEWindowHelpNodes.Load(Config,'');
finally
Config.Free;
end;
except
on E: Exception do begin
IDEMessageDialog('Read error','Error reading file '+Filename+LineEnding+E.Message,
mtError,[mbOk]);
end;
end;
end;
procedure SaveIDEWindowHelp;
var
Filename: String;
Config: TConfigStorage;
begin
if IDEWindowHelpNodes=nil then exit;
Filename:=GetIDEWindowHelpFilename;
try
Config:=TXMLOptionsStorage.Create(Filename,false);
if Config=nil then exit;
try
IDEWindowHelpNodes.Save(Config,'');
Config.WriteToDisk;
finally
Config.Free;
end;
except
on E: Exception do begin
IDEMessageDialog(lisCodeToolsDefsWriteError,
Format(lisErrorWritingFile, [Filename+LineEnding+E.Message]),
mtError,[mbOk]);
end;
end;
end;
{ TIWHelpNode }
procedure TIWHelpNode.SetHasHelp(const AValue: Boolean);
begin
if FHasHelp=AValue then exit;
FHasHelp:=AValue;
end;
procedure TIWHelpNode.SetIsRoot(const AValue: boolean);
begin
if FIsRoot=AValue then exit;
FIsRoot:=AValue;
end;
procedure TIWHelpNode.SetName(const AValue: string);
begin
if FName=AValue then exit;
FName:=AValue;
end;
function TIWHelpNode.GetChilds(Index: integer): TIWHelpNode;
begin
Result:=TIWHelpNode(FItems[Index]);
end;
function TIWHelpNode.GetCount: integer;
begin
if FItems<>nil then
Result:=FItems.Count
else
Result:=0;
end;
procedure TIWHelpNode.SetPath(const AValue: string);
begin
if FPath=AValue then exit;
FPath:=AValue;
end;
procedure TIWHelpNode.DoRemove(AChild: TIWHelpNode);
begin
FItems.Remove(AChild);
AChild.FParent:=nil;
end;
constructor TIWHelpNode.Create;
begin
end;
destructor TIWHelpNode.Destroy;
begin
Clear;
if FParent<>nil then
FParent.DoRemove(Self);
FreeAndNil(FItems);
inherited Destroy;
end;
procedure TIWHelpNode.Clear;
var
i: Integer;
CurChild: TIWHelpNode;
begin
if FItems<>nil then begin
for i:=FItems.Count-1 downto 0 do begin
CurChild:=Children[i];
CurChild.FParent:=nil;
CurChild.Free;
end;
FreeAndNil(FItems);
end;
end;
procedure TIWHelpNode.Assign(Source: TIWHelpNode);
var
i: Integer;
SrcNode: TIWHelpNode;
NewNode: TIWHelpNode;
begin
Clear;
Name:=Source.Name;
Path:=Source.Path;
HasHelp:=Source.HasHelp;
IsRoot:=Source.IsRoot;
for i:=0 to Source.Count-1 do begin
SrcNode:=Source[i];
NewNode:=AddChild;
NewNode.Assign(SrcNode);
end;
end;
function TIWHelpNode.AddChild(const ChildName: string;
const ChildPath: string): TIWHelpNode;
begin
Result:=TIWHelpNode.Create;
Result.FParent:=Self;
Result.Name:=ChildName;
Result.Path:=ChildPath;
if FItems=nil then
FItems:=TFPList.Create;
FItems.Add(Result);
end;
procedure TIWHelpNode.Load(Config: TConfigStorage; const CfgPath: string);
var
NewChildCount: LongInt;
i: Integer;
NewChild: TIWHelpNode;
NewName: String;
begin
Clear;
NewName:=Config.GetValue(CfgPath+'Name','');
if NewName='' then exit;
Name:=NewName;
Path:=Config.GetValue(CfgPath+'Path','');
HasHelp:=Config.GetValue(CfgPath+'HasHelp',false);
IsRoot:=Config.GetValue(CfgPath+'IsRoot',false);
NewChildCount:=Config.GetValue(CfgPath+'ChildCount',0);
for i:=0 to NewChildCount-1 do begin
NewChild:=AddChild('');
NewChild.Load(Config,CfgPath+'Node'+IntToStr(i+1)+'/');
end;
end;
procedure TIWHelpNode.Save(Config: TConfigStorage; const CfgPath: string);
var
i: Integer;
begin
Config.SetDeleteValue(CfgPath+'Name',Name,'');
Config.SetDeleteValue(CfgPath+'Path',Path,'');
Config.SetDeleteValue(CfgPath+'HasHelp',HasHelp,false);
Config.SetDeleteValue(CfgPath+'IsRoot',IsRoot,false);
Config.SetDeleteValue(CfgPath+'ChildCount',Count,0);
for i:=0 to Count-1 do
Children[i].Save(Config,CfgPath+'Node'+IntToStr(i+1)+'/');
end;
function TIWHelpNode.FindByName(const ChildName: string): TIWHelpNode;
var
i: Integer;
begin
for i := 0 to Count-1 do begin
Result:=Children[i];
if CompareText(Result.Name,ChildName)=0 then exit;
end;
Result:=nil;
end;
procedure TIWHelpNode.DeleteLeavesWithoutHelp;
var
CurChild: TIWHelpNode;
i: Integer;
begin
for i:=Count-1 downto 0 do begin
CurChild:=Children[i];
CurChild.DeleteLeavesWithoutHelp;
if (CurChild.Count=0) and (not CurChild.HasHelp) then
CurChild.Free;
end;
end;
function TIWHelpNode.GetFullPath: string;
var
Node: TIWHelpNode;
SkipTillRoot: Boolean;
begin
Result:='';
Node:=Self;
SkipTillRoot:=false;
while Node<>nil do begin
if (Node.Parent=nil) or (not SkipTillRoot) then
Result:=Node.Path+Result;
if Node.IsRoot then
SkipTillRoot:=true;
Node:=Node.Parent;
end;
end;
{ TIWHelpTree }
constructor TIWHelpTree.Create;
begin
Clear;
end;
destructor TIWHelpTree.Destroy;
begin
Clear;
FreeAndNil(FRoot);
inherited Destroy;
end;
procedure TIWHelpTree.Clear;
begin
FreeAndNil(FRoot);
FRoot:=TIWHelpNode.Create;
Root.Name:='IDE windows and dialogs';
Root.Path:='IDE_Window:_';
end;
procedure TIWHelpTree.Assign(Source: TIWHelpTree);
begin
Clear;
Root.Assign(Source.Root);
end;
procedure TIWHelpTree.Load(Config: TConfigStorage; const Path: string);
begin
Clear;
FRoot.Load(Config,Path);
end;
procedure TIWHelpTree.Save(Config: TConfigStorage; const Path: string);
begin
FRoot.Save(Config,Path);
end;
function TIWHelpTree.ControlHasValidNamePath(AControl: TControl): Boolean;
begin
if (AControl=nil) then exit(false);
if AControl.Name='' then exit(false);
if AControl.Parent=nil then begin
Result:=true;
end else begin
Result:=ControlHasValidNamePath(AControl.Parent);
end;
end;
function TIWHelpTree.FindNodeForControl(AControl: TControl;
CreateIfNotExists: Boolean): TIWHelpNode;
function Find(TheControl: TControl): TIWHelpNode;
var
NextParent: TWinControl;
ParentHelpNode: TIWHelpNode;
CurName: String;
begin
Result:=nil;
//DebugLn('TIWHelpTree.FindNodeForControl.Find ',dbgsName(TheControl));
NextParent:=TheControl.Parent;
if NextParent=nil then begin
CurName:=TheControl.ClassName;
ParentHelpNode:=Root;
end else begin
CurName:=TheControl.Name;
if CurName='' then exit;
ParentHelpNode:=Find(NextParent);
if ParentHelpNode=nil then exit;
end;
Result:=ParentHelpNode.FindByName(CurName);
if (Result=nil) and CreateIfNotExists then begin
Result:=ParentHelpNode.AddChild(CurName,CurName);
//DebugLn('Find Create: ParentHelpNode=',ParentHelpNode.Name,' Result=',Result.Name);
end;
end;
begin
Result:=Find(AControl);
end;
procedure TIWHelpTree.WriteDebugReport;
procedure WriteNode(const Prefix: string; Node: TIWHelpNode);
var
i: Integer;
begin
if Node=nil then exit;
DebugLn(Prefix,'Name="',Node.Name,'" Path="',Node.Path,'" HashHelp=',dbgs(Node.HasHelp));
for i:=0 to Node.Count-1 do
WriteNode(Prefix+' ',Node[i]);
end;
begin
DebugLn('TIWHelpTree.WriteDebugReport =====================================');
WriteNode('',Root);
end;
procedure TIWHelpTree.DeleteLeavesWithoutHelp;
begin
Root.DeleteLeavesWithoutHelp;
end;
procedure TIWHelpTree.InvokeHelp(AControl: TControl);
var
URL: String;
begin
URL:=CreateURL(AControl);
if URL='' then exit;
ShowHelpOrError(URL,'Help for '+dbgsName(AControl),'text/html');
end;
function TIWHelpTree.CreateURL(AControl: TControl): string;
var
HelpNode: TIWHelpNode;
function Find(TheControl: TControl): TIWHelpNode;
var
NextParent: TWinControl;
ParentHelpNode: TIWHelpNode;
CurName: String;
begin
Result:=nil;
NextParent:=TheControl.Parent;
if NextParent=nil then begin
CurName:=TheControl.ClassName;
ParentHelpNode:=Root;
end else begin
CurName:=TheControl.Name;
ParentHelpNode:=Find(NextParent);
if ParentHelpNode=nil then exit;
end;
Result:=ParentHelpNode.FindByName(CurName);
if (Result<>nil) and Result.HasHelp then
HelpNode:=Result;
end;
begin
HelpNode:=nil;
// search a help for this control
Find(AControl);
if HelpNode=nil then begin
Result:='';
end else begin
Result:='http://wiki.lazarus.freepascal.org/'+HelpNode.GetFullPath;
end;
end;
finalization
FreeAndNil(IDEWindowHelpNodes);
end.