chmhelp: added components and example to load chm files in LCL applications

git-svn-id: trunk@37982 -
This commit is contained in:
mattias 2012-07-20 11:52:08 +00:00
parent 40fd2c1745
commit c582332a32
8 changed files with 630 additions and 4 deletions

5
.gitattributes vendored
View File

@ -383,6 +383,10 @@ components/anchordocking/minide/simplefrm.pas svneol=native#text/plain
components/anchordocking/minide/unit1.lfm svneol=native#text/plain components/anchordocking/minide/unit1.lfm svneol=native#text/plain
components/anchordocking/minide/unit1.pas svneol=native#text/plain components/anchordocking/minide/unit1.pas svneol=native#text/plain
components/chmhelp/README.txt svneol=native#text/plain components/chmhelp/README.txt svneol=native#text/plain
components/chmhelp/democontrol/ContextHelpDemo.lpi svneol=native#text/plain
components/chmhelp/democontrol/ContextHelpDemo.lpr svneol=native#text/plain
components/chmhelp/democontrol/ctxchmhelpunit1.lfm svneol=native#text/plain
components/chmhelp/democontrol/ctxchmhelpunit1.pas svneol=native#text/plain
components/chmhelp/democontrol/helpconnectionunit1.lfm svneol=native#text/plain components/chmhelp/democontrol/helpconnectionunit1.lfm svneol=native#text/plain
components/chmhelp/democontrol/helpconnectionunit1.pas svneol=native#text/plain components/chmhelp/democontrol/helpconnectionunit1.pas svneol=native#text/plain
components/chmhelp/democontrol/lhelpconnectiondemo1.lpi svneol=native#text/plain components/chmhelp/democontrol/lhelpconnectiondemo1.lpi svneol=native#text/plain
@ -413,6 +417,7 @@ components/chmhelp/lhelp/lnethttpdataprovider.pas svneol=native#text/plain
components/chmhelp/packages/help/Makefile svneol=native#text/plain components/chmhelp/packages/help/Makefile svneol=native#text/plain
components/chmhelp/packages/help/Makefile.compiled svneol=native#text/plain components/chmhelp/packages/help/Makefile.compiled svneol=native#text/plain
components/chmhelp/packages/help/Makefile.fpc svneol=native#text/plain components/chmhelp/packages/help/Makefile.fpc svneol=native#text/plain
components/chmhelp/packages/help/lazhelpchm.pas svneol=native#text/plain
components/chmhelp/packages/help/lhelpcontrol.pas svneol=native#text/plain components/chmhelp/packages/help/lhelpcontrol.pas svneol=native#text/plain
components/chmhelp/packages/help/lhelpcontrolpkg.lpk svneol=native#text/plain components/chmhelp/packages/help/lhelpcontrolpkg.lpk svneol=native#text/plain
components/chmhelp/packages/help/lhelpcontrolpkg.pas svneol=native#text/plain components/chmhelp/packages/help/lhelpcontrolpkg.pas svneol=native#text/plain

View File

@ -0,0 +1,92 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
<General>
<SessionStorage Value="InIDEConfig"/>
<MainUnit Value="0"/>
<Title Value="ContextHelpDemo"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<Icon Value="0"/>
</General>
<i18n>
<EnableI18N LFM="False"/>
</i18n>
<VersionInfo>
<StringTable ProductVersion=""/>
</VersionInfo>
<BuildModes Count="1">
<Item1 Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="2">
<Item1>
<PackageName Value="lhelpcontrolpkg"/>
</Item1>
<Item2>
<PackageName Value="LCL"/>
</Item2>
</RequiredPackages>
<Units Count="2">
<Unit0>
<Filename Value="ContextHelpDemo.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ContextHelpDemo"/>
</Unit0>
<Unit1>
<Filename Value="ctxchmhelpunit1.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="Form1"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="CtxCHMHelpUnit1"/>
</Unit1>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="ContextHelpDemo"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CompilerMessages>
<MsgFileName Value=""/>
</CompilerMessages>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,20 @@
program ContextHelpDemo;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, ctxchmhelpunit1, lhelpcontrolpkg;
{$R *.res}
begin
RequireDerivedFormResource := True;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

