2
/***************************************************************************
7
***************************************************************************/
9
***************************************************************************
11
* This source is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
16
* This code is distributed in the hope that it will be useful, but *
17
* WITHOUT ANY WARRANTY; without even the implied warranty of *
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
19
* General Public License for more details. *
21
* A copy of the GNU General Public License is available on the World *
22
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
23
* obtain it by writing to the Free Software Foundation, *
24
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
26
***************************************************************************
36
Classes, SysUtils, AVL_Tree, LCLProc, LCLIntf, LCLType, Forms, Controls,
37
Buttons, StdCtrls, Dialogs, ExtCtrls, FileProcs, Graphics, ButtonPanel,
38
LConvEncoding, lazutf8classes,
40
BasicCodeTools, CodeToolManager, CodeAtom, CodeCache, CustomCodeTool, CodeTree,
41
PascalParserTool, FindDeclarationTool,
43
PropEdits, ObjectInspector, FormEditingIntf, ProjectIntf, TextTools,
44
IDEDialogs, LazHelpIntf, LazHelpHTML, HelpFPDoc, MacroIntf, IDEWindowIntf,
45
IDEMsgIntf, PackageIntf, LazIDEIntf, HelpIntfs, IDEHelpIntf,
47
LazarusIDEStrConsts, TransferMacros, DialogProcs, IDEOptionDefs,
48
ObjInspExt, EnvironmentOpts, AboutFrm, MsgView, Project, MainBar, OutputFilter,
49
IDEFPDocFileSearch, PackageDefs, PackageSystem,
50
HelpOptions, MainIntf, LazConf, HelpFPCMessages, CodeHelp,
51
IDEContextHelpEdit, IDEWindowHelp;
55
{ TSimpleFPCKeywordHelpDatabase }
57
TSimpleFPCKeywordHelpDatabase = class(THTMLHelpDatabase)
59
FKeywordPrefixNode: THelpNode;
61
function GetNodesForKeyword(const HelpKeyword: string;
62
var ListOfNodes: THelpNodeQueryList; var ErrMsg: string
63
): TShowHelpResult; override;
64
function ShowHelp(Query: THelpQuery; BaseNode, NewNode: THelpNode;
65
QueryItem: THelpQueryItem;
66
var ErrMsg: string): TShowHelpResult; override;
69
TLIHProviders = class;
71
{ TLazIDEHTMLProvider }
73
TLazIDEHTMLProvider = class(TAbstractIDEHTMLProvider)
75
fWaitingForAsync: boolean;
76
FProviders: TLIHProviders;
77
procedure SetProviders(const AValue: TLIHProviders);
78
procedure OpenNextURL(Data: PtrInt); // called via Application.QueueAsyncCall
79
procedure OpenFPDoc(Path: string);
82
destructor Destroy; override;
83
function URLHasStream(const URL: string): boolean; override;
84
procedure OpenURLAsync(const URL: string); override;
85
function GetStream(const URL: string; Shared: Boolean): TStream; override;
86
procedure ReleaseStream(const URL: string); override;
87
property Providers: TLIHProviders read FProviders write SetProviders;
90
{ TLIHProviderStream }
92
TLIHProviderStream = class
98
destructor Destroy; override;
99
procedure IncreaseRefCount;
100
procedure DecreaseRefCount;
101
property RefCount: integer read FRefCount;
105
manages all TLazIDEHTMLProvider }
107
TLIHProviders = class
109
FStreams: TAVLTree;// tree of TLIHProviderStream sorted for URL
112
destructor Destroy; override;
113
function FindStream(const URL: string; CreateIfNotExists: Boolean): TLIHProviderStream;
114
function GetStream(const URL: string; Shared: boolean): TStream;
115
procedure ReleaseStream(const URL: string);
119
At the moment it is a TLabel that simply strips all tags }
121
TSimpleHTMLControl = class(TLabel,TIDEHTMLControlIntf)
123
FMaxLineCount: integer;
124
FProvider: TAbstractIDEHTMLProvider;
126
procedure SetProvider(const AValue: TAbstractIDEHTMLProvider);
128
constructor Create(AOwner: TComponent); override;
129
function GetURL: string;
130
procedure SetURL(const AValue: string);
131
property Provider: TAbstractIDEHTMLProvider read FProvider write SetProvider;
132
procedure SetHTMLContent(Stream: TStream; const NewURL: string);
133
procedure GetPreferredControlSize(out AWidth, AHeight: integer);
134
property MaxLineCount: integer read FMaxLineCount write FMaxLineCount;
137
{ TScrollableHTMLControl
138
At the moment it is a TMemo that simply strips all tags }
140
TScrollableHTMLControl = class(TMemo,TIDEHTMLControlIntf)
142
FProvider: TAbstractIDEHTMLProvider;
144
procedure SetProvider(const AValue: TAbstractIDEHTMLProvider);
146
constructor Create(AOwner: TComponent); override;
147
function GetURL: string;
148
procedure SetURL(const AValue: string);
149
property Provider: TAbstractIDEHTMLProvider read FProvider write SetProvider;
150
procedure SetHTMLContent(Stream: TStream; const NewURL: string);
151
procedure GetPreferredControlSize(out AWidth, AHeight: integer);
154
{ TIDEHelpDatabases }
156
TIDEHelpDatabases = class(THelpDatabases)
158
function ShowHelpSelector(Query: THelpQuery; Nodes: THelpNodeQueryList;
160
var Selection: THelpNodeQuery
161
): TShowHelpResult; override;
162
function GetBaseDirectoryForBasePathObject(BasePathObject: TObject): string; override;
163
function ShowHelpForSourcePosition(Query: THelpQuerySourcePosition;
164
var ErrMsg: string): TShowHelpResult; override;
165
function SubstituteMacros(var s: string): boolean; override;
171
TIDEHelpManager = class(TBaseHelpManager)
172
// help menu of the IDE menu bar
173
procedure mnuHelpAboutLazarusClicked(Sender: TObject);
174
procedure mnuHelpOnlineHelpClicked(Sender: TObject);
175
procedure mnuHelpReportBugClicked(Sender: TObject);
177
procedure mnuSearchInFPDocFilesClick(Sender: TObject);
179
procedure mnuEditMessageHelpClick(Sender: TObject);
181
FFCLHelpDB: THelpDatabase;
182
FFCLHelpDBPath: THelpBaseURLObject;
183
FHTMLProviders: TLIHProviders;
184
FLCLHelpDB: THelpDatabase;
185
FLCLHelpDBPath: THelpBaseURLObject;
186
FMainHelpDB: THelpDatabase;
187
FMainHelpDBPath: THelpBasePathObject;
188
FRTLHelpDB: THelpDatabase;
189
FRTLHelpDBPath: THelpBaseURLObject;
190
procedure RegisterIDEHelpDatabases;
191
procedure RegisterDefaultIDEHelpViewers;
192
procedure FindDefaultBrowser(var DefaultBrowser, Params: string);
194
constructor Create(TheOwner: TComponent); override;
195
destructor Destroy; override;
197
procedure ConnectMainBarEvents; override;
198
procedure LoadHelpOptions; override;
199
procedure SaveHelpOptions; override;
201
procedure ShowLazarusHelpStartPage;
202
procedure ShowIDEHelpForContext(HelpContext: THelpContext);
203
procedure ShowIDEHelpForKeyword(const Keyword: string); // an arbitrary keyword, not a fpc keyword
205
function ShowHelpForSourcePosition(const Filename: string;
206
const CodePos: TPoint;
207
var ErrMsg: string): TShowHelpResult; override;
208
procedure ShowHelpForMessage(Line: integer); override;
209
procedure ShowHelpForObjectInspector(Sender: TObject); override;
210
procedure ShowHelpForIDEControl(Sender: TControl); override;
212
function CreateHint(aHintWindow: THintWindow; ScreenPos: TPoint;
213
const BaseURL: string; var TheHint: string;
214
out HintWinRect: TRect): boolean; override;
215
function GetHintForSourcePosition(const ExpandedFilename: string;
216
const CodePos: TPoint;
217
out BaseURL, HTMLHint: string;
218
Flags: TIDEHelpManagerCreateHintFlags = []): TShowHelpResult; override;
220
function ConvertSourcePosToPascalHelpContext(const CaretPos: TPoint;
221
const Filename: string): TPascalHelpContextList; override;
222
function ConvertCodePosToPascalHelpContext(
223
ACodePos: PCodeXYPosition): TPascalHelpContextList;
224
function GetFPDocFilenameForSource(SrcFilename: string;
225
ResolveIncludeFiles: Boolean; out AnOwner: TObject): string; override;
227
property FCLHelpDB: THelpDatabase read FFCLHelpDB;
228
property FCLHelpDBPath: THelpBaseURLObject read FFCLHelpDBPath;
229
property MainHelpDB: THelpDatabase read FMainHelpDB;
230
property MainHelpDBPath: THelpBasePathObject read FMainHelpDBPath;
231
property LCLHelpDB: THelpDatabase read FLCLHelpDB;
232
property LCLHelpDBPath: THelpBaseURLObject read FLCLHelpDBPath;
233
property RTLHelpDB: THelpDatabase read FRTLHelpDB;
234
property RTLHelpDBPath: THelpBaseURLObject read FRTLHelpDBPath;
237
{ THelpSelectorDialog }
239
THelpSelectorDialog = class(TForm)
240
BtnPanel: TButtonPanel;
241
NodesGroupBox: TGroupBox;
242
NodesListBox: TListBox;
243
procedure HelpSelectorDialogClose(Sender: TObject;
244
var CloseAction: TCloseAction);
245
procedure NodesListBoxDblClick(Sender: TObject);
247
FNodes: THelpNodeQueryList;
248
procedure SetNodes(const AValue: THelpNodeQueryList);
249
procedure FillNodesListBox;
251
constructor Create(TheOwner: TComponent); override;
252
property Nodes: THelpNodeQueryList read FNodes write SetNodes;
255
{ Help Contexts for IDE help }
257
lihcStartPage = 'StartPage';
258
lihcRTLUnits = 'RTLUnits';
259
lihcFCLUnits = 'FCLUnits';
260
lihcLCLUnits = 'LCLUnits';
262
lihBaseUrl = 'http://lazarus-ccr.sourceforge.net/docs/';
264
lihRTLURL = lihBaseUrl+'rtl/';
265
lihFCLURL = lihBaseUrl+'fcl/';
266
lihLCLURL = lihBaseUrl+'lcl/';
269
HelpBoss: TBaseHelpManager = nil;
275
function LazCreateIDEHTMLControl(Owner: TComponent;
276
var Provider: TAbstractIDEHTMLProvider;
277
Flags: TIDEHTMLControlFlags): TControl;
279
if ihcScrollable in Flags then
280
Result:=TScrollableHTMLControl.Create(Owner)
282
Result:=TSimpleHTMLControl.Create(Owner);
284
Provider:=CreateIDEHTMLProvider(Result);
285
if ihcScrollable in Flags then
287
Provider.ControlIntf:=TScrollableHTMLControl(Result);
288
TScrollableHTMLControl(Result).Provider:=Provider;
292
Provider.ControlIntf:=TSimpleHTMLControl(Result);
293
TSimpleHTMLControl(Result).Provider:=Provider;
297
function LazCreateIDEHTMLProvider(Owner: TComponent): TAbstractIDEHTMLProvider;
299
Result:=TLazIDEHTMLProvider.Create(Owner);
300
TLazIDEHTMLProvider(Result).Providers:=TIDEHelpManager(HelpBoss).FHTMLProviders;
303
function CompareLIHProviderStream(Data1, Data2: Pointer): integer;
305
Result:=CompareStr(TLIHProviderStream(Data1).URL,TLIHProviderStream(Data2).URL);
308
function CompareURLWithLIHProviderStream(URL, Stream: Pointer): integer;
310
Result:=CompareStr(AnsiString(URL),TLIHProviderStream(Stream).URL);
313
{ TSimpleFPCKeywordHelpDatabase }
315
function TSimpleFPCKeywordHelpDatabase.GetNodesForKeyword(
316
const HelpKeyword: string; var ListOfNodes: THelpNodeQueryList;
317
var ErrMsg: string): TShowHelpResult;
321
Result:=shrHelpNotFound;
322
if (csDesigning in ComponentState) then exit;
323
if (FPCKeyWordHelpPrefix<>'')
324
and (LeftStr(HelpKeyword,length(FPCKeyWordHelpPrefix))=FPCKeyWordHelpPrefix) then begin
325
// HelpKeyword starts with KeywordPrefix
326
KeyWord:=copy(HelpKeyword,length(FPCKeyWordHelpPrefix)+1,length(HelpKeyword));
327
// test: testfcpkeyword
328
if KeyWord='testfcpkeyword' then begin
329
// this help database knows this keyword
330
// => add a node, so that if there are several possibilities the IDE can
331
// show the user a dialog to choose
332
if FKeywordPrefixNode=nil then
333
FKeywordPrefixNode:=THelpNode.CreateURL(Self,'','');
334
FKeywordPrefixNode.Title:='Pascal keyword '+KeyWord;
335
CreateNodeQueryListAndAdd(FKeywordPrefixNode,nil,ListOfNodes,true);
341
function TSimpleFPCKeywordHelpDatabase.ShowHelp(Query: THelpQuery; BaseNode,
342
NewNode: THelpNode; QueryItem: THelpQueryItem; var ErrMsg: string
345
KeywordQuery: THelpQueryKeyword;
348
Result:=shrHelpNotFound;
349
if not (Query is THelpQueryKeyword) then exit;
350
KeywordQuery:=THelpQueryKeyword(Query);
351
KeyWord:=copy(KeywordQuery.Keyword,length(FPCKeyWordHelpPrefix)+1,length(KeywordQuery.Keyword));
352
debugln(['TSimpleFPCKeywordHelpDatabase.ShowHelp Keyword=',Keyword]);
355
function HTMLToCaption(const s: string; MaxLines: integer): string;
366
//debugln(['HTMLToCaption HTML="',Result,'"']);
370
if copy(Result,1,3)=UTF8BOM then
371
Result:=copy(s,4,length(Result));
372
InHeader:=false; // it could be a snippet
373
while p<=length(Result) do begin
374
if Result[p]='<' then begin
377
if (EndPos<=length(Result)) and (Result[EndPos]='/') then inc(EndPos);
378
while (EndPos<=length(Result))
379
and (not (Result[EndPos] in [' ','>','"','/',#9,#10,#13])) do
381
CurTagName:=UpperCase(copy(Result,p+1,EndPos-p-1));
382
while (EndPos<=length(Result)) do begin
383
if Result[EndPos]='"' then begin
386
while (EndPos<=length(Result)) and (Result[EndPos]<>'"') do
388
if EndPos>length(Result) then break;
390
if (Result[EndPos]='>') then begin
396
//debugln(['HTMLToCaption CurTagName=',CurTagName,' Tag="',copy(Result,p,EndPos-p),'"']);
398
if CurTagName='HTML' then
403
if CurTagName='BODY' then
405
// start of body => ignore header
407
Result:=copy(Result,EndPos,length(Result));
412
if CurTagName='/BODY' then
415
Result:=copy(Result,1,p-1);
419
if (CurTagName='P') or (CurTagName='/P') then begin
420
// add a line break if there is not already one
422
while (sp>1) and (Result[sp-1] in [' ',#9]) do dec(sp);
423
if (sp>1) and (not (Result[sp-1] in [#10,#13])) then
426
if (CurTagName='DIV') or (CurTagName='/DIV')
428
// add a line break if not in first line
433
if CurTagName='BR' then
438
if Line>MaxLines then begin
439
Result:=copy(Result,1,p)+LineEnding+'...';
445
if NewTag='' then begin
446
//debugln(['HTMLToCaption deleting tag ',copy(Result,p,EndPos-p)]);
447
System.Delete(Result,p,EndPos-p);
450
Result:=copy(Result,1,p-1)+NewTag+copy(Result,EndPos,length(Result));
451
inc(p,length(NewTag));
453
end else if Result[p] in [' ',#9,#10,#13] then begin
454
// replace spaces and newline characters with a single space
456
while (EndPos<=length(Result)) and (Result[EndPos] in [' ',#9,#10,#13]) do
458
if (p > 1) and not (Result[p-1] in [' ',#9,#10,#13]) then
460
Result:=copy(Result,1,p-1)+' '+copy(Result,EndPos,length(Result));
464
Result:=copy(Result,1,p-1)+copy(Result,EndPos,length(Result));
465
end else if Result[p]='&' then begin
466
// special chars: < > &
467
if (p+2<Length(Result)) and (Result[p+1]='l') and (Result[p+2]='t') and (Result[p+3]=';') then begin
469
Result:=copy(Result,1,p-1)+'<'+copy(Result,EndPos,length(Result));
471
if (p+2<Length(Result)) and (Result[p+1]='g') and (Result[p+2]='t') and (Result[p+3]=';') then begin
473
Result:=copy(Result,1,p-1)+'>'+copy(Result,EndPos,length(Result));
475
if (p+3<Length(Result)) and (Result[p+1]='a') and (Result[p+2]='m') and (Result[p+3]='p') and (Result[p+4]=';') then begin
477
Result:=copy(Result,1,p-1)+'&'+copy(Result,EndPos,length(Result));
485
while (p>0) and (Result[p] in [' ',#9,#10,#13]) do dec(p);
488
//DebugLn(['HTMLToCaption Caption="',dbgstr(Result),'"']);
491
function HTMLToCaption(Stream: TStream; MaxLines: integer): string;
495
SetLength(s,Stream.Size);
497
Stream.Read(s[1],length(s));
498
Result:=HTMLToCaption(s,MaxLines);
501
{ TSimpleHTMLControl }
503
procedure TSimpleHTMLControl.SetProvider(const AValue: TAbstractIDEHTMLProvider);
505
if FProvider=AValue then exit;
509
constructor TSimpleHTMLControl.Create(AOwner: TComponent);
511
inherited Create(AOwner);
515
Alignment := taLeftJustify;
516
Font.Color := clInfoText;
517
BorderSpacing.Around := 4;
518
ShowAccelChar := False; //don't underline after &
521
function TSimpleHTMLControl.GetURL: string;
526
procedure TSimpleHTMLControl.SetURL(const AValue: string);
531
if Provider=nil then raise Exception.Create('TSimpleHTMLControl.SetURL missing Provider');
532
if FURL=AValue then exit;
533
NewURL:=Provider.MakeURLAbsolute(Provider.BaseURL,AValue);
534
if FURL=NewURL then exit;
537
Stream:=Provider.GetStream(FURL,true);
539
Caption:=HTMLToCaption(Stream, MaxLineCount);
541
Provider.ReleaseStream(FURL);
544
on E: Exception do begin
550
procedure TSimpleHTMLControl.SetHTMLContent(Stream: TStream;
551
const NewURL: string);
554
Caption:=HTMLToCaption(Stream,MaxLineCount);
555
//debugln(['TSimpleHTMLControl.SetHTMLContent ',Caption]);
558
procedure TSimpleHTMLControl.GetPreferredControlSize(out AWidth, AHeight: integer);
568
DC := GetDC(Parent.Handle);
570
R := Rect(0, 0, 600, 200);
571
OldFont := SelectObject(DC, HGDIOBJ(Font.Reference.Handle));
572
Flags := DT_CALCRECT or DT_EXPANDTABS;
573
inc(Flags, DT_WordBreak);
574
LabelText := GetLabelText;
575
DrawText(DC, PChar(LabelText), Length(LabelText), R, Flags);
576
SelectObject(DC, OldFont);
577
AWidth := R.Right - R.Left + 8; // border
578
AHeight := R.Bottom - R.Top + 8; // border
580
ReleaseDC(Parent.Handle, DC);
582
//DebugLn(['TSimpleHTMLControl.GetPreferredControlSize Caption="',Caption,'" ',AWidth,'x',AHeight]);
585
{ TScrollableHTMLControl }
587
procedure TScrollableHTMLControl.SetProvider(const AValue: TAbstractIDEHTMLProvider);
589
if FProvider=AValue then exit;
593
constructor TScrollableHTMLControl.Create(AOwner: TComponent);
595
inherited Create(AOwner);
596
BorderSpacing.Around := 4;
597
BorderStyle := bsNone;
599
ScrollBars := ssAutoVertical;
602
function TScrollableHTMLControl.GetURL: string;
607
procedure TScrollableHTMLControl.SetURL(const AValue: string);
612
if Provider=nil then raise Exception.Create('TScrollableHTMLControl.SetURL missing Provider');
613
if FURL=AValue then exit;
614
NewURL:=Provider.MakeURLAbsolute(Provider.BaseURL,AValue);
615
if FURL=NewURL then exit;
618
Stream:=Provider.GetStream(FURL,true);
620
Caption:=HTMLToCaption(Stream, MaxInt);
622
Provider.ReleaseStream(FURL);
625
on E: Exception do begin
631
procedure TScrollableHTMLControl.SetHTMLContent(Stream: TStream;
632
const NewURL: string);
635
Caption:=HTMLToCaption(Stream,MaxInt);
636
//debugln(['TScrollableHTMLControl.SetHTMLContent ',Caption]);
639
procedure TScrollableHTMLControl.GetPreferredControlSize(out AWidth, AHeight: integer);
643
GetPreferredSize(AWidth, AHeight);
646
{ TLazIDEHTMLProvider }
648
procedure TLazIDEHTMLProvider.SetProviders(const AValue: TLIHProviders);
650
if FProviders=AValue then exit;
654
procedure TLazIDEHTMLProvider.OpenNextURL(Data: PtrInt);
662
fWaitingForAsync:=false;
663
SplitURL(NextURL,URLScheme,URLPath,URLParams);
664
debugln(['TLazIDEHTMLProvider.OpenNextURL "',URLScheme,'" :// "',URLPath,'" & "',URLParams,'"']);
665
if URLScheme='source' then begin
667
if REMatches(URLPath,'(.*)\((.*),(.*)\)') then begin
669
p.Y:=StrToIntDef(REVar(2),p.x);
670
p.X:=StrToIntDef(REVar(3),p.y);
674
AFilename:=SetDirSeparators(AFilename);
675
LazarusIDE.DoOpenFileAndJumpToPos(AFilename,p,-1,-1,-1,[]);
676
end else if (URLScheme='openpackage') and (URLPath<>'')
677
and IsValidIdent(URLPath) then begin
678
PackageEditingInterface.DoOpenPackageWithName(URLPath,[],false);
679
end else if (URLScheme='fpdoc') and (URLParams<>'') then begin
680
OpenFPDoc(URLParams);
684
procedure TLazIDEHTMLProvider.OpenFPDoc(Path: string);
688
function ExtractSubPath: string;
692
p:=System.Pos('.',RestPath);
693
if p<1 then p:=length(RestPath)+1;
694
Result:=copy(RestPath,1,p-1);
695
RestPath:=copy(RestPath,p+1,length(RestPath));
698
procedure InvalidPathError(Msg: string);
700
debugln(['InvalidPathError Path="',Path,'" Msg="',Msg,'"']);
701
IDEMessageDialog('Unable to open fpdoc help',
702
'The fpdoc path "'+Path+'" is invalid.'#13+Msg,mtError,[mbCancel]);
710
ContextList: TPascalHelpContextList;
714
PascalHelpContextLists: TList;
720
PkgName:=ExtractSubPath;
721
if (PkgName='') or (PkgName[1]<>'#') then begin
722
InvalidPathError('It does not start with a package name, for example #rtl.');
725
PkgName:=copy(PkgName,2,length(PkgName));
726
if (PkgName='') or not IsValidIdent(PkgName) then begin
727
InvalidPathError('It does not start with a package name, for example #rtl.');
730
if SysUtils.CompareText(PkgName,'rtl')=0 then PkgName:='fcl';
731
Pkg:=TLazPackage(PackageEditingInterface.FindPackageWithName(PkgName));
732
if Pkg=nil then begin
733
InvalidPathError('Package "'+PkgName+'" not found.');
736
if Pkg.IsVirtual then begin
737
InvalidPathError('Package "'+PkgName+'" has no help.');
741
AnUnitName:=ExtractSubPath;
742
if (AnUnitName='') or (not IsValidIdent(AnUnitName)) then begin
743
InvalidPathError('Unit name "'+AnUnitName+'" is invalid.');
748
PkgFile:=Pkg.FindUnit(AnUnitName);
749
if PkgFile=nil then begin
750
// search in all sub packages
753
PackageGraph.GetAllRequiredPackages(Pkg.FirstRequiredDependency,PkgList);
754
if PkgList<>nil then begin
755
for i:=0 to PkgList.Count-1 do begin
756
SubPkg:=TLazPackage(PkgList[i]);
757
PkgFile:=SubPkg.FindUnit(AnUnitName);
758
if PkgFile<>nil then begin
768
if (PkgFile<>nil) and (PkgFile.FileType in PkgFileRealUnitTypes) then begin
769
// normal unit in lpk
770
Filename:=PkgFile.GetFullFilename;
771
end else if SysUtils.CompareText(PkgName,'fcl')=0 then begin
772
// search in FPC sources
773
Filename:=CodeToolBoss.DirectoryCachePool.FindUnitInUnitSet('',AnUnitName);
775
if Filename='' then begin
776
InvalidPathError('Unit "'+AnUnitName+'" was not found in package '+Pkg.Name+'.');
780
PascalHelpContextLists:=TList.Create;
782
// create a context list (and add it as sole element to the PascalHelpContextLists)
783
ContextList:=TPascalHelpContextList.Create;
784
PascalHelpContextLists.Add(ContextList);
785
ContextList.Add(pihcFilename,Filename);
786
ContextList.Add(pihcSourceName,AnUnitName);
788
ElementName:=ExtractSubPath;
789
if ElementName='' then break;
790
ContextList.Add(pihcType,ElementName);
792
ShowHelpForPascalContexts(Filename,Point(1,1),PascalHelpContextLists,ErrMsg);
794
if PascalHelpContextLists<>nil then begin
795
for i:=0 to PascalHelpContextLists.Count-1 do
796
TObject(PascalHelpContextLists[i]).Free;
797
PascalHelpContextLists.Free;
802
destructor TLazIDEHTMLProvider.Destroy;
804
if (Application<>nil) and fWaitingForAsync then
805
Application.RemoveAsyncCalls(Self);
809
function TLazIDEHTMLProvider.URLHasStream(const URL: string): boolean;
816
SplitURL(NextURL,URLScheme,URLPath,URLParams);
817
if (URLScheme='file') or (URLScheme='lazdoc') or (URLScheme='fpdoc') then
821
procedure TLazIDEHTMLProvider.OpenURLAsync(const URL: string);
824
//debugln(['TLazIDEHTMLProvider.OpenURLAsync URL=',URL]);
825
if not fWaitingForAsync then begin
826
Application.QueueAsyncCall(@OpenNextURL,0);
827
fWaitingForAsync:=true;
831
function TLazIDEHTMLProvider.GetStream(const URL: string; Shared: Boolean
834
Result:=FProviders.GetStream(URL,Shared);
837
procedure TLazIDEHTMLProvider.ReleaseStream(const URL: string);
839
FProviders.ReleaseStream(URL);
844
constructor TLIHProviders.Create;
846
FStreams:=TAVLTree.Create(@CompareLIHProviderStream);
849
destructor TLIHProviders.Destroy;
851
FStreams.FreeAndClear;
852
FreeAndNil(FStreams);
856
function TLIHProviders.FindStream(const URL: string; CreateIfNotExists: Boolean
857
): TLIHProviderStream;
863
Node:=FStreams.FindKey(Pointer(URL),@CompareURLWithLIHProviderStream);
864
if Node<>nil then begin
865
Result:=TLIHProviderStream(Node.Data);
866
end else if CreateIfNotExists then begin
867
Result:=TLIHProviderStream.Create;
869
FStreams.Add(Result);
874
function TLIHProviders.GetStream(const URL: string; Shared: boolean): TStream;
876
procedure OpenFile(out Stream: TStream; const Filename: string;
877
UseCTCache: boolean);
884
if UseCTCache then begin
885
Buf:=CodeToolBoss.LoadFile(Filename,true,false);
887
raise Exception.Create('TLIHProviders.GetStream: unable to open file '+Filename);
888
ms:=TMemoryStream.Create;
889
Buf.SaveToStream(ms);
896
DebugLn(['TLIHProviders.GetStream.OpenFile ',Filename]);
897
fs:=TFileStreamUTF8.Create(Filename,fmOpenRead);
916
Stream: TLIHProviderStream;
921
if URL='' then raise Exception.Create('TLIHProviders.GetStream no URL');
923
Stream:=FindStream(URL,true);
924
Stream.IncreaseRefCount;
925
Result:=Stream.Stream;
931
if Result=nil then begin
932
SplitURL(URL,URLType,URLPath,URLParams);
933
{$ifdef VerboseLazDoc}
934
DebugLn(['TLIHProviders.GetStream URLType=',URLType,' URLPath=',URLPath,' URLParams=',URLParams]);
936
if URLType='lazdoc' then begin
937
if copy(URLPath,1,8)='lazarus/' then begin
938
URLPath:=copy(URLPath,9,length(URLPath));
939
if (URLPath='index.html')
940
or (URLPath='images/laztitle.jpg')
941
or (URLPath='images/cheetah1.png')
942
or (URLPath='lazdoc.css')
945
EnvironmentOptions.GetParsedLazarusDirectory+SetDirSeparators('/docs/'+URLPath),
949
end else if URLType='file' then begin
950
OpenFile(Result,SetDirSeparators(URLPath),true);
952
{Result:=TMemoryStream.Create;
953
Stream.Stream:=Result;
954
Result.Write(HTML[1],length(HTML));
957
raise Exception.Create('TLIHProviders.GetStream: URL not found "'+dbgstr(URL)+'"');
959
Stream.Stream:=Result;
962
if (Result=nil) and (Stream<>nil) then
967
procedure TLIHProviders.ReleaseStream(const URL: string);
969
Stream: TLIHProviderStream;
971
Stream:=FindStream(URL,false);
973
raise Exception.Create('TLIHProviders.ReleaseStream "'+URL+'"');
974
Stream.DecreaseRefCount;
975
if Stream.RefCount=0 then begin
976
FStreams.Remove(Stream);
981
{ TLIHProviderStream }
983
destructor TLIHProviderStream.Destroy;
989
procedure TLIHProviderStream.IncreaseRefCount;
994
procedure TLIHProviderStream.DecreaseRefCount;
997
raise Exception.Create('TLIHProviderStream.DecreaseRefCount');
1001
{ THelpSelectorDialog }
1003
procedure THelpSelectorDialog.HelpSelectorDialogClose(Sender: TObject;
1004
var CloseAction: TCloseAction);
1006
IDEDialogLayoutList.SaveLayout(Self);
1009
procedure THelpSelectorDialog.NodesListBoxDblClick(Sender: TObject);
1011
ModalResult := mrOK;
1014
procedure THelpSelectorDialog.SetNodes(const AValue: THelpNodeQueryList);
1016
if FNodes=AValue then exit;
1021
procedure THelpSelectorDialog.FillNodesListBox;
1025
NodeQuery: THelpNodeQuery;
1027
List:=TStringList.Create;
1028
if (Nodes<>nil) then begin
1029
for i:=0 to Nodes.Count-1 do begin
1030
NodeQuery:=Nodes[i];
1031
List.Add(NodeQuery.AsString);
1034
NodesListBox.Items.Assign(List);
1036
if NodesListBox.Count > 0 then NodesListBox.ItemIndex := 0;
1039
constructor THelpSelectorDialog.Create(TheOwner: TComponent);
1041
inherited Create(TheOwner);
1042
IDEDialogLayoutList.ApplyLayout(Self,500,300);
1044
Caption := lisHelpSelectorDialog;
1045
NodesGroupBox.Caption:=lisSelectAHelpItem;
1046
BtnPanel.OKButton.Caption:=lisMenuOk;
1049
{ TIDEHelpDatabases }
1051
function TIDEHelpDatabases.ShowHelpSelector(Query: THelpQuery;
1052
Nodes: THelpNodeQueryList;
1054
var Selection: THelpNodeQuery
1057
Dialog: THelpSelectorDialog;
1062
Dialog:=THelpSelectorDialog.Create(nil);
1064
Dialog.Nodes:=Nodes;
1065
if Dialog.ShowModal=mrOk then begin
1066
i:=Dialog.NodesListBox.ItemIndex;
1068
Selection:=Nodes[i];
1079
function TIDEHelpDatabases.GetBaseDirectoryForBasePathObject(
1080
BasePathObject: TObject): string;
1083
DebugLn('TIDEHelpDatabases.GetBaseDirectoryForBasePathObject BasePathObject=',dbgsName(BasePathObject));
1084
if (BasePathObject is THelpBasePathObject) then
1085
Result:=THelpBasePathObject(BasePathObject).BasePath
1086
else if (BasePathObject=HelpBoss) or (BasePathObject=MainIDEInterface) then
1087
Result:=EnvironmentOptions.GetParsedLazarusDirectory
1088
else if BasePathObject is TProject then
1089
Result:=TProject(BasePathObject).ProjectDirectory
1090
else if BasePathObject is TLazPackage then
1091
Result:=TLazPackage(BasePathObject).Directory;
1093
IDEMacros.SubstituteMacros(Result);
1094
Result:=AppendPathDelim(Result);
1097
function TIDEHelpDatabases.ShowHelpForSourcePosition(
1098
Query: THelpQuerySourcePosition; var ErrMsg: string): TShowHelpResult;
1100
Result:=HelpBoss.ShowHelpForSourcePosition(Query.Filename,
1101
Query.SourcePosition,ErrMsg);
1104
function TIDEHelpDatabases.SubstituteMacros(var s: string): boolean;
1106
Result:=IDEMacros.SubstituteMacros(s);
1111
procedure TIDEHelpManager.mnuSearchInFPDocFilesClick(Sender: TObject);
1113
ShowFPDocFileSearch;
1116
procedure TIDEHelpManager.mnuEditMessageHelpClick(Sender: TObject);
1121
procedure TIDEHelpManager.mnuHelpAboutLazarusClicked(Sender: TObject);
1126
procedure TIDEHelpManager.mnuHelpOnlineHelpClicked(Sender: TObject);
1128
ShowLazarusHelpStartPage;
1131
procedure TIDEHelpManager.mnuHelpReportBugClicked(Sender: TObject);
1133
OpenURL(lisReportingBugURL);
1136
procedure TIDEHelpManager.RegisterIDEHelpDatabases;
1138
procedure CreateMainIDEHelpDB;
1140
StartNode: THelpNode;
1141
HTMLHelp: THTMLHelpDatabase;
1143
FMainHelpDB:=HelpDatabases.CreateHelpDatabase(lihcStartPage,
1144
THTMLHelpDatabase,true);
1145
HTMLHelp:=FMainHelpDB as THTMLHelpDatabase;
1146
FMainHelpDBPath:=THelpBasePathObject.Create('$(LazarusDir)/docs');
1147
HTMLHelp.BasePathObject:=FMainHelpDBPath;
1149
// HTML nodes for the IDE
1150
StartNode:=THelpNode.CreateURLID(HTMLHelp,'Lazarus',
1151
'file://index.html',lihcStartPage);
1152
HTMLHelp.TOCNode:=THelpNode.Create(HTMLHelp,StartNode);// once as TOC
1153
HTMLHelp.RegisterItemWithNode(StartNode);// and once as normal page
1156
procedure CreateRTLHelpDB;
1158
HTMLHelp: TFPDocHTMLHelpDatabase;
1159
FPDocNode: THelpNode;
1160
DirItem: THelpDBISourceDirectory;
1162
FRTLHelpDB:=HelpDatabases.CreateHelpDatabase(lihcRTLUnits,
1163
TFPDocHTMLHelpDatabase,true);
1164
HTMLHelp:=FRTLHelpDB as TFPDocHTMLHelpDatabase;
1165
HTMLHelp.DefaultBaseURL:=lihRTLURL;
1166
FRTLHelpDBPath:=THelpBaseURLObject.Create;
1167
HTMLHelp.BasePathObject:=FRTLHelpDBPath;
1169
// FPDoc nodes for units in the RTL
1170
FPDocNode:=THelpNode.CreateURL(HTMLHelp,
1171
'RTL - Free Pascal Run Time Library Units',
1172
'file://index.html');
1173
HTMLHelp.TOCNode:=THelpNode.Create(HTMLHelp,FPDocNode);// once as TOC
1174
DirItem:=THelpDBISourceDirectory.Create(FPDocNode,'$(FPCSrcDir)/rtl',
1175
'*.pp;*.pas',true);// and once as normal page
1176
HTMLHelp.RegisterItem(DirItem);
1179
procedure CreateFCLHelpDB;
1181
HTMLHelp: TFPDocHTMLHelpDatabase;
1182
FPDocNode: THelpNode;
1183
DirItem: THelpDBISourceDirectory;
1185
FFCLHelpDB:=HelpDatabases.CreateHelpDatabase(lihcFCLUnits,
1186
TFPDocHTMLHelpDatabase,true);
1187
HTMLHelp:=FFCLHelpDB as TFPDocHTMLHelpDatabase;
1188
HTMLHelp.DefaultBaseURL:=lihFCLURL;
1189
FFCLHelpDBPath:=THelpBaseURLObject.Create;
1190
HTMLHelp.BasePathObject:=FFCLHelpDBPath;
1192
// FPDoc nodes for units in the FCL
1194
HTMLHelp.TOCNode:=THelpNode.CreateURL(HTMLHelp,
1195
'FCL - Free Pascal Component Library Units',
1196
'file://index.html');
1198
// fpc 2.0.x FCL source directory
1199
FPDocNode:=THelpNode.CreateURL(HTMLHelp,
1200
'FCL - Free Pascal Component Library Units (2.0.x)',
1201
'file://index.html');
1202
DirItem:=THelpDBISourceDirectory.Create(FPDocNode,
1203
'$(FPCSrcDir)/fcl/inc','*.pp;*.pas',false);
1204
HTMLHelp.RegisterItem(DirItem);
1206
// fpc 2.2.x FCL source directory
1207
FPDocNode:=THelpNode.CreateURL(HTMLHelp,
1208
'FCL - Free Pascal Component Library Units',
1209
'file://index.html');
1210
DirItem:=THelpDBISourceDirectory.Create(FPDocNode,
1211
'$(FPCSrcDir)/packages/fcl-base/src','*.pp;*.pas',true);
1212
HTMLHelp.RegisterItem(DirItem);
1214
// fpc 2.4.4+ FCL source directory
1215
FPDocNode:=THelpNode.CreateURL(HTMLHelp,
1216
'FCL - Free Pascal Component Library Units',
1217
'file://index.html');
1218
DirItem:=THelpDBISourceDirectories.Create(FPDocNode,'$(FPCSrcDir)/packages',
1219
'fcl-base/src;fcl-db/src;fcl-extra/src;fcl-process/src;fcl-web/src;paszlib/src',
1221
HTMLHelp.RegisterItem(DirItem);
1224
procedure CreateLCLHelpDB;
1226
HTMLHelp: TFPDocHTMLHelpDatabase;
1227
FPDocNode: THelpNode;
1228
DirItem: THelpDBISourceDirectory;
1230
FLCLHelpDB:=HelpDatabases.CreateHelpDatabase(lihcLCLUnits,
1231
TFPDocHTMLHelpDatabase,true);
1232
HTMLHelp:=FLCLHelpDB as TFPDocHTMLHelpDatabase;
1233
HTMLHelp.DefaultBaseURL:=lihLCLURL;
1234
FLCLHelpDBPath:=THelpBaseURLObject.Create;
1235
HTMLHelp.BasePathObject:=FLCLHelpDBPath;
1237
// FPDoc nodes for units in the RTL
1238
FPDocNode:=THelpNode.CreateURL(HTMLHelp,
1239
'LCL - Lazarus Component Library Units',
1240
'file://index.html');
1241
HTMLHelp.TOCNode:=THelpNode.Create(HTMLHelp,FPDocNode);// once as TOC
1242
DirItem:=THelpDBISourceDirectory.Create(FPDocNode,'$(LazarusDir)/lcl',
1243
'*.pp;*.pas',true);// and once as normal page
1244
HTMLHelp.RegisterItem(DirItem);
1247
procedure CreateFPCKeywordsHelpDB;
1249
{$IFDEF EnableSimpleFPCKeyWordHelpDB}
1250
HelpDatabases.CreateHelpDatabase('SimpleDemoForFPCKeyWordHelpDB',
1251
TSimpleFPCKeywordHelpDatabase,true);
1256
CreateMainIDEHelpDB;
1260
CreateFPCMessagesHelpDB;
1261
CreateFPCKeywordsHelpDB;
1264
procedure TIDEHelpManager.RegisterDefaultIDEHelpViewers;
1266
HelpViewer: THTMLBrowserHelpViewer;
1268
HelpViewer:= THTMLBrowserHelpViewer.Create(nil);
1269
HelpViewer.OnFindDefaultBrowser := @FindDefaultBrowser;
1270
HelpViewers.RegisterViewer(HelpViewer);
1273
procedure TIDEHelpManager.FindDefaultBrowser(var DefaultBrowser, Params: string);
1275
GetDefaultBrowser(DefaultBrowser, Params);
1278
constructor TIDEHelpManager.Create(TheOwner: TComponent);
1280
inherited Create(TheOwner);
1283
HelpOpts:=THelpOptions.Create;
1284
HelpOpts.SetDefaultFilename;
1285
HelpDatabases:=TIDEHelpDatabases.Create;
1286
HelpIntfs.HelpManager:=HelpDatabases;
1287
HelpViewers:=THelpViewers.Create;
1288
RegisterIDEHelpDatabases;
1289
RegisterDefaultIDEHelpViewers;
1291
CodeHelpBoss:=TCodeHelpManager.Create(Self);
1293
// register property editors for URL handling
1294
RegisterPropertyEditor(TypeInfo(AnsiString),
1295
THTMLHelpDatabase,'BaseURL',TURLDirectoryPropertyEditor);
1297
FHTMLProviders:=TLIHProviders.Create;
1299
if CreateIDEHTMLControl=nil then
1300
CreateIDEHTMLControl:=@LazCreateIDEHTMLControl;
1301
if CreateIDEHTMLProvider=nil then
1302
CreateIDEHTMLProvider:=@LazCreateIDEHTMLProvider;
1305
destructor TIDEHelpManager.Destroy;
1307
FreeThenNil(FHTMLProviders);
1308
FreeThenNil(CodeHelpBoss);
1309
FPCMessagesHelpDB:=nil;
1311
FreeThenNil(HelpOpts);
1312
FreeThenNil(FMainHelpDBPath);
1313
FreeThenNil(FRTLHelpDBPath);
1314
FreeThenNil(FFCLHelpDBPath);
1315
FreeThenNil(FLCLHelpDBPath);
1321
procedure TIDEHelpManager.ConnectMainBarEvents;
1325
itmHelpAboutLazarus.OnClick := @mnuHelpAboutLazarusClicked;
1326
itmHelpOnlineHelp.OnClick := @mnuHelpOnlineHelpClicked;
1327
itmHelpReportingBug.OnClick := @mnuHelpReportBugClicked;
1329
{$IFDEF EnableFPDocSearch}
1330
itmSearchInFPDocFiles.OnClick:=@mnuSearchInFPDocFilesClick;
1337
procedure TIDEHelpManager.LoadHelpOptions;
1342
procedure TIDEHelpManager.SaveHelpOptions;
1347
procedure TIDEHelpManager.ShowLazarusHelpStartPage;
1349
ShowIDEHelpForKeyword(lihcStartPage);
1352
procedure TIDEHelpManager.ShowIDEHelpForContext(HelpContext: THelpContext);
1354
ShowHelpOrErrorForContext(MainHelpDB.ID,HelpContext);
1357
procedure TIDEHelpManager.ShowIDEHelpForKeyword(const Keyword: string);
1359
ShowHelpOrErrorForKeyword(MainHelpDB.ID,Keyword);
1362
function TIDEHelpManager.ShowHelpForSourcePosition(const Filename: string;
1363
const CodePos: TPoint; var ErrMsg: string): TShowHelpResult;
1365
function CollectKeyWords(CodeBuffer: TCodeBuffer): TShowHelpResult;
1368
IdentStart, IdentEnd: integer;
1372
Result:=shrHelpNotFound;
1374
CodeBuffer.LineColToPosition(CodePos.Y,CodePos.X,p);
1376
GetIdentStartEndAtPosition(CodeBuffer.Source,p,IdentStart,IdentEnd);
1377
if IdentEnd<=IdentStart then exit;
1378
if (IdentStart > 1) and (CodeBuffer.Source[IdentStart - 1] in ['$','%']) then
1380
KeyWord:=copy(CodeBuffer.Source,IdentStart,IdentEnd-IdentStart);
1382
if KeyWord[1] = '$' then
1383
Result:=ShowHelpForDirective('',FPCDirectiveHelpPrefix+Keyword,ErrorMsg)
1384
else if KeyWord[1] = '%' then
1385
Result:=ShowHelpForDirective('',IDEDirectiveHelpPrefix+Keyword,ErrorMsg)
1387
Result:=ShowHelpForKeyword('',FPCKeyWordHelpPrefix+Keyword,ErrorMsg);
1388
if Result=shrHelpNotFound then exit;
1389
HelpManager.ShowError(Result,ErrorMsg);
1392
function CollectDeclarations(CodeBuffer: TCodeBuffer;
1393
out Complete: boolean): TShowHelpResult;
1395
NewList: TPascalHelpContextList;
1396
PascalHelpContextLists: TList;
1397
ListOfPCodeXYPosition: TFPList;
1398
CurCodePos: PCodeXYPosition;
1402
Result:=shrHelpNotFound;
1403
ListOfPCodeXYPosition:=nil;
1404
PascalHelpContextLists:=nil;
1406
// get all possible declarations of this identifier
1407
if CodeToolBoss.FindDeclarationAndOverload(CodeBuffer,CodePos.X,CodePos.Y,
1408
ListOfPCodeXYPosition,[fdlfWithoutEmptyProperties,fdlfWithoutForwards])
1410
if ListOfPCodeXYPosition=nil then exit;
1411
debugln('TIDEHelpManager.ShowHelpForSourcePosition B Success ',dbgs(ListOfPCodeXYPosition.Count));
1412
// convert the source positions in pascal help context list
1413
for i:=0 to ListOfPCodeXYPosition.Count-1 do begin
1414
CurCodePos:=PCodeXYPosition(ListOfPCodeXYPosition[i]);
1415
debugln('TIDEHelpManager.ShowHelpForSourcePosition C ',CurCodePos^.Code.Filename,' X=',dbgs(CurCodePos^.X),' Y=',dbgs(CurCodePos^.Y));
1416
NewList:=ConvertCodePosToPascalHelpContext(CurCodePos);
1417
if NewList<>nil then begin
1418
if PascalHelpContextLists=nil then
1419
PascalHelpContextLists:=TList.Create;
1420
PascalHelpContextLists.Add(NewList);
1423
if PascalHelpContextLists=nil then exit;
1425
// invoke help system
1427
debugln('TIDEHelpManager.ShowHelpForSourcePosition D PascalHelpContextLists.Count=',dbgs(PascalHelpContextLists.Count));
1428
Result:=ShowHelpForPascalContexts(Filename,CodePos,PascalHelpContextLists,ErrMsg);
1429
end else if CodeToolBoss.ErrorCode<>nil then begin
1430
MainIDEInterface.DoJumpToCodeToolBossError;
1434
FreeListOfPCodeXYPosition(ListOfPCodeXYPosition);
1435
if PascalHelpContextLists<>nil then begin
1436
for i:=0 to PascalHelpContextLists.Count-1 do
1437
TObject(PascalHelpContextLists[i]).Free;
1438
PascalHelpContextLists.Free;
1444
CodeBuffer: TCodeBuffer;
1447
debugln('TIDEHelpManager.ShowHelpForSourcePosition A Filename=',Filename,' ',dbgs(CodePos));
1448
Result:=shrHelpNotFound;
1449
ErrMsg:='No help found for "'+Filename+'"'
1450
+' at ('+IntToStr(CodePos.Y)+','+IntToStr(CodePos.X)+')';
1451
// commit editor changes
1452
if not CodeToolBoss.GatherExternalChanges then exit;
1453
// get code buffer for Filename
1454
if mrOk<>LoadCodeBuffer(CodeBuffer,FileName,[lbfCheckIfText],false) then
1457
Result:=CollectDeclarations(CodeBuffer,Complete);
1458
if Complete then exit;
1459
Result:=CollectKeyWords(CodeBuffer);
1462
function TIDEHelpManager.ConvertCodePosToPascalHelpContext(
1463
ACodePos: PCodeXYPosition): TPascalHelpContextList;
1465
procedure AddContext(Descriptor: TPascalHelpContextType;
1466
const Context: string);
1468
Result.Add(Descriptor,Context);
1469
//debugln(' AddContext Descriptor=',dbgs(ord(Descriptor)),' Context="',Context,'"');
1472
procedure AddContextsBackwards(Tool: TCodeTool;
1473
Node: TCodeTreeNode);
1475
if Node=nil then exit;
1476
AddContextsBackwards(Tool,Node.Parent);
1478
ctnUnit, ctnPackage, ctnProgram, ctnLibrary:
1479
AddContext(pihcSourceName,Tool.GetSourceName);
1481
AddContext(pihcVariable,Tool.ExtractDefinitionName(Node));
1483
AddContext(pihcType,Tool.ExtractDefinitionName(Node));
1485
AddContext(pihcConst,Tool.ExtractDefinitionName(Node));
1487
AddContext(pihcProperty,Tool.ExtractPropName(Node,false));
1489
AddContext(pihcProcedure,Tool.ExtractProcName(Node,
1490
[phpWithoutClassName]));
1492
AddContext(pihcParameterList,Tool.ExtractProcHead(Node,
1493
[phpWithoutClassKeyword,phpWithoutClassName,phpWithoutName,
1494
phpWithoutSemicolon]));
1499
MainCodeBuffer: TCodeBuffer;
1500
Tool: TCustomCodeTool;
1503
Node: TCodeTreeNode;
1504
IncludeChain: TFPList;
1505
ConversionResult: LongInt;
1509
if ACodePos^.Code=nil then begin
1510
debugln('WARNING: ConvertCodePosToPascalHelpContext ACodePos.Code=nil');
1513
Result:=TPascalHelpContextList.Create;
1514
// add filename and all filenames of the include chain
1517
CodeToolBoss.GetIncludeCodeChain(ACodePos^.Code,true,IncludeChain);
1518
if IncludeChain=nil then begin
1519
debugln('WARNING: ConvertCodePosToPascalHelpContext IncludeChain=nil');
1522
for i:=0 to IncludeChain.Count-1 do
1523
AddContext(pihcFilename,TCodeBuffer(IncludeChain[i]).Filename);
1524
MainCodeBuffer:=TCodeBuffer(IncludeChain[0]);
1529
Tool:=CodeToolBoss.FindCodeToolForSource(MainCodeBuffer);
1530
if not (Tool is TCodeTool) then begin
1531
debugln('WARNING: ConvertCodePosToPascalHelpContext not (Tool is TCodeTool) MainCodeBuffer=',MainCodeBuffer.Filename);
1534
// convert cursor position to clean position
1535
ConversionResult:=Tool.CaretToCleanPos(ACodePos^,CleanPos);
1536
if ConversionResult<>0 then begin
1537
// position not in clean code, maybe a comment, maybe behind last line
1542
Node:=Tool.FindDeepestNodeAtPos(CleanPos,false);
1543
if Node=nil then begin
1544
// position not in a scanned pascal node, maybe in between
1548
AddContextsBackwards(TCodeTool(Tool),Node);
1551
function TIDEHelpManager.GetFPDocFilenameForSource(SrcFilename: string;
1552
ResolveIncludeFiles: Boolean; out AnOwner: TObject): string;
1554
CacheWasUsed: boolean;
1556
Result:=CodeHelpBoss.GetFPDocFilenameForSource(SrcFilename,ResolveIncludeFiles,
1557
CacheWasUsed,AnOwner);
1560
procedure TIDEHelpManager.ShowHelpForMessage(Line: integer);
1562
function ParseMessage(MsgItem: TIDEMessageLine): TStringList;
1564
Result:=TStringList.Create;
1565
Result.Values['Message']:=MsgItem.Msg;
1566
if MsgItem.Parts<>nil then
1567
Result.Assign(MsgItem.Parts);
1571
MsgItem: TIDEMessageLine;
1572
MessageParts: TStringList;
1574
//debugln('TIDEHelpManager.ShowHelpForMessage A Line=',dbgs(Line));
1575
if MessagesView=nil then exit;
1577
Line:=MessagesView.SelectedMessageIndex;
1578
//DebugLn('TIDEHelpManager.ShowHelpForMessage B Line=',dbgs(Line),' ',dbgs(MessagesView.VisibleItemCount));
1579
if (Line<0) or (Line>=MessagesView.VisibleItemCount) then exit;
1580
MsgItem:=MessagesView.VisibleItems[Line];
1581
if MsgItem=nil then exit;
1582
if MsgItem.Msg<>'' then begin
1583
MessageParts:=ParseMessage(MsgItem);
1584
ShowHelpOrErrorForMessageLine(MsgItem.Msg,MessageParts);
1588
procedure TIDEHelpManager.ShowHelpForObjectInspector(Sender: TObject);
1590
AnInspector: TObjectInspectorDlg;
1594
NewTopLine: integer;
1596
//DebugLn('TIDEHelpManager.ShowHelpForObjectInspector ',dbgsName(Sender));
1597
if Sender=nil then Sender:=ObjectInspector1;
1598
if Sender is TObjectInspectorDlg then begin
1599
AnInspector:=TObjectInspectorDlg(Sender);
1600
if AnInspector.GetActivePropertyRow<>nil then begin
1601
if FindDeclarationOfOIProperty(AnInspector,nil,Code,Caret,NewTopLine) then
1603
if NewTopLine=0 then ;
1604
ShowHelpForSourcePosition(Code.Filename,Caret,ErrMsg);
1607
DebugLn('TIDEHelpManager.ShowHelpForObjectInspector show default help for OI');
1608
ShowHelpForIDEControl(AnInspector);
1613
procedure TIDEHelpManager.ShowHelpForIDEControl(Sender: TControl);
1616
IDEWindowHelpNodes.InvokeHelp(Sender);
1619
function TIDEHelpManager.CreateHint(aHintWindow: THintWindow; ScreenPos: TPoint;
1620
const BaseURL: string; var TheHint: string; out HintWinRect: TRect): boolean;
1623
Provider: TAbstractIDEHTMLProvider;
1624
HTMLControl: TControl;
1626
NewWidth, NewHeight: integer;
1628
IsHTML:=SysUtils.CompareText(copy(TheHint,1,6),'<HTML>')=0;
1630
if aHintWindow.ControlCount>0 then begin
1631
aHintWindow.Controls[0].Free;
1633
if IsHTML then begin
1635
HTMLControl:=CreateIDEHTMLControl(aHintWindow,Provider, [ihcWithClipboardMenu]);
1636
Provider.BaseURL:=BaseURL;
1637
HTMLControl.Parent:=aHintWindow;
1638
HTMLControl.Align:=alClient;
1639
ms:=TMemoryStream.Create;
1642
ms.Write(TheHint[1],length(TheHint));
1644
Provider.ControlIntf.SetHTMLContent(ms,'');
1648
Provider.ControlIntf.GetPreferredControlSize(NewWidth,NewHeight);
1650
if NewWidth <= 0 then
1653
inc(NewWidth, 8); // border
1655
if NewHeight <= 0 then
1658
inc(NewHeight, 8); // border
1660
HintWinRect := Rect(0, 0, NewWidth, NewHeight);
1663
HintWinRect := aHintWindow.CalcHintRect(Screen.Width, TheHint, nil);
1665
OffsetRect(HintWinRect, ScreenPos.X, ScreenPos.Y+30);
1670
function TIDEHelpManager.GetHintForSourcePosition(
1671
const ExpandedFilename: string; const CodePos: TPoint; out BaseURL,
1672
HTMLHint: string; Flags: TIDEHelpManagerCreateHintFlags): TShowHelpResult;
1675
CacheWasUsed: boolean;
1676
HintFlags: TCodeHelpHintOptions;
1680
Code:=CodeToolBoss.LoadFile(ExpandedFilename,true,false);
1681
if (Code=nil) or Code.LineColIsSpace(CodePos.Y,CodePos.X) then
1682
exit(shrHelpNotFound);
1683
HintFlags:=[chhoDeclarationHeader];
1684
if ihmchAddFocusHint in Flags then
1685
Include(HintFlags,chhoShowFocusHint);
1686
if CodeHelpBoss.GetHTMLHint(Code,CodePos.X,CodePos.Y,
1687
HintFlags,BaseURL,HTMLHint,CacheWasUsed)=chprSuccess
1690
Result:=shrHelpNotFound;
1693
function TIDEHelpManager.ConvertSourcePosToPascalHelpContext(
1694
const CaretPos: TPoint; const Filename: string): TPascalHelpContextList;
1696
CodePos: TCodeXYPosition;
1698
ACodeTool: TCodeTool;
1701
Code:=CodeToolBoss.FindFile(Filename);
1702
if Code=nil then exit;
1704
CodePos.X:=CaretPos.X;
1705
CodePos.Y:=CaretPos.Y;
1706
if not CodeToolBoss.Explore(Code,ACodeTool,false) then exit;
1707
if ACodeTool=nil then ;
1708
Result:=ConvertCodePosToPascalHelpContext(@CodePos);