lazarus/examples/idehelp/myidehelp.pas

985 lines
34 KiB
ObjectPascal

{ Demo package to show the various help types of the IDE.
Copyright (C) 2012 Mattias Gaertner mattias@freepascal.org
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.
}
{
ToDos:
Examples:
- help for messages: use codetools TFPCMsgFile
- predefined identifiers: cardinal, longint
- predefined procs: exit, break, continue, writeln
- help for sources
- HTML help - showing an URL
- IDE dialogs / wiki:
- custom dialogs / wiki:
- fpc compiler options:
Wiki:
- explain all on the wiki
Help for:
- Other messages: Linker errors, fpcres errors
- FPC keyword: context, for example 'var' can be a section or a parameter modifier
}
unit MyIDEHelp;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
// LCL
LCLProc, Dialogs, ComCtrls, StdCtrls, ExtCtrls, LazHelpIntf, HelpIntfs,
// LazUtils
LazConfigStorage,
// IdeIntf
IDEDialogs, IDEHelpIntf, IDEOptionsIntf, IDEOptEditorIntf, BaseIDEIntf;
const
MyHelpConfigFilename = 'demo_myidehelp.xml';
MyHelpOptionID: integer = 10000; // an arbitrary number, choose a big number
// to append your options frame as last / below the others
var
IDEHelpPkgName: string = 'DemoIDEHelp';
type
{ TMyHelpDatabase
This is base class for all the demonstrated IDE help databases.
In your help database you would probably combine all the features you
want into a single class. }
TMyHelpDatabase = class(THelpDatabase)
private
FEnabled: boolean;
FModified: boolean;
procedure SetEnabled(AValue: boolean);
public
constructor Create(TheOwner: TComponent); override;
procedure LoadFromConfig(Config: TConfigStorage); virtual; // called in Register
procedure SaveToConfig(Config: TConfigStorage); virtual; // called by TMyHelpSetupDialog.WriteSettings
property Enabled: boolean read FEnabled write SetEnabled; // switch to disable single example databases
property Modified: boolean read FModified write FModified;
end;
{ TMyFPCKeywordHelpDatabase
Help for FPC keywords like 'procedure'.
Actually FPC keywords are a special case. Any LCL TControl can set its
HelpKeyword property and invoke keyword help.
Notes: Do not forget to register this using HelpDatabases.CreateHelpDatabase!
You can combine all your databases into one. }
TMyFPCKeywordHelpDatabase = class(TMyHelpDatabase)
private
FAllKeywordNode: THelpNode;
FKeywordToText: TStrings;
procedure SetKeywordToText(AValue: TStrings);
public
const
DefaultKeyWordToText = 'procedure=Named code block';
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
function GetNodesForKeyword(const HelpKeyword: string;
var ListOfNodes: THelpNodeQueryList; var {%H-}ErrMsg: string
): TShowHelpResult; override;
function ShowHelp(Query: THelpQuery; {%H-}BaseNode, {%H-}NewNode: THelpNode;
{%H-}QueryItem: THelpQueryItem;
var {%H-}ErrMsg: string): TShowHelpResult; override;
procedure LoadFromConfig(Config: TConfigStorage); override;
procedure SaveToConfig(Config: TConfigStorage); override;
property KeywordToText: TStrings read FKeywordToText write SetKeywordToText; // every line has the format: Keyword=Text
end;
var
MyFPCKeywordHelpDatabase: TMyFPCKeywordHelpDatabase;
type
{ TMyDirectiveHelpDatabase
Help for FPC and Lazarus IDE directives like '$mode' and '%H'
Notes: Do not forget to register this using HelpDatabases.CreateHelpDatabase!
You can combine all your databases into one. }
TMyDirectiveHelpDatabase = class(TMyHelpDatabase)
private
FAllDirectiveNode: THelpNode;
FFPCDirectiveToText: TStrings;
FIDEDirectiveToText: TStrings;
procedure SetFPCDirectiveToText(AValue: TStrings);
procedure SetIDEDirectiveToText(AValue: TStrings);
public
const
DefaultFPCDirectiveToText = 'mode=Set the syntax, e.g. fpc, objfpc, delphi, macpas, tp';
DefaultIDEDirectiveToText = 'H=Use {%H-} to hide any compiler message at that source position in IDE messages window.';
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
function GetNodesForDirective(const HelpDirective: string;
var ListOfNodes: THelpNodeQueryList; var {%H-}ErrMsg: string
): TShowHelpResult; override;
function ShowHelp(Query: THelpQuery; {%H-}BaseNode, {%H-}NewNode: THelpNode;
{%H-}QueryItem: THelpQueryItem;
var {%H-}ErrMsg: string): TShowHelpResult; override;
procedure LoadFromConfig(Config: TConfigStorage); override;
procedure SaveToConfig(Config: TConfigStorage); override;
property FPCDirectiveToText: TStrings read FFPCDirectiveToText write SetFPCDirectiveToText; // every line has the format: Keyword=Text
property IDEDirectiveToText: TStrings read FIDEDirectiveToText write SetIDEDirectiveToText; // every line has the format: Keyword=Text
end;
var
MyDirectiveHelpDatabase: TMyDirectiveHelpDatabase;
type
{ TMyMessagesHelpDatabase
Help for messages, for example compiler messages like 'identifier not found'.
Notes: Do not forget to register this using HelpDatabases.CreateHelpDatabase!
You can combine all your databases into one. }
TMyMessagesHelpDatabase = class(TMyHelpDatabase)
private
FAllMessageNode: THelpNode;
public
constructor Create(TheOwner: TComponent); override;
function GetNodesForMessage(const AMessage: string; MessageParts: TStrings;
var ListOfNodes: THelpNodeQueryList; var ErrMsg: string
): TShowHelpResult; override;
function ShowHelp(Query: THelpQuery; {%H-}BaseNode, {%H-}NewNode: THelpNode;
{%H-}QueryItem: THelpQueryItem;
var {%H-}ErrMsg: string): TShowHelpResult; override;
end;
var
MyMessagesHelpDatabase: TMyMessagesHelpDatabase;
type
{ TMyContextHelpDatabase
Help for HelpContext numbers. The IDE does not use this kind itself, because
there is a risk that two packages have overlapping numbers.
This help type is useful for your own applications, because a simple number
is used to identify help and any LCL TControl can set its HelpContext
property, so you can set this via the object inspector.
Notes: Do not forget to register this using HelpDatabases.CreateHelpDatabase!
You can combine all your databases into one. }
TMyContextHelpDatabase = class(TMyHelpDatabase)
private
FAllContextNode: THelpNode;
FContextToMessage: TStrings;
procedure SetContextToMessage(AValue: TStrings);
public
const
DefaultContextToMessage = '3456=A help text for helpcontext 3456';
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
function GetNodesForContext(HelpContext: THelpContext;
var ListOfNodes: THelpNodeQueryList; var ErrMsg: string
): TShowHelpResult; override;
function ShowHelp(Query: THelpQuery; {%H-}BaseNode, {%H-}NewNode: THelpNode;
{%H-}QueryItem: THelpQueryItem;
var {%H-}ErrMsg: string): TShowHelpResult; override;
procedure LoadFromConfig(Config: TConfigStorage); override;
procedure SaveToConfig(Config: TConfigStorage); override;
property ContextToMessage: TStrings read FContextToMessage write SetContextToMessage; // every line has the format: DecimalNumber=Text
end;
var
MyContextHelpDatabase: TMyContextHelpDatabase;
type
{ TMyClassesHelpDatabase
Help for classes.
At the moment (0.9.31) the IDE does not use this kind itself.
Notes: Do not forget to register this using HelpDatabases.CreateHelpDatabase!
You can combine all your databases into one. }
TMyClassesHelpDatabase = class(TMyHelpDatabase)
private
FAllClassNode: THelpNode;
public
function GetNodesForClass(AClass: TClass; var ListOfNodes: THelpNodeQueryList;
var ErrMsg: string): TShowHelpResult; override;
function ShowHelp(Query: THelpQuery; {%H-}BaseNode, {%H-}NewNode: THelpNode;
{%H-}QueryItem: THelpQueryItem;
var {%H-}ErrMsg: string): TShowHelpResult; override;
end;
var
MyClassesHelpDatabase: TMyClassesHelpDatabase;
type
{ TMyPascalSourcesHelpDatabase
Help for pascal sources.
Notes: Do not forget to register this using HelpDatabases.CreateHelpDatabase!
You can combine all your databases into one. }
TMyPascalSourcesHelpDatabase = class(TMyHelpDatabase)
private
FAllSourceNode: THelpNode;
public
function GetNodesForClass(AClass: TClass; var ListOfNodes: THelpNodeQueryList;
var ErrMsg: string): TShowHelpResult; override;
function ShowHelp(Query: THelpQuery; {%H-}BaseNode, {%H-}NewNode: THelpNode;
{%H-}QueryItem: THelpQueryItem;
var {%H-}ErrMsg: string): TShowHelpResult; override;
end;
var
MyPascalSourcesHelpDatabase: TMyPascalSourcesHelpDatabase;
type
{ TMyHelpSetupDialog }
TMyHelpSetupDialog = class(TAbstractIDEOptionsEditor)
ClassesCheckBox: TCheckBox;
ClassesNoteLabel: TLabel;
ContextEnableCheckBox: TCheckBox;
ContextMemo: TMemo;
ContextNoteLabel: TLabel;
DirectivesEnableCheckBox: TCheckBox;
DirectivesSplitter: TSplitter;
FPCDirectivesMemo: TMemo;
DirectivesNoteLabel: TLabel;
FPCDirectivesGroupBox: TGroupBox;
FPCKeywordsEnableCheckBox: TCheckBox;
FPCKeywordsMemo: TMemo;
FPCKeywordsNoteLabel: TLabel;
IDEDirectivesGroupBox: TGroupBox;
IDEDirectivesMemo: TMemo;
MessagesEnableCheckBox: TCheckBox;
MessagesNoteLabel: TLabel;
PageControl1: TPageControl;
FPCKeywordsTabSheet: TTabSheet;
DirectivesTabSheet: TTabSheet;
MessagesTabSheet: TTabSheet;
ContextTabSheet: TTabSheet;
PascalSourcesEnabledCheckBox: TCheckBox;
PascalSourcesNoteLabel: TLabel;
PascalSourcesTabSheet: TTabSheet;
ClassesTabSheet: TTabSheet;
private
public
HelpShortCutAsText: string;
function GetTitle: String; override;
procedure ReadSettings({%H-}AOptions: TAbstractIDEOptions); override;
procedure Setup({%H-}ADialog: TAbstractOptionsEditorDialog); override;
class function SupportedOptionsClass: TAbstractIDEOptionsClass; override;
procedure WriteSettings({%H-}AOptions: TAbstractIDEOptions); override;
end;
procedure LoadSaveMyIDEOptions(Filename: string; Load: boolean);
procedure TrimStrings(List: TStrings);
function AssignTrimmedStrings(Src, Dest: TStrings): boolean; // true if changed
procedure Register;
implementation
procedure LoadSaveMyIDEOptions(Filename: string; Load: boolean);
var
Config: TConfigStorage;
begin
Config:=GetIDEConfigStorage(Filename,Load);
try
Config.AppendBasePath('FPCKeywords');
if Load then
MyFPCKeywordHelpDatabase.LoadFromConfig(Config)
else
MyFPCKeywordHelpDatabase.SaveToConfig(Config);
Config.UndoAppendBasePath;
Config.AppendBasePath('Directives');
if Load then
MyDirectiveHelpDatabase.LoadFromConfig(Config)
else
MyDirectiveHelpDatabase.SaveToConfig(Config);
Config.UndoAppendBasePath;
Config.AppendBasePath('Messages');
if Load then
MyMessagesHelpDatabase.LoadFromConfig(Config)
else
MyMessagesHelpDatabase.SaveToConfig(Config);
Config.UndoAppendBasePath;
Config.AppendBasePath('Contexts');
if Load then
MyContextHelpDatabase.LoadFromConfig(Config)
else
MyContextHelpDatabase.SaveToConfig(Config);
Config.UndoAppendBasePath;
Config.AppendBasePath('Classes');
if Load then
MyClassesHelpDatabase.LoadFromConfig(Config)
else
MyClassesHelpDatabase.SaveToConfig(Config);
Config.UndoAppendBasePath;
Config.AppendBasePath('PascalSources');
if Load then
MyPascalSourcesHelpDatabase.LoadFromConfig(Config)
else
MyPascalSourcesHelpDatabase.SaveToConfig(Config);
Config.UndoAppendBasePath;
finally
Config.Free;
end;
end;
procedure TrimStrings(List: TStrings);
var
i: Integer;
Line: String;
begin
if List=nil then exit;
for i:=List.Count-1 downto 0 do begin
Line:=Trim(List[i]);
if Line='' then
List.Delete(i)
else if Line<>List[i] then
List[i]:=Line;
end;
end;
function AssignTrimmedStrings(Src, Dest: TStrings): boolean;
var
SrcIndex: Integer;
DstIndex: Integer;
Line: String;
begin
Result:=false;
SrcIndex:=0;
DstIndex:=0;
while SrcIndex<Src.Count-1 do begin
Line:=Trim(Src[SrcIndex]);
inc(SrcIndex);
if Line<>'' then continue;
if DstIndex=Dest.Count then begin
Dest.Add(Line);
Result:=true;
end else if Dest[DstIndex]<>Line then begin
Dest[DstIndex]:=Line;
Result:=true;
end;
inc(DstIndex);
end;
while Dest.Count>DstIndex do begin
Result:=true;
Dest.Delete(Dest.Count-1);
end;
end;
procedure Register;
begin
// register help databases
// For demonstration purpose there is one help database per help type.
// Normally you would combine them into one database.
MyFPCKeywordHelpDatabase:=TMyFPCKeywordHelpDatabase(
HelpDatabases.CreateHelpDatabase('MyFPCKeyWordHelpDB',TMyFPCKeywordHelpDatabase,true));
MyDirectiveHelpDatabase:=TMyDirectiveHelpDatabase(
HelpDatabases.CreateHelpDatabase('MyDirectiveHelpDB',TMyDirectiveHelpDatabase,true));
MyMessagesHelpDatabase:=TMyMessagesHelpDatabase(
HelpDatabases.CreateHelpDatabase('MyMessagesHelpDB',TMyMessagesHelpDatabase,true));
MyContextHelpDatabase:=TMyContextHelpDatabase(
HelpDatabases.CreateHelpDatabase('MyContextHelpDB',TMyContextHelpDatabase,true));
MyClassesHelpDatabase:=TMyClassesHelpDatabase(
HelpDatabases.CreateHelpDatabase('MyClassHelpDB',TMyClassesHelpDatabase,true));
MyPascalSourcesHelpDatabase:=TMyPascalSourcesHelpDatabase(
HelpDatabases.CreateHelpDatabase('MyPascalSourcesHelpDB',TMyPascalSourcesHelpDatabase,true));
// register frame in the IDE options to setup "My IDE help"
MyHelpOptionID:=RegisterIDEOptionsEditor(GroupHelp,TMyHelpSetupDialog,MyHelpOptionID)^.Index;
LoadSaveMyIDEOptions(MyHelpConfigFilename,true);
end;
{ TMyPascalSourcesHelpDatabase }
function TMyPascalSourcesHelpDatabase.GetNodesForClass(AClass: TClass;
var ListOfNodes: THelpNodeQueryList; var ErrMsg: string): TShowHelpResult;
var
Title: String;
begin
ErrMsg:='';
Result:=shrHelpNotFound;
if (csDesigning in ComponentState) or (not Enabled) then exit;
if not AClass.InheritsFrom(TMyHelpDatabase) then exit;
// this help database knows this context
Title:='Help for source';
// => add a node, so that if there are several possibilities the IDE can
// show the user a dialog to choose
if FAllSourceNode=nil then
FAllSourceNode:=THelpNode.CreateURL(Self,'','');
FAllSourceNode.Title:=Title;
CreateNodeQueryListAndAdd(FAllSourceNode,nil,ListOfNodes,true);
Result:=shrSuccess;
end;
function TMyPascalSourcesHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
): TShowHelpResult;
var
Msg: String;
PascalQuery: THelpQueryPascalContexts;
begin
ErrMsg:='';
Result:=shrHelpNotFound;
if not (Query is THelpQueryClass) then exit;
PascalQuery:=THelpQueryPascalContexts(Query);
debugln(['TMyPascalSourcesHelpDatabase.ShowHelp PascalSource="',PascalQuery.ListOfPascalHelpContextList.Count,'"']);
Msg:='This is a demonstration how to get help for a pascal identifier. See package '+IDEHelpPkgName;
IDEMessageDialog('My pascal source help',
'ToDo: implement me:'+LineEnding+LineEnding
+Msg,mtInformation,[mbOk]);
Result:=shrSuccess;
end;
{ TMyClassesHelpDatabase }
function TMyClassesHelpDatabase.GetNodesForClass(AClass: TClass;
var ListOfNodes: THelpNodeQueryList; var ErrMsg: string): TShowHelpResult;
var
Title: String;
begin
ErrMsg:='';
Result:=shrHelpNotFound;
if (csDesigning in ComponentState) or (not Enabled) then exit;
if not AClass.InheritsFrom(TMyHelpDatabase) then exit;
// this help database knows this context
Title:='Help for class';
// => add a node, so that if there are several possibilities the IDE can
// show the user a dialog to choose
if FAllClassNode=nil then
FAllClassNode:=THelpNode.CreateURL(Self,'','');
FAllClassNode.Title:=Title;
CreateNodeQueryListAndAdd(FAllClassNode,nil,ListOfNodes,true);
Result:=shrSuccess;
end;
function TMyClassesHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
): TShowHelpResult;
var
ClassQuery: THelpQueryClass;
Msg: String;
begin
ErrMsg:='';
Result:=shrHelpNotFound;
if not (Query is THelpQueryClass) then exit;
ClassQuery:=THelpQueryClass(Query);
debugln(['TMyClassHelpDatabase.ShowHelp Class="',dbgsname(ClassQuery.TheClass)]);
Msg:='This is a demonstration how to get help for a class. See package '+IDEHelpPkgName;
IDEMessageDialog('My class help',
'The class "'+ClassQuery.TheClass.ClassName+'":'+LineEnding+LineEnding
+Msg,mtInformation,[mbOk]);
Result:=shrSuccess;
end;
{ TMyHelpDatabase }
procedure TMyHelpDatabase.SetEnabled(AValue: boolean);
begin
if FEnabled=AValue then Exit;
FEnabled:=AValue;
Modified:=true;
end;
constructor TMyHelpDatabase.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
Enabled:=true;
end;
procedure TMyHelpDatabase.LoadFromConfig(Config: TConfigStorage);
begin
Enabled:=Config.GetValue('Enabled',true);
end;
procedure TMyHelpDatabase.SaveToConfig(Config: TConfigStorage);
begin
Config.SetDeleteValue('Enabled',Enabled,true);
end;
{ TMyHelpSetupDialog }
function TMyHelpSetupDialog.GetTitle: String;
begin
Result:='My IDE Help';
end;
procedure TMyHelpSetupDialog.ReadSettings(AOptions: TAbstractIDEOptions);
begin
// fpc keywords
FPCKeywordsEnableCheckBox.Checked:=MyFPCKeywordHelpDatabase.Enabled;
FPCKeywordsMemo.Text:=MyFPCKeywordHelpDatabase.KeywordToText.Text;
// directives
DirectivesEnableCheckBox.Checked:=MyDirectiveHelpDatabase.Enabled;
FPCDirectivesMemo.Text:=MyDirectiveHelpDatabase.FPCDirectiveToText.Text;
IDEDirectivesMemo.Text:=MyDirectiveHelpDatabase.IDEDirectiveToText.Text;
// messages
MessagesEnableCheckBox.Checked:=MyMessagesHelpDatabase.Enabled;
// context
ContextEnableCheckBox.Checked:=MyContextHelpDatabase.Enabled;
ContextMemo.Text:=MyContextHelpDatabase.ContextToMessage.Text;
// classes
ClassesCheckBox.Checked:=MyClassesHelpDatabase.Enabled;
// pascal sources
PascalSourcesEnabledCheckBox.Checked:=MyPascalSourcesHelpDatabase.Enabled;
end;
procedure TMyHelpSetupDialog.Setup(ADialog: TAbstractOptionsEditorDialog);
begin
HelpShortCutAsText:='F1';
IDEHelpPkgName:='DemoIDEHelp';
// fpc keywords
FPCKeywordsTabSheet.Caption:='FPC keywords';
FPCKeywordsNoteLabel.Caption:='Simple help for FPC keywords. Installed by package '+IDEHelpPkgName+'.'
+' You get this help when you press the help key ('+HelpShortCutAsText+') in the source editor and caret is not on an identifier.'
+' Each line has the format "keyword=text" without the quotes. For example "repeat=This keyword starts a repeat-until loop."';
FPCKeywordsEnableCheckBox.Caption:='Enable';
// directives
DirectivesTabSheet.Caption:='Directives';
DirectivesNoteLabel.Caption:='Simple help for FPC and IDE directives. Installed by package '+IDEHelpPkgName+'.'
+' You get this help when you press the help key ('+HelpShortCutAsText+') in the source editor and caret is on a directive (e.g. {$mode objfpc} or {%H-}).'
+' Each line has the format "directive=text" without the quotes. Here is an example for the fpc directives: "H=$H+ turns ansistring on, $H- turns shortstrings on.". Here is an example for an IDE directive: "H=%H- hides the compiler generated message at this source position."';
DirectivesEnableCheckBox.Caption:='Enable';
FPCDirectivesGroupBox.Caption:='FPC directives (e.g. mode=...)';
IDEDirectivesGroupBox.Caption:='IDE directives (e.g. H=...)';
// messages
MessagesTabSheet.Caption:='Messages';
MessagesNoteLabel.Caption:='Simple help for messages. Installed by package '+IDEHelpPkgName+'.'
+' You get this help when you click on Help in the context menu of the messages window.'
+' There is only an example for the message "unitname.pas(line,col) Error: User defined: test", which is created by a {$error test} in the source.';
MessagesEnableCheckBox.Caption:='Enable';
// context
ContextTabSheet.Caption:='HelpContext';
ContextNoteLabel.Caption:='Simple help for HelpContext numbers. Installed by package '+IDEHelpPkgName+'.'
+' You get this help when you press the help key ('+HelpShortCutAsText+') on a control which has a value in its property "HelpContext".'
+' Each line has the format "decimal_number=text" without the quotes. Here is an example for HelpContext=1: "1=Help for button foobar."';
ContextEnableCheckBox.Caption:='Enable';
// classes
ClassesTabSheet.Caption:='Classes';
ClassesNoteLabel.Caption:='Simple help for messages. Installed by package '+IDEHelpPkgName+'.'
+' This help type is currently not used in the IDE.';
ClassesCheckBox.Caption:='Enable';
// pascal sources
PascalSourcesTabSheet.Caption:='Pascal Sources';
PascalSourcesNoteLabel.Caption:='Simple help for pascal sources. Installed by package '+IDEHelpPkgName+'.'
+' You get this help when you press the help key ('+HelpShortCutAsText+') in the source editor and caret is on an identifier.'
+' There is currently no example for this in this package.';
PascalSourcesEnabledCheckBox.Caption:='Enable';
end;
class function TMyHelpSetupDialog.
SupportedOptionsClass: TAbstractIDEOptionsClass;
begin
// show whenever help options are shown
Result:=TAbstractIDEHelpOptions;
end;
procedure TMyHelpSetupDialog.WriteSettings(AOptions: TAbstractIDEOptions);
begin
// fpc keywords
MyFPCKeywordHelpDatabase.Enabled:=FPCKeywordsEnableCheckBox.Checked;
MyFPCKeywordHelpDatabase.KeywordToText:=FPCKeywordsMemo.Lines;
// directives
MyDirectiveHelpDatabase.Enabled:=DirectivesEnableCheckBox.Checked;
MyDirectiveHelpDatabase.FPCDirectiveToText:=FPCDirectivesMemo.Lines;
// messages
MyMessagesHelpDatabase.Enabled:=MessagesEnableCheckBox.Checked;
// context
MyContextHelpDatabase.Enabled:=ContextEnableCheckBox.Checked;
MyContextHelpDatabase.ContextToMessage:=ContextMemo.Lines;
// classes
MyClassesHelpDatabase.Enabled:=ClassesCheckBox.Checked;
// sources
MyPascalSourcesHelpDatabase.Enabled:=PascalSourcesEnabledCheckBox.Checked;
// save if modified
if MyFPCKeywordHelpDatabase.Modified
or MyDirectiveHelpDatabase.Modified
or MyMessagesHelpDatabase.Modified
or MyContextHelpDatabase.Modified
or MyClassesHelpDatabase.Modified
or MyPascalSourcesHelpDatabase.Modified
then
LoadSaveMyIDEOptions(MyHelpConfigFilename,false);
end;
{ TMyContextHelpDatabase }
procedure TMyContextHelpDatabase.SetContextToMessage(AValue: TStrings);
begin
if AssignTrimmedStrings(AValue,FContextToMessage) then
Modified:=true;
end;
constructor TMyContextHelpDatabase.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FContextToMessage:=TStringList.Create;
ContextToMessage.Text:=DefaultContextToMessage;
end;
destructor TMyContextHelpDatabase.Destroy;
begin
FreeAndNil(FContextToMessage);
inherited Destroy;
end;
function TMyContextHelpDatabase.GetNodesForContext(HelpContext: THelpContext;
var ListOfNodes: THelpNodeQueryList; var ErrMsg: string): TShowHelpResult;
var
Msg: String;
Title: String;
begin
ErrMsg:='';
Result:=shrHelpNotFound;
if (csDesigning in ComponentState) or (not Enabled) then exit;
Msg:=ContextToMessage.Values[IntToStr(HelpContext)];
if Msg='' then exit;
// this help database knows this context
Title:='Help for context';
// => add a node, so that if there are several possibilities the IDE can
// show the user a dialog to choose
if FAllContextNode=nil then
FAllContextNode:=THelpNode.CreateURL(Self,'','');
FAllContextNode.Title:=Title;
CreateNodeQueryListAndAdd(FAllContextNode,nil,ListOfNodes,true);
Result:=shrSuccess;
end;
function TMyContextHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
): TShowHelpResult;
var
Context: THelpQueryContext;
Msg: String;
begin
ErrMsg:='';
Result:=shrHelpNotFound;
if not (Query is THelpQueryContext) then exit;
Context:=THelpQueryContext(Query);
debugln(['TMyContextHelpDatabase.ShowHelp Context="',Context.Context]);
Msg:=ContextToMessage.Values[IntToStr(Context.Context)];
IDEMessageDialog('My context help',
'The context "'+IntToStr(Context.Context)+'":'+LineEnding+LineEnding
+Msg,mtInformation,[mbOk]);
Result:=shrSuccess;
end;
procedure TMyContextHelpDatabase.LoadFromConfig(Config: TConfigStorage);
begin
inherited LoadFromConfig(Config);
Config.GetValue('Contexts',ContextToMessage);
if ContextToMessage.Count=0 then
ContextToMessage.Text:=DefaultContextToMessage;
end;
procedure TMyContextHelpDatabase.SaveToConfig(Config: TConfigStorage);
begin
inherited SaveToConfig(Config);
Config.SetValue('Contexts',ContextToMessage);
end;
{ TMyMessagesHelpDatabase }
constructor TMyMessagesHelpDatabase.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
end;
function TMyMessagesHelpDatabase.GetNodesForMessage(const AMessage: string;
MessageParts: TStrings; var ListOfNodes: THelpNodeQueryList;
var ErrMsg: string): TShowHelpResult;
var
Title: String;
begin
ErrMsg:='';
Result:=shrHelpNotFound;
if (csDesigning in ComponentState) or (not Enabled) then exit;
debugln(['TMyMessagesHelpDatabase.GetNodesForDirective AMessage="',AMessage,'" Parts="',MessageParts.Text,'"']);
// check if the message fits
if MessageParts=nil then exit;
if MessageParts.Values['Message']<>'User defined: Test' then exit;
// this help database knows this message
Title:='Help for message';
// => add a node, so that if there are several possibilities the IDE can
// show the user a dialog to choose
if FAllMessageNode=nil then
FAllMessageNode:=THelpNode.CreateURL(Self,'','');
FAllMessageNode.Title:=Title;
CreateNodeQueryListAndAdd(FAllMessageNode,nil,ListOfNodes,true);
Result:=shrSuccess;
end;
function TMyMessagesHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
): TShowHelpResult;
var
Msg: THelpQueryMessage;
begin
ErrMsg:='';
Result:=shrHelpNotFound;
if not (Query is THelpQueryMessage) then exit;
Msg:=THelpQueryMessage(Query);
debugln(['TMyMessagesHelpDatabase.ShowHelp Msg="',Msg.WholeMessage,'" Parts="',Msg.MessageParts.Text,'"']);
// check if the message fits
if Msg.MessageParts=nil then exit;
if Msg.MessageParts.Values['Message']<>'User defined: Test' then exit;
IDEMessageDialog('My message help',
'The message "$'+Msg.WholeMessage+'":'+LineEnding+LineEnding
+'Success. Message recognized by TMyMessagesHelpDatabase',mtInformation,[mbOk]);
Result:=shrSuccess;
end;
{ TMyDirectiveHelpDatabase }
procedure TMyDirectiveHelpDatabase.SetFPCDirectiveToText(AValue: TStrings);
begin
if AssignTrimmedStrings(AValue,FFPCDirectiveToText) then
Modified:=true;
end;
procedure TMyDirectiveHelpDatabase.SetIDEDirectiveToText(AValue: TStrings);
begin
if AssignTrimmedStrings(AValue,FIDEDirectiveToText) then
Modified:=true;
end;
constructor TMyDirectiveHelpDatabase.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
Enabled:=true;
FFPCDirectiveToText:=TStringList.Create;
FPCDirectiveToText.Text:=DefaultFPCDirectiveToText;
FIDEDirectiveToText:=TStringList.Create;
IDEDirectiveToText.Text:=DefaultIDEDirectiveToText;
end;
destructor TMyDirectiveHelpDatabase.Destroy;
begin
FreeAndNil(FFPCDirectiveToText);
FreeAndNil(FIDEDirectiveToText);
inherited Destroy;
end;
function TMyDirectiveHelpDatabase.GetNodesForDirective(
const HelpDirective: string; var ListOfNodes: THelpNodeQueryList;
var ErrMsg: string): TShowHelpResult;
var
Directive: String;
i: Integer;
Title: String;
begin
Result:=shrHelpNotFound;
if (csDesigning in ComponentState) or (not Enabled) then exit;
debugln(['TMyDirectiveHelpDatabase.GetNodesForDirective HelpDirective="',HelpDirective,'"']);
if (FPCDirectiveHelpPrefix<>'')
and (LeftStr(HelpDirective,length(FPCDirectiveHelpPrefix))=FPCDirectiveHelpPrefix)
then begin
// HelpDirective is for example 'FPCDirective_$mode'
Directive:=copy(HelpDirective,length(FPCDirectiveHelpPrefix)+2,length(HelpDirective));
// directive is now 'mode'
i:=FPCDirectiveToText.IndexOfName(lowercase(Directive));
if i<0 then exit;
Title:='Free Pascal Compiler directive $'+Directive;
end else if (IDEDirectiveHelpPrefix<>'')
and (LeftStr(HelpDirective,length(IDEDirectiveHelpPrefix))=IDEDirectiveHelpPrefix)
then begin
// IDE directive
Directive:=copy(HelpDirective,length(IDEDirectiveHelpPrefix)+2,length(HelpDirective));
// directive is now 'H'
i:=IDEDirectiveToText.IndexOfName(lowercase(Directive));
Title:='IDE directive %'+Directive;
end;
// this help database knows this Directive
// => add a node, so that if there are several possibilities the IDE can
// show the user a dialog to choose
if FAllDirectiveNode=nil then
FAllDirectiveNode:=THelpNode.CreateURL(Self,'','');
FAllDirectiveNode.Title:=Title;
CreateNodeQueryListAndAdd(FAllDirectiveNode,nil,ListOfNodes,true);
Result:=shrSuccess;
end;
function TMyDirectiveHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
): TShowHelpResult;
var
DirectiveQuery: THelpQueryDirective;
Directive: String;
Txt: String;
begin
Result:=shrHelpNotFound;
if not (Query is THelpQueryDirective) then exit;
DirectiveQuery:=THelpQueryDirective(Query);
Directive:=DirectiveQuery.Directive;
if (FPCDirectiveHelpPrefix<>'')
and (LeftStr(Directive,length(FPCDirectiveHelpPrefix))=FPCDirectiveHelpPrefix)
then begin
// Directive is for example 'FPCDirective_$mode'
Directive:=copy(Directive,length(FPCDirectiveHelpPrefix)+2,length(Directive));
// directive is now 'mode'
Txt:=FPCDirectiveToText.Values[lowercase(Directive)];
IDEMessageDialog('My fpc directive help',
'Free Pascal compiler directive "$'+Directive+'":'+LineEnding+LineEnding
+Txt,mtInformation,[mbOk]);
end else if (IDEDirectiveHelpPrefix<>'')
and (LeftStr(Directive,length(IDEDirectiveHelpPrefix))=IDEDirectiveHelpPrefix)
then begin
// IDE directive
Directive:=copy(Directive,length(IDEDirectiveHelpPrefix)+2,length(Directive));
Txt:=IDEDirectiveToText.Values[lowercase(Directive)];
IDEMessageDialog('My Lazarus IDE directive help',
'Lazarus IDE directive "%'+Directive+'":'+LineEnding+LineEnding
+Txt,mtInformation,[mbOk]);
end;
Result:=shrSuccess;
end;
procedure TMyDirectiveHelpDatabase.LoadFromConfig(Config: TConfigStorage);
begin
inherited LoadFromConfig(Config);
Config.GetValue('FPCDirectives',FPCDirectiveToText);
if FPCDirectiveToText.Count=0 then
FPCDirectiveToText.Text:=DefaultFPCDirectiveToText;
Config.GetValue('IDEDirectives',IDEDirectiveToText);
if IDEDirectiveToText.Count=0 then
IDEDirectiveToText.Text:=DefaultIDEDirectiveToText;
end;
procedure TMyDirectiveHelpDatabase.SaveToConfig(Config: TConfigStorage);
begin
inherited SaveToConfig(Config);
Config.SetValue('FPCDirectives',FPCDirectiveToText);
Config.SetValue('IDEDirectives',IDEDirectiveToText);
end;
{ TMyFPCKeywordHelpDatabase }
procedure TMyFPCKeywordHelpDatabase.SetKeywordToText(AValue: TStrings);
begin
if AssignTrimmedStrings(AValue,FKeywordToText) then
Modified:=true;
end;
constructor TMyFPCKeywordHelpDatabase.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FKeywordToText:=TStringList.Create;
KeywordToText.Text:=DefaultKeyWordToText;
end;
destructor TMyFPCKeywordHelpDatabase.Destroy;
begin
FreeAndNil(FKeywordToText);
inherited Destroy;
end;
function TMyFPCKeywordHelpDatabase.GetNodesForKeyword(
const HelpKeyword: string; var ListOfNodes: THelpNodeQueryList;
var ErrMsg: string): TShowHelpResult;
var
KeyWord: String;
i: Integer;
begin
Result:=shrHelpNotFound;
if (csDesigning in ComponentState) or (not Enabled) then exit;
if (FPCKeyWordHelpPrefix='')
or (LeftStr(HelpKeyword,length(FPCKeyWordHelpPrefix))<>FPCKeyWordHelpPrefix)
then exit;
// HelpKeyword is for example 'FPCKeyword_procedure'
KeyWord:=copy(HelpKeyword,length(FPCKeyWordHelpPrefix)+1,length(HelpKeyword));
// keyword is now 'procedure'
i:=KeywordToText.IndexOfName(lowercase(KeyWord));
if i<0 then exit;
// this help database knows this keyword
// => add a node, so that if there are several possibilities the IDE can
// show the user a dialog to choose
if FAllKeywordNode=nil then
FAllKeywordNode:=THelpNode.CreateURL(Self,'','');
FAllKeywordNode.Title:='Pascal keyword '+KeyWord;
CreateNodeQueryListAndAdd(FAllKeywordNode,nil,ListOfNodes,true);
Result:=shrSuccess;
end;
function TMyFPCKeywordHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
): TShowHelpResult;
var
KeywordQuery: THelpQueryKeyword;
KeyWord: String;
Txt: String;
begin
Result:=shrHelpNotFound;
if not (Query is THelpQueryKeyword) then exit;
KeywordQuery:=THelpQueryKeyword(Query);
KeyWord:=copy(KeywordQuery.Keyword,length(FPCKeyWordHelpPrefix)+1,length(KeywordQuery.Keyword));
Txt:=KeywordToText.Values[lowercase(KeyWord)];
IDEMessageDialog('My fpc keyword help',
'The keyword "'+KeyWord+'":'+LineEnding+LineEnding
+Txt,mtInformation,[mbOk]);
Result:=shrSuccess;
end;
procedure TMyFPCKeywordHelpDatabase.LoadFromConfig(Config: TConfigStorage);
begin
inherited LoadFromConfig(Config);
Config.GetValue('KeywordToText',KeywordToText);
if KeywordToText.Count=0 then
KeywordToText.Text:=DefaultKeyWordToText;
end;
procedure TMyFPCKeywordHelpDatabase.SaveToConfig(Config: TConfigStorage);
begin
inherited SaveToConfig(Config);
Config.SetValue('KeywordToText',KeywordToText);
end;
{$R *.lfm}
end.