View File

@ -0,0 +1,54 @@
object Form1: TForm1
Left = 545
Height = 239
Top = 193
Width = 359
Caption = 'Form1'
ClientHeight = 239
ClientWidth = 359
OnCreate = FormCreate
LCLVersion = '1.1'
object Edit1: TEdit
Left = 71
Height = 22
Top = 72
Width = 225
HelpType = htKeyword
HelpKeyword = 'example/MainPage.html'
TabOrder = 0
Text = 'Edit1'
end
object Edit2: TEdit
Left = 71
Height = 22
Top = 128
Width = 224
HelpType = htKeyword
HelpKeyword = 'example/SecondPage.html'
TabOrder = 1
Text = 'Edit2'
end
object ShowHelpButton: TButton
Left = 70
Height = 20
Top = 20
Width = 128
AutoSize = True
Caption = 'ShowHelpButton'
OnClick = ShowHelpButtonClick
TabOrder = 2
end
object CHMHelpDatabase1: TCHMHelpDatabase
AutoRegister = True
Filename = '../../../tools/chmmaker/example.chm'
KeywordPrefix = 'example/'
left = 80
top = 168
end
object LHelpConnector1: TLHelpConnector
LHelpPath = '../lhelp/lhelp'
AutoRegister = True
left = 256
top = 168
end
end

View File

@ -0,0 +1,87 @@
{
Abstract:
This example demonstrates the chm help components.
TCHMLHelpDatabase handles help for a single chm file - it contains the
mapping from Keyword to page.
TLHelpConnector starts "lhelp" a chm viewer written in pure pascal.
How was the example created:
Put a TCHMHelpDatabase on a form.
Set AutoRegister to true.
Set KeywordPrefix to 'example/'
Set Filename to the path of the chm file '../../../tools/chmaker/example.chm'
You can create the example.chm with chmmaker (see the REDAME.txt
in the chmmaker directory).
Put a TLHelpConnector on the form.
Set AutoRegister to true.
Set LHelpPath to '../lhelp/lhelp'.
Put a TEdit on a form.
Set HelpType to htKeyword
Set HelpKeyword to 'example/MainPage.html'
Run the program.
Focus the edit field and press F1. lhelp will be started. lhelp will load
example.chm and show the page MainPage.html.
}
unit CtxCHMHelpUnit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
HelpIntfs, LazHelpIntf, LazHelpCHM;
const
{$IFDEF Darwin}
HelpShortcut = #$e2#$8c#$98'?';
{$ELSE}
HelpShortcut = 'F1'';
{$ENDIF}
type
{ TForm1 }
TForm1 = class(TForm)
CHMHelpDatabase1: TCHMHelpDatabase;
Edit1: TEdit;
Edit2: TEdit;
LHelpConnector1: TLHelpConnector;
ShowHelpButton: TButton;
procedure FormCreate(Sender: TObject);
procedure ShowHelpButtonClick(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateLCLHelpSystem;
Edit1.Text:='Edit1 - Press '+HelpShortcut+' for help';
Edit2.Text:='Edit2 - Press '+HelpShortcut+' for help';
end;
procedure TForm1.ShowHelpButtonClick(Sender: TObject);
begin
// This demonstrates how to show a help item manually:
ShowHelpOrErrorForKeyword('','example/AboutLazarus.html');
end;
{$R *.lfm}
end.

View File

@ -0,0 +1,355 @@
{
*****************************************************************************
* *
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
* for details about the copyright. *
* *
* This program 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. *
* *
*****************************************************************************
Author: Mattias Gaertner
Abstract:
Methods and types for simple CHM help using chm viewer "lhelp".
}
unit LazHelpCHM;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LazHelpIntf, LazConfigStorage, HelpIntfs,
Dialogs, Forms, LazLogger, FileUtil, LHelpControl;
const
CHMMimeType = 'application/chm';
CHMPathParam = 'path';
type
{ TCHMHelpDatabase
KeywordPrefix: if set, then the database will handle all Keywords
beginning with this value. And when the path is created by replacing
the prefix with the BaseURL.
For example:
Create a chm. For example build and run chmmaker in lazarus/tools/chmmaker
to create the example.chm (lazarus/tools/chmmaker/example.chm).
Put a TCHMHelpDatabase on a form.
Set AutoRegister to true.
Set KeywordPrefix to 'example/'
Set CHM file to '../../../tools/chmmaker/example.chm'
Put a TLHelpRemoteViewer on the form.
Set AutoRegister to true.
Set LHelpPath to the path of lhelp. E.g. '../../lhelp/lhelp'
Put a TEdit on a form.
Set HelpType to htKeyword
Set HelpKeyword to 'example/MainPage.html'
Run the program.
Focus the edit field and press F1. The page 'MainPage.html' will be shown.
}
TCHMHelpDatabase = class(THelpDatabase)
private
FFilename: string;
FHelpNode: THelpNode;
FKeywordPrefix: string;
procedure SetFilename(AValue: string);
procedure SetKeywordPrefix(AValue: string);
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
function ShowHelp({%H-}Query: THelpQuery; {%H-}BaseNode, NewNode: THelpNode;
{%H-}QueryItem: THelpQueryItem;
var ErrMsg: string): TShowHelpResult; override;
function ShowURL(const URL, Title: string;
var ErrMsg: string): TShowHelpResult; virtual;
function GetNodesForKeyword(const HelpKeyword: string;
var ListOfNodes: THelpNodeQueryList;
var ErrMsg: string): TShowHelpResult; override;
procedure Load(Storage: TConfigStorage); override;
procedure Save(Storage: TConfigStorage); override;
published
property AutoRegister;
property Filename: string read FFilename write SetFilename;
property KeywordPrefix: string read FKeywordPrefix write SetKeywordPrefix;
end;
type
TOnFindLHelp = procedure(var Path: string) of object;
{ TLHelpConnector }
TLHelpConnector = class(THelpViewer)
private
FConnection: TLHelpConnection;
FLHelpPath: string;
FOnFindLHelp: TOnFindLHelp;
procedure SetLHelpPath(AValue: string);
public
constructor Create(TheOwner: TComponent); override;
function ShowNode(Node: THelpNode; var ErrMsg: string): TShowHelpResult; override;
procedure Assign(Source: TPersistent); override;
procedure Load(Storage: TConfigStorage); override;
procedure Save(Storage: TConfigStorage); override;
function GetLocalizedName: string; override;
property OnFindLHelp: TOnFindLHelp read FOnFindLHelp write FOnFindLHelp;
property Connection: TLHelpConnection read FConnection;
published
property LHelpPath: string read FLHelpPath write SetLHelpPath;
property AutoRegister;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('System',[TCHMHelpDatabase,TLHelpConnector]);
end;
{ TLHelpConnector }
procedure TLHelpConnector.SetLHelpPath(AValue: string);
begin
if FLHelpPath=AValue then Exit;
FLHelpPath:=AValue;
end;
constructor TLHelpConnector.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
AddSupportedMimeType(CHMMimeType);
end;
function TLHelpConnector.ShowNode(Node: THelpNode; var ErrMsg: string
): TShowHelpResult;
var
Path: String;
IPCFile: String;
URLScheme: string;
URLPath: string;
URLParams: string;
CHMFilename: String;
SubPath: String;
Response: TLHelpResponse;
s: String;
begin
debugln(['TLHelpConnector.ShowNode START URL="',Node.URL,'"']);
Result:=shrViewerError;
ErrMsg:='';
if (not Node.URLValid) then begin
ErrMsg:='TLHelpConnector.ShowNode Node.URLValid=false';
exit;
end;
if (Node.URL='') then begin
ErrMsg:='TLHelpConnector.ShowNode Node.URL empty';
exit;
end;
SplitURL(Node.URL,URLScheme,URLPath,URLParams);
CHMFilename:=SetDirSeparators(URLPath);
if not FileExistsUTF8(CHMFilename) then begin
ErrMsg:='chm file "'+CHMFilename+'" not found';
exit;
end;
SubPath:='';
if LeftStr(URLParams,length(CHMPathParam)+1)=CHMPathParam+'=' then begin
SubPath:=URLParams;
Delete(SubPath,1,length(CHMPathParam)+1);
end;
if Connection=nil then begin
// create a connection to lhelp:
FConnection := TLHelpConnection.Create;
Connection.ProcessWhileWaiting := @Application.ProcessMessages;
end;
if Connection.ServerRunning = false then begin
IPCFile:=ExtractFileName(Application.ExeName);
IPCFile+='lhelpconnector';
{$IFDEF Unix}
if FileExistsUTF8('/tmp/'+IPCFile) then
DeleteFileUTF8('/tmp/'+IPCFile);
{$ENDIF}
// get lhelp path
Path:=LHelpPath;
if Assigned(OnFindLHelp) then
OnFindLHelp(Path);
// append exe extension
if (ExtractFileExt(Path)='') and (GetExeExt<>'') then
Path:=Path+GetExeExt;
// search in Path
if (Path<>'') and (ExtractFilePath(Path)='') then begin
s:=FindDefaultExecutablePath(Path);
if s<>'' then Path:=s;
end;
{$IFDEF darwin}
// search exe in application bundle
if DirectoryExistsUTF8(Path+'.app') then
Path:=Path+'.app/Contents/MacOS/'+ExtractFileName(Path);
{$ENDIF}
if not FileExistsUTF8(Path) then begin
ErrMsg:='The chm viewer program lhelp was not found at "'+Path+'"';
exit;
end;
Connection.StartHelpServer(IPCFile,Path);
end;
Response:=Connection.OpenURL(CHMFilename,SubPath);
case Response of
srSuccess: exit(shrSuccess);
srNoAnswer: ErrMsg:='lhelp does not respond';
srInvalidFile: ErrMsg:='lhelp can not open the file "'+CHMFilename+'"';
srInvalidURL,srInvalidContext: ErrMsg:='lhelp can not find the help entry "'+SubPath+'"';
else
ErrMsg:='Something is wrong with lhelp';
end;
end;
procedure TLHelpConnector.Assign(Source: TPersistent);
var
Src: TLHelpConnector;
begin
if Source is TLHelpConnector then begin
Src:=TLHelpConnector(Source);
LHelpPath:=Src.LHelpPath;
end;
inherited Assign(Source);
end;
procedure TLHelpConnector.Load(Storage: TConfigStorage);
begin
inherited Load(Storage);
LHelpPath:=Storage.GetValue('LHelp/Path','');
end;
procedure TLHelpConnector.Save(Storage: TConfigStorage);
begin
inherited Save(Storage);
Storage.SetDeleteValue('LHelp/Path',LHelpPath,'');
end;
function TLHelpConnector.GetLocalizedName: string;
begin
Result:='LHelp Connector';
end;
{ TCHMHelpDatabase }
procedure TCHMHelpDatabase.SetFilename(AValue: string);
begin
if FFilename=AValue then Exit;
FFilename:=AValue;
end;
procedure TCHMHelpDatabase.SetKeywordPrefix(AValue: string);
begin
if FKeywordPrefix=AValue then Exit;
FKeywordPrefix:=AValue;
end;
constructor TCHMHelpDatabase.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
AddSupportedMimeType(CHMMimeType);
end;
destructor TCHMHelpDatabase.Destroy;
begin
FreeAndNil(FHelpNode);
inherited Destroy;
end;
function TCHMHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
): TShowHelpResult;
begin
ErrMsg:='';
Result:=shrContextNotFound;
if NewNode.URLValid then begin
Result:=ShowURL(NewNode.URL,NewNode.Title,ErrMsg);
end else begin
Result:=shrContextNotFound;
ErrMsg:='TCHMHelpDatabase.ShowHelp Node.URLValid=false Node.URL="'+NewNode.URL+'"';
end;
end;
function TCHMHelpDatabase.ShowURL(const URL, Title: string; var ErrMsg: string
): TShowHelpResult;
var
Viewer: THelpViewer;
Node: THelpNode;
begin
//DebugLn('TCHMHelpDatabase.ShowURL A URL="',URL,'" Title="',Title,'"');
if not FileExistsUTF8(Filename) then begin
ErrMsg:='chm help file "'+Filename+'" not found';
exit(shrDatabaseNotFound);
end;
// find HTML viewer
Result:=FindViewer(CHMMimeType,ErrMsg,Viewer);
if Result<>shrSuccess then exit;
// call viewer
Node:=nil;
try
Node:=THelpNode.CreateURL(Self,Title,URL);
Result:=Viewer.ShowNode(Node,ErrMsg);
finally
Node.Free;
end;
end;
function TCHMHelpDatabase.GetNodesForKeyword(const HelpKeyword: string;
var ListOfNodes: THelpNodeQueryList; var ErrMsg: string): TShowHelpResult;
var
Path: String;
begin
Result:=inherited GetNodesForKeyword(HelpKeyword, ListOfNodes, ErrMsg);
if Result<>shrSuccess then exit;
if not (csDesigning in ComponentState)
and (KeywordPrefix<>'')
and (LeftStr(HelpKeyword,length(KeywordPrefix))=KeywordPrefix) then begin
// HelpKeyword starts with KeywordPrefix -> add default node
if FHelpNode=nil then
FHelpNode:=THelpNode.CreateURL(Self,'','');
Path:=copy(HelpKeyword,length(KeywordPrefix)+1,length(HelpKeyword));
FHelpNode.Title:='Show page '+Path+' of '+ExtractFileName(Filename);
FHelpNode.URL:='chmfile://'+FilenameToURLPath(Filename)+'?'+CHMPathParam+'='+Path;
CreateNodeQueryListAndAdd(FHelpNode,nil,ListOfNodes,true);
end;
end;
procedure TCHMHelpDatabase.Load(Storage: TConfigStorage);
begin
inherited Load(Storage);
KeywordPrefix:=Storage.GetValue('KeywordPrefix','');
Filename:=Storage.GetValue('Filename','');
end;
procedure TCHMHelpDatabase.Save(Storage: TConfigStorage);
begin
inherited Save(Storage);
Storage.SetDeleteValue('KeywordPrefix',KeywordPrefix,'');
Storage.SetDeleteValue('Filename',Filename, '');
end;
end.

View File

@ -21,12 +21,18 @@
<Description Value="This package contains unit that will allow you to &quot;remote control&quot; the program LHelp."/> <Description Value="This package contains unit that will allow you to &quot;remote control&quot; the program LHelp."/>
<License Value="Modified LGPL-2, same as LCL"/> <License Value="Modified LGPL-2, same as LCL"/>
<Version Minor="2"/> <Version Minor="2"/>
<Files Count="1"> <Files Count="2">
<Item1> <Item1>
<Filename Value="lhelpcontrol.pas"/> <Filename Value="lhelpcontrol.pas"/>
<UnitName Value="LHelpControl"/> <UnitName Value="LHelpControl"/>
</Item1> </Item1>
<Item2>
<Filename Value="lazhelpchm.pas"/>
<HasRegisterProc Value="True"/>
<UnitName Value="LazHelpCHM"/>
</Item2>
</Files> </Files>
<Type Value="RunAndDesignTime"/>
<RequiredPkgs Count="2"> <RequiredPkgs Count="2">
<Item1> <Item1>
<PackageName Value="LCL"/> <PackageName Value="LCL"/>

View File

@ -7,8 +7,15 @@ unit lhelpcontrolpkg;
interface interface
uses uses
LHelpControl; LHelpControl, LazHelpCHM, LazarusPackageIntf;
implementation implementation
procedure Register;
begin
RegisterUnit('LazHelpCHM', @LazHelpCHM.Register);
end;
initialization
RegisterPackage('lhelpcontrolpkg', @Register);
end. end.