diff --git a/.gitattributes b/.gitattributes index f85d38b2c8..d603b35d43 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1303,6 +1303,9 @@ ide/lazdoc.pas svneol=native#text/plain ide/lazdocfrm.lfm svneol=native#text/plain ide/lazdocfrm.lrs svneol=native#text/plain ide/lazdocfrm.pas svneol=native#text/plain +ide/lazdocselectinherited.lfm svneol=native#text/plain +ide/lazdocselectinherited.lrs svneol=native#text/plain +ide/lazdocselectinherited.pas svneol=native#text/plain ide/lrtpotools.pas svneol=native#text/pascal ide/macropromptdlg.pas svneol=native#text/pascal ide/main.pp svneol=native#text/pascal diff --git a/docs/xml/lcl/buttons.xml b/docs/xml/lcl/buttons.xml index fa451b7d15..848547ff64 100644 --- a/docs/xml/lcl/buttons.xml +++ b/docs/xml/lcl/buttons.xml @@ -390,8 +390,8 @@ Constructors allocate memory and system resources needed by the object. They als - Is used to align a button to a border of a parent control. - Align is used to align a control to a border of a parent control, even if the parent control is resized.

+ +

Possible values fo Allign are:
alTop: Places the control at the top, using the full clientwidth of its parent control.
alBottom: Places the control at the bottom, using the full clientwidth of its parent control.
@@ -399,6 +399,9 @@ alLeft: Places the control at the left side of its parent and uses the available alRight: Like alLeft but on the right side of the parent control.
alNone: The control can be placed anywhere on the parent control.
alClient: The control takes al available space on parent control next to controls aligned to the top, bottom, right or left.
+ + +
diff --git a/docs/xml/lcl/controls.xml b/docs/xml/lcl/controls.xml index f451c515b2..7580d2b96e 100644 --- a/docs/xml/lcl/controls.xml +++ b/docs/xml/lcl/controls.xml @@ -6986,9 +6986,11 @@ - - - + Used to align the control in one of four directions. + + + + @@ -10585,8 +10587,10 @@ paint requests received by the parent control.

A clipping window to the parent canvas. -

The TGraphicsControl.Canvas is a clipping window to the parent -canvas.

If you ask for the Canvas.Width or Canvas.Height, you are actually + +

The TGraphicsControl.Canvas is a clipping window to the parent +canvas.

+

If you ask for the Canvas.Width or Canvas.Height, you are actually getting the parent control's Canvas dimensions. To get the dimensions of the TGraphicControl, you must query the ClientRect.

diff --git a/ide/lazdoc.pas b/ide/lazdoc.pas index 86aa7fb346..8e8ff03ef9 100644 --- a/ide/lazdoc.pas +++ b/ide/lazdoc.pas @@ -31,21 +31,20 @@ unit LazDoc; interface uses - Classes, SysUtils, - LCLProc, - CodeToolManager, CodeCache, FileProcs, + Classes, SysUtils, LCLProc, FileUtil, + CodeToolManager, CodeCache, FileProcs, AvgLvlTree, Laz_DOM, Laz_XMLRead, Laz_XMLWrite, - LazHelpIntf, - EnvironmentOpts; + MacroIntf, PackageIntf, LazHelpIntf, ProjectIntf, LazIDEIntf, + IDEProcs, PackageDefs, EnvironmentOpts; type { TLazFPDocFile } TLazFPDocFile = class public - Doc: TXMLdocument; Filename: string; - ChangeStep: integer; + Doc: TXMLdocument; + ChangeStep: integer;// the CodeBuffer.ChangeStep value, when Doc was build CodeBuffer: TCodeBuffer; destructor Destroy; override; end; @@ -54,7 +53,7 @@ type TLazDocManager = class private - FDocs: TFPList;// list of loaded TLazFPDocFile + FDocs: TAvgLvlTree;// tree of loaded TLazFPDocFile public constructor Create; destructor Destroy; override; @@ -64,12 +63,28 @@ type out ADocFile: TLazFPDocFile): Boolean; function GetFPDocFilenameForHelpContext( Context: TPascalHelpContextList): string; - function GetFPDocFilenameForSource(const SrcFilename: string): string; + function GetFPDocFilenameForSource(SrcFilename: string; + ResolveIncludeFiles: Boolean): string; procedure FreeDocs; end; + +function CompareLazFPDocFilenames(Data1, Data2: Pointer): integer; +function CompareAnsistringWithLazFPDocFile(Key, Data: Pointer): integer; + implementation +function CompareLazFPDocFilenames(Data1, Data2: Pointer): integer; +begin + Result:=CompareFilenames(TLazFPDocFile(Data1).Filename, + TLazFPDocFile(Data2).Filename); +end; + +function CompareAnsistringWithLazFPDocFile(Key, Data: Pointer): integer; +begin + Result:=CompareFilenames(AnsiString(Key),TLazFPDocFile(Data).Filename); +end; + { TLazFPDocFile } destructor TLazFPDocFile.Destroy; @@ -80,7 +95,7 @@ end; constructor TLazDocManager.Create; begin - FDocs:=TFPList.Create; + FDocs:=TAvgLvlTree.Create(@CompareLazFPDocFilenames); end; destructor TLazDocManager.Destroy; @@ -92,13 +107,13 @@ end; function TLazDocManager.FindFPDocFile(const Filename: string): TLazFPDocFile; var - i: Integer; + Node: TAvgLvlTreeNode; begin - for i:=0 to FDocs.Count-1 do begin - Result:=TLazFPDocFile(FDocs[i]); - if CompareFilenames(Result.Filename,Filename)=0 then exit; - end; - Result:=nil; + Node:=FDocs.FindKey(Pointer(Filename),@CompareAnsistringWithLazFPDocFile); + if Node<>nil then + Result:=TLazFPDocFile(Node.Data) + else + Result:=nil; end; function TLazDocManager.LoadFPDocFile(const Filename: string; UpdateFromDisk, @@ -125,6 +140,8 @@ begin // no update needed exit(true); end; + + DebugLn(['TLazDocManager.LoadFPDocFile parsing ',ADocFile.Filename]); // parse XML ADocFile.ChangeStep:=ADocFile.CodeBuffer.ChangeStep; @@ -152,37 +169,111 @@ begin for i:=0 to Context.Count-1 do begin if Context.Items[i].Descriptor<>pihcFilename then continue; SrcFilename:=Context.Items[i].Context; - Result:=GetFPDocFilenameForSource(SrcFilename); + Result:=GetFPDocFilenameForSource(SrcFilename,true); exit; end; end; -function TLazDocManager.GetFPDocFilenameForSource(const SrcFilename: string - ): string; +function TLazDocManager.GetFPDocFilenameForSource(SrcFilename: string; + ResolveIncludeFiles: Boolean): string; var SrcDir: String; FPDocName: String; -begin - SrcDir:=ExtractFilePath(SrcFilename); - FPDocName:=lowercase(ExtractFileNameOnly(SrcFilename))+'.xml'; - // check if SrcFilename is in one of the project directories - - // check if SrcFilename is in one of package directories - - // check if SrcFilename is one of the Lazarus sources - - // search in the default LazDoc paths + SearchPath: String; + procedure CheckIfInProject(AProject: TLazProject); + var + ProjectDirs: String; + begin + if AProject=nil then exit; + if (AProject.FindFile(SrcFilename,[pfsfOnlyProjectFiles])<>nil) then begin + SearchPath:=SearchPath+';'+AProject.LazDocPaths; + exit; + end; + // search in project directories + if not FilenameIsAbsolute(SrcFilename) then exit; + ProjectDirs:=AProject.LazCompilerOptions.OtherUnitFiles; + if FindPathInSearchPath(PChar(SrcDir),length(SrcDir), + PChar(ProjectDirs),length(ProjectDirs))<>nil + then + SearchPath:=SearchPath+';'+AProject.LazDocPaths; + end; + + procedure CheckIfInAPackage; + var + PkgList: TList; + i: Integer; + Dirs: String; + APackage: TLazPackage; + begin + if not FilenameIsAbsolute(SrcFilename) then exit; + PkgList:=PackageEditingInterface.GetOwnersOfUnit(SrcFilename); + if PkgList=nil then exit; + try + for i:=0 to PkgList.Count-1 do begin + if TObject(PkgList[i]) is TLazPackage then begin + APackage:=TLazPackage(PkgList[i]); + Dirs:=APackage.CompilerOptions.OtherUnitFiles; + if FindPathInSearchPath(PChar(SrcDir),length(SrcDir), + PChar(Dirs),length(Dirs))<>nil + then begin + // TODO: add lazdoc paths to package + //SearchPath:=SearchPath+';'+APackage.LazDocPaths; + end; + end; + end; + finally + PkgList.Free; + end; + end; + + procedure CheckIfInLazarus; + var + LazDir: String; + begin + if not FilenameIsAbsolute(SrcFilename) then exit; + LazDir:=AppendPathDelim(EnvironmentOptions.LazarusDirectory); + if FileIsInPath(SrcFilename,LazDir+'lcl') then begin + SearchPath:=SearchPath+';'+LazDir+SetDirSeparators('docs/xml/lcl'); + end; + end; + +var + CodeBuf: TCodeBuffer; +begin Result:=''; + + if ResolveIncludeFiles then begin + CodeBuf:=CodeToolBoss.FindFile(SrcFilename); + if CodeBuf<>nil then begin + CodeBuf:=CodeToolBoss.GetMainCode(CodeBuf); + if CodeBuf<>nil then begin + SrcFilename:=CodeBuf.Filename; + end; + end; + end; + + if not FilenameIsPascalSource(SrcFilename) then exit; + + SrcDir:=ExtractFilePath(SrcFilename); + + SearchPath:=''; + CheckIfInProject(LazarusIDE.ActiveProject); + CheckIfInAPackage; + CheckIfInLazarus; + // finally add default paths + SearchPath:=SearchPath+';'+EnvironmentOptions.LazDocPaths; + // substitute macros + IDEMacros.SubstituteMacros(SearchPath); + + FPDocName:=lowercase(ExtractFileNameOnly(SrcFilename))+'.xml'; + DebugLn(['TLazDocManager.GetFPDocFilenameForSource Search ',FPDocName,' in "',SearchPath,'"']); + Result:=SearchFileInPath(FPDocName,'',SearchPath,';',ctsfcAllCase); end; procedure TLazDocManager.FreeDocs; -var - i: Integer; begin - for i:=FDocs.Count-1 downto 0 do - TObject(FDocs[i]).Free; - FDocs.Clear; + FDocs.FreeAndClear; end; end. diff --git a/ide/lazdocfrm.lfm b/ide/lazdocfrm.lfm index d39fd44a7f..7b8a05110a 100644 --- a/ide/lazdocfrm.lfm +++ b/ide/lazdocfrm.lfm @@ -151,7 +151,6 @@ object LazDocForm: TLazDocForm end object InheritedTabSheet: TTabSheet Caption = 'InheritedTabSheet' - TabVisible = False object InheritedShortLabel: TLabel Left = 5 Height = 13 @@ -172,9 +171,36 @@ object LazDocForm: TLazDocForm Width = 732 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 2 + ReadOnly = True TabOrder = 0 Text = 'InheritedShortEdit' end + object MoveToInheritedButton: TButton + Height = 26 + Top = 54 + Width = 143 + AutoSize = True + BorderSpacing.InnerBorder = 4 + Caption = 'MoveToInheritedButton' + OnClick = MoveToInheritedButtonClick + TabOrder = 1 + end + object CopyFromInheritedButton: TButton + AnchorSideLeft.Control = MoveToInheritedButton + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = MoveToInheritedButton + AnchorSideTop.Side = asrCenter + Left = 153 + Height = 26 + Top = 54 + Width = 155 + AutoSize = True + BorderSpacing.Left = 10 + BorderSpacing.InnerBorder = 4 + Caption = 'CopyFromInheritedButton' + OnClick = CopyFromInheritedButtonClick + TabOrder = 2 + end end end object Panel1: TPanel diff --git a/ide/lazdocfrm.lrs b/ide/lazdocfrm.lrs index 36662261ee..9fc591c83c 100644 --- a/ide/lazdocfrm.lrs +++ b/ide/lazdocfrm.lrs @@ -47,128 +47,137 @@ LazarusResources.Add('TLazDocForm','FORMDATA',[ +#6'Height'#2#26#3'Top'#2#28#5'Width'#3#137#0#7'Anchors'#11#5'akTop'#7'akRigh' +'t'#0#8'AutoSize'#9#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#19'Browse' +'ExampleButton'#7'OnClick'#7#24'BrowseExampleButtonClick'#8'TabOrder'#2#1#0#0 - +#0#9'TTabSheet'#17'InheritedTabSheet'#7'Caption'#6#17'InheritedTabSheet'#10 - +'TabVisible'#8#0#6'TLabel'#19'InheritedShortLabel'#4'Left'#2#5#6'Height'#2#13 - +#3'Top'#2#4#5'Width'#2'm'#7'Caption'#6#19'InheritedShortLabel'#5'Color'#7#6 - +'clNone'#11'ParentColor'#8#0#0#5'TEdit'#18'InheritedShortEdit'#22'AnchorSide' - +'Left.Control'#7#17'InheritedTabSheet'#21'AnchorSideTop.Control'#7#19'Inheri' - +'tedShortLabel'#18'AnchorSideTop.Side'#7#9'asrBottom'#23'AnchorSideRight.Con' - +'trol'#7#17'InheritedTabSheet'#20'AnchorSideRight.Side'#7#9'asrBottom'#6'Hei' - +'ght'#2#23#3'Top'#2#19#5'Width'#3#220#2#7'Anchors'#11#5'akTop'#6'akLeft'#7'a' - +'kRight'#0#17'BorderSpacing.Top'#2#2#8'TabOrder'#2#0#4'Text'#6#18'InheritedS' - +'hortEdit'#0#0#0#0#6'TPanel'#6'Panel1'#6'Height'#2'u'#5'Width'#2#17#5'Align' - +#7#6'alLeft'#10'BevelOuter'#7#6'bvNone'#11'FullRepaint'#8#14'ParentShowHint' - +#8#8'ShowHint'#9#8'TabOrder'#2#1#0#12'TSpeedButton'#16'BoldFormatButton'#6'H' - +'eight'#2#17#5'Width'#2#17#5'Align'#7#5'alTop'#5'Color'#7#9'clBtnFace'#10'Gl' - +'yph.Data'#10#182#1#0#0#178#1#0#0'/* XPM */'#10'static char *graphic[] = {' - +#10'"17 17 2 1",'#10'". c None",'#10'", c #000000",'#10'".................",' - +#10'".................",'#10'".................",'#10'".................",' - +#10'"....,,,,,,,,.....",'#10'".....,,,..,,,....",'#10'".....,,,..,,,....",' - +#10'".....,,,..,,,....",'#10'".....,,,,,,,.....",'#10'".....,,,..,,,....",' - ,#10'".....,,,..,,,....",'#10'".....,,,..,,,....",'#10'"....,,,,,,,,.....",' - +#10'".................",'#10'".................",'#10'".................",' - +#10'"................."}'#10#9'NumGlyphs'#2#0#7'OnClick'#7#17'FormatButtonCl' - +'ick'#0#0#12'TSpeedButton'#18'ItalicFormatButton'#3'Tag'#2#1#6'Height'#2#17#3 - +'Top'#2#17#5'Width'#2#17#5'Align'#7#5'alTop'#5'Color'#7#9'clBtnFace'#10'Glyp' - +'h.Data'#10#197#1#0#0#193#1#0#0'/* XPM */'#10'static char *graphic[] = {'#10 - +'"17 17 3 1",'#10'". c None",'#10'", c #000000",'#10'"- c #9696AF",'#10'"...' - +'..............",'#10'".................",'#10'".................",'#10'"...' - +'.....,,,,,....",'#10'".........,,-.....",'#10'"........-,,......",'#10'"...' - +'.....,,-......",'#10'".......-,,.......",'#10'".......,,-.......",'#10'"...' - +'...-,,........",'#10'"......,,-........",'#10'"....,,,,,,.......",'#10'"...' + +#0#9'TTabSheet'#17'InheritedTabSheet'#7'Caption'#6#17'InheritedTabSheet'#0#6 + +'TLabel'#19'InheritedShortLabel'#4'Left'#2#5#6'Height'#2#13#3'Top'#2#4#5'Wid' + +'th'#2'm'#7'Caption'#6#19'InheritedShortLabel'#5'Color'#7#6'clNone'#11'Paren' + +'tColor'#8#0#0#5'TEdit'#18'InheritedShortEdit'#22'AnchorSideLeft.Control'#7 + +#17'InheritedTabSheet'#21'AnchorSideTop.Control'#7#19'InheritedShortLabel'#18 + +'AnchorSideTop.Side'#7#9'asrBottom'#23'AnchorSideRight.Control'#7#17'Inherit' + +'edTabSheet'#20'AnchorSideRight.Side'#7#9'asrBottom'#6'Height'#2#23#3'Top'#2 + +#19#5'Width'#3#220#2#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#17'Border' + +'Spacing.Top'#2#2#8'ReadOnly'#9#8'TabOrder'#2#0#4'Text'#6#18'InheritedShortE' + +'dit'#0#0#7'TButton'#21'MoveToInheritedButton'#6'Height'#2#26#3'Top'#2'6'#5 + +'Width'#3#143#0#8'AutoSize'#9#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6 + +#21'MoveToInheritedButton'#7'OnClick'#7#26'MoveToInheritedButtonClick'#8'Tab' + +'Order'#2#1#0#0#7'TButton'#23'CopyFromInheritedButton'#22'AnchorSideLeft.Con' + +'trol'#7#21'MoveToInheritedButton'#19'AnchorSideLeft.Side'#7#9'asrBottom'#21 + +'AnchorSideTop.Control'#7#21'MoveToInheritedButton'#18'AnchorSideTop.Side'#7 + +#9'asrCenter'#4'Left'#3#153#0#6'Height'#2#26#3'Top'#2'6'#5'Width'#3#155#0#8 + +'AutoSize'#9#18'BorderSpacing.Left'#2#10#25'BorderSpacing.InnerBorder'#2#4#7 + +'Caption'#6#23'CopyFromInheritedButton'#7'OnClick'#7#28'CopyFromInheritedBut' + ,'tonClick'#8'TabOrder'#2#2#0#0#0#0#6'TPanel'#6'Panel1'#6'Height'#2'u'#5'Widt' + +'h'#2#17#5'Align'#7#6'alLeft'#10'BevelOuter'#7#6'bvNone'#11'FullRepaint'#8#14 + +'ParentShowHint'#8#8'ShowHint'#9#8'TabOrder'#2#1#0#12'TSpeedButton'#16'BoldF' + +'ormatButton'#6'Height'#2#17#5'Width'#2#17#5'Align'#7#5'alTop'#5'Color'#7#9 + +'clBtnFace'#10'Glyph.Data'#10#182#1#0#0#178#1#0#0'/* XPM */'#10'static char ' + +'*graphic[] = {'#10'"17 17 2 1",'#10'". c None",'#10'", c #000000",'#10'"...' +'..............",'#10'".................",'#10'".................",'#10'"...' + +'..............",'#10'"....,,,,,,,,.....",'#10'".....,,,..,,,....",'#10'"...' + +'..,,,..,,,....",'#10'".....,,,..,,,....",'#10'".....,,,,,,,.....",'#10'"...' + +'..,,,..,,,....",'#10'".....,,,..,,,....",'#10'".....,,,..,,,....",'#10'"...' + +'.,,,,,,,,.....",'#10'".................",'#10'".................",'#10'"...' +'..............",'#10'"................."}'#10#9'NumGlyphs'#2#0#7'OnClick'#7 - +#17'FormatButtonClick'#0#0#12'TSpeedButton'#21'UnderlineFormatButton'#3'Tag' - +#2#2#6'Height'#2#17#3'Top'#2'"'#5'Width'#2#17#5'Align'#7#5'alTop'#5'Color'#7 - +#9'clBtnFace'#10'Glyph.Data'#10#197#1#0#0#193#1#0#0'/* XPM */'#10'static cha' - +'r *graphic[] = {'#10'"17 17 3 1",'#10'". c None",'#10'", c #000000",'#10'"-' - +' c #848484",'#10'".................",'#10'".................",'#10'".......' - +'..........",'#10'"....,,,,.,,,,....",'#10'".....,,...,,.....",'#10'".....,,' - +'...,,.....",'#10'".....,,...,,.....",'#10'".....,,...,,.....",'#10'".....,,' - +'...,,.....",'#10'".....,,...,,.....",'#10'".....,,-.-,,.....",'#10'"......,' - +',,,,......",'#10'".................",'#10'"....,,,,,,,,,....",'#10'".......' - +'..........",'#10'".................",'#10'"................."}'#10#9'NumGly' - +'phs'#2#0#7'OnClick'#7#17'FormatButtonClick'#0#0#12'TSpeedButton'#19'InsertC' - +'odeTagButton'#3'Tag'#2#3#6'Height'#2#17#3'Top'#2'3'#5'Width'#2#17#5'Align'#7 - +#5'alTop'#5'Color'#7#9'clBtnFace'#10'Glyph.Data'#10#253#9#0#0#249#9#0#0'/* X' - +'PM */'#13#10'static char * InsertCodeTag_xpm[] = {'#13#10'"17 15 112 2",'#13 - +#10'" '#9'c None",'#13#10'". '#9'c #ECE9D8",'#13#10'"+ '#9'c #FFF0CF",'#13 - +#10'"@ '#9'c #FFEDC5",'#13#10'"# '#9'c #FBE8C5",'#13#10'"$ '#9'c #EDDAC5",' - +#13#10'"% '#9'c #F4E8DB",'#13#10'"& '#9'c #FAEDD5",'#13#10'"* '#9'c #F3D49E"' - +','#13#10'"= '#9'c #BF9855",'#13#10'"- '#9'c #C89D55",'#13#10'"; '#9'c #BC8E' - +'5A",'#13#10'"> '#9'c #7C6135",'#13#10'", '#9'c #B18655",'#13#10'"'' '#9'c #' - +'916940",'#13#10'") '#9'c #C3AC93",'#13#10'"! '#9'c #CCA76A",'#13#10'"~ '#9 - +'c #80684A",'#13#10'"{ '#9'c #DCAA63",'#13#10'"] '#9'c #A8834A",'#13#10'"^ ' - +#9'c #977443",'#13#10'"/ '#9'c #B99052",'#13#10'"( '#9'c #947047",'#13#10'"_' - +' '#9'c #896842",'#13#10'": '#9'c #C4955E",'#13#10'"< '#9'c #87653F",'#13#10 - +'"[ '#9'c #A37A4E",'#13#10'"} '#9'c #F0E1CF",'#13#10'"| '#9'c #BD964F",'#13 - +#10'"1 '#9'c #977740",'#13#10'"2 '#9'c #7C6038",'#13#10'"3 '#9'c #9C7749",' - +#13#10'"4 '#9'c #866340",'#13#10'"5 '#9'c #BA8D59",'#13#10'"6 '#9'c #634430"' - +','#13#10'"7 '#9'c #8A6542",'#13#10'"8 '#9'c #C99761",'#13#10'"9 '#9'c #CC9B' - +'62",'#13#10'"0 '#9'c #6C5842",'#13#10'"a '#9'c #82705A",'#13#10'"b '#9'c #A' - +'47C4F",'#13#10'"c '#9'c #614A2F",'#13#10'"d '#9'c #906C45",'#13#10'"e '#9'c' - +' #7C513C",'#13#10'"f '#9'c #AD7F54",'#13#10'"g '#9'c #B78858",'#13#10'"h '#9 - +'c #A4825B",'#13#10'"i '#9'c #8D7A65",'#13#10'"j '#9'c #927D67",'#13#10'"k ' - +#9'c #93705B",'#13#10'"l '#9'c #3F3636",'#13#10'"m '#9'c #D3D3D3",'#13#10'"n' - +' '#9'c #CE9E60",'#13#10'"o '#9'c #755738",'#13#10'"p '#9'c #A77951",'#13#10 - +'"q '#9'c #CE9C63",'#13#10'"r '#9'c #3B271D",'#13#10'"s '#9'c #825F4B",'#13 - +#10'"t '#9'c #D6D5D3",'#13#10'"u '#9'c #EEEAE0",'#13#10'"v '#9'c #AB7A53",' - +#13#10'"w '#9'c #745438",'#13#10'"x '#9'c #A77B50",'#13#10'"y '#9'c #948B83"' - +','#13#10'"z '#9'c #261313",'#13#10'"A '#9'c #8B6843",'#13#10'"B '#9'c #6347' - +'30",'#13#10'"C '#9'c #4B3924",'#13#10'"D '#9'c #B58757",'#13#10'"E '#9'c #8' - +'16347",'#13#10'"F '#9'c #ECEAE0",'#13#10'"G '#9'c #735438",'#13#10'"H '#9'c' - +' #A2774E",'#13#10'"I '#9'c #C0915C",'#13#10'"J '#9'c #A37B4E",'#13#10'"K '#9 - +'c #6D5134",'#13#10'"L '#9'c #7C593C",'#13#10'"M '#9'c #917C63",'#13#10'"N ' - +#9'c #99938C",'#13#10'"O '#9'c #B5B1AC",'#13#10'"P '#9'c #E8E8E8",'#13#10'"Q' - +' '#9'c #866B4D",'#13#10'"R '#9'c #8C6D49",'#13#10'"S '#9'c #684F32",'#13#10 - +'"T '#9'c #1D130E",'#13#10'"U '#9'c #B58657",'#13#10'"V '#9'c #8E6C44",'#13 - +#10'"W '#9'c #A67E50",'#13#10'"X '#9'c #81623E",'#13#10'"Y '#9'c #6D5234",' - +#13#10'"Z '#9'c #5F4D37",'#13#10'"` '#9'c #978E85",'#13#10'" .'#9'c #ECEAE2"' - +','#13#10'"..'#9'c #CAC7C4",'#13#10'"+.'#9'c #8F7658",'#13#10'"@.'#9'c #4A31' - +'24",'#13#10'"#.'#9'c #B98859",'#13#10'"$.'#9'c #885842",'#13#10'"%.'#9'c #4' - +'63222",'#13#10'"&.'#9'c #CB9A62",'#13#10'"*.'#9'c #3D231E",'#13#10'"=.'#9'c' - +' #39271C",'#13#10'"-.'#9'c #876E51",'#13#10'";.'#9'c #938778",'#13#10'">.'#9 - +'c #D7D5D3",'#13#10'",.'#9'c #DFDFDF",'#13#10'"''.'#9'c #9E9891",'#13#10'").' - ,#9'c #908C87",'#13#10'"!.'#9'c #918A88",'#13#10'"~.'#9'c #8F8B87",'#13#10'"{' - +'.'#9'c #989188",'#13#10'"].'#9'c #BEBAB5",'#13#10'". . . . . . . . . . . . ' - +'. . . . . ",'#13#10'". . . . . . . . . . . . . . . . . ",'#13#10'". . . . .' - +' + @ # $ % . . . . . . . ",'#13#10'". . & * = - ; > , '' ) . . . . . . ",' - +#13#10'"! ~ { ] ^ / ( _ : < [ } . . . . . ",'#13#10'"| 1 2 3 4 5 6 7 8 9 0 a' - +' . . . . . ",'#13#10'"b c d e f g h i j k l m . . . . . ",'#13#10'"n o p q ' - +'r s t . . . u . . . . . . ",'#13#10'", q v w x y . . . . . . . . . . . ",' - +#13#10'"z A B C D E F . . . . . . . . . . ",'#13#10'"G H I J K L M N N O P .' - +' . . . . . ",'#13#10'"Q R S T U V W X X Y Z ` .. . . . ",'#13#10'". ..+.@.' - +'#.$.%.9 q &.*.=.X -.;.>.. ",'#13#10'". . . ,.''.N ).N N N !.~.{.-.-.].. ",' - +#13#10'". . . . . . . . . . . . . . . . . "};'#13#10#9'NumGlyphs'#2#0#7'OnCl' - +'ick'#7#17'FormatButtonClick'#0#0#12'TSpeedButton'#18'InsertRemarkButton'#3 - +'Tag'#2#4#6'Height'#2#17#3'Top'#2'D'#5'Width'#2#17#5'Align'#7#5'alTop'#5'Col' - +'or'#7#9'clBtnFace'#10'Glyph.Data'#10#218#1#0#0#214#1#0#0'/* XPM */'#13#10's' - +'tatic char * InsertRemark_xpm[] = {'#13#10'"17 17 2 1",'#13#10'" '#9'c #ECE' - +'9D8",'#13#10'".'#9'c #0000FF",'#13#10'" ",'#13#10'" ' - +' ",'#13#10'" ",'#13#10'" ... ... ",'#13#10 - +'" .. .. ",'#13#10'" .. .. ",'#13#10'" .. .. "' - +','#13#10'" .. .. ",'#13#10'" ... ... ",'#13#10'" .. ' - +' .. ",'#13#10'" .. .. ",'#13#10'" .. .. ",'#13#10'"' - +' .. .. ",'#13#10'" ... ... ",'#13#10'" ",' - +#13#10'" ",'#13#10'" "};'#13#10#9'NumGlyphs' - +#2#0#7'OnClick'#7#17'FormatButtonClick'#0#0#12'TSpeedButton'#18'InsertVarTag' - +'Button'#3'Tag'#2#5#6'Height'#2#17#3'Top'#2'U'#5'Width'#2#17#5'Align'#7#5'al' - +'Top'#5'Color'#7#9'clBtnFace'#10'Glyph.Data'#10#219#2#0#0#215#2#0#0'/* XPM *' - +'/'#13#10'static char * InsertVarTag_xpm[] = {'#13#10'"17 17 18 1",'#13#10'"' - +' '#9'c #ECE9D8",'#13#10'".'#9'c #D4D4D4",'#13#10'"+'#9'c #AAAAAA",'#13#10'"' - +'@'#9'c #E6E6E6",'#13#10'"#'#9'c #000000",'#13#10'"$'#9'c #CCCCCC",'#13#10'"' - +'%'#9'c #C4C4C4",'#13#10'"&'#9'c #888888",'#13#10'"*'#9'c #444444",'#13#10'"' - +'='#9'c #999999",'#13#10'"-'#9'c #666666",'#13#10'";'#9'c #222222",'#13#10'"' - +'>'#9'c #BBBBBB",'#13#10'",'#9'c #5E5E5E",'#13#10'"'''#9'c #808080",'#13#10 - +'")'#9'c #FFFFFF",'#13#10'"!'#9'c #777777",'#13#10'"~'#9'c #4C4C4C",'#13#10 - +'" ",'#13#10'" ",'#13#10'" "' - +','#13#10'" ",'#13#10'" ",'#13#10'" ' - +' ",'#13#10'" .+++..++ .+++ ",'#13#10'" @#$#@%&*=@-;&> ",'#13#10'"' - +' ,*, ;>,'')'''' ",'#13#10'" .;. -!~~>~~> ",'#13#10'" ' - +' ",'#13#10'" ",'#13#10'" ",'#13#10'" ' - +' ",'#13#10'" ",'#13#10'" ",'#13#10 - +'" "};'#13#10#9'NumGlyphs'#2#0#7'OnClick'#7#17'FormatButtonC' - +'lick'#0#0#0#11'TOpenDialog'#10'OpenDialog'#5'Title'#6#17'Open example file' - +#6'Filter'#6#28'pascal file|*.pas; *.pp; *.p'#11'FilterIndex'#2#0#4'left'#2 - +'@'#3'top'#2#24#0#0#0 + +#17'FormatButtonClick'#0#0#12'TSpeedButton'#18'ItalicFormatButton'#3'Tag'#2#1 + +#6'Height'#2#17#3'Top'#2#17#5'Width'#2#17#5'Align'#7#5'alTop'#5'Color'#7#9'c' + +'lBtnFace'#10'Glyph.Data'#10#197#1#0#0#193#1#0#0'/* XPM */'#10'static char *' + +'graphic[] = {'#10'"17 17 3 1",'#10'". c None",'#10'", c #000000",'#10'"- c ' + +'#9696AF",'#10'".................",'#10'".................",'#10'"..........' + +'.......",'#10'"........,,,,,....",'#10'".........,,-.....",'#10'"........-,' + +',......",'#10'"........,,-......",'#10'".......-,,.......",'#10'".......,,-' + +'.......",'#10'"......-,,........",'#10'"......,,-........",'#10'"....,,,,,,' + +'.......",'#10'".................",'#10'".................",'#10'"..........' + +'.......",'#10'".................",'#10'"................."}'#10#9'NumGlyphs' + +#2#0#7'OnClick'#7#17'FormatButtonClick'#0#0#12'TSpeedButton'#21'UnderlineFor' + +'matButton'#3'Tag'#2#2#6'Height'#2#17#3'Top'#2'"'#5'Width'#2#17#5'Align'#7#5 + +'alTop'#5'Color'#7#9'clBtnFace'#10'Glyph.Data'#10#197#1#0#0#193#1#0#0'/* XPM' + +' */'#10'static char *graphic[] = {'#10'"17 17 3 1",'#10'". c None",'#10'", ' + +'c #000000",'#10'"- c #848484",'#10'".................",'#10'"..............' + +'...",'#10'".................",'#10'"....,,,,.,,,,....",'#10'".....,,...,,..' + +'...",'#10'".....,,...,,.....",'#10'".....,,...,,.....",'#10'".....,,...,,..' + +'...",'#10'".....,,...,,.....",'#10'".....,,...,,.....",'#10'".....,,-.-,,..' + +'...",'#10'"......,,,,,......",'#10'".................",'#10'"....,,,,,,,,,.' + +'...",'#10'".................",'#10'".................",'#10'"..............' + +'..."}'#10#9'NumGlyphs'#2#0#7'OnClick'#7#17'FormatButtonClick'#0#0#12'TSpeed' + +'Button'#19'InsertCodeTagButton'#3'Tag'#2#3#6'Height'#2#17#3'Top'#2'3'#5'Wid' + +'th'#2#17#5'Align'#7#5'alTop'#5'Color'#7#9'clBtnFace'#10'Glyph.Data'#10#253#9 + +#0#0#249#9#0#0'/* XPM */'#13#10'static char * InsertCodeTag_xpm[] = {'#13#10 + +'"17 15 112 2",'#13#10'" '#9'c None",'#13#10'". '#9'c #ECE9D8",'#13#10'"+ ' + +#9'c #FFF0CF",'#13#10'"@ '#9'c #FFEDC5",'#13#10'"# '#9'c #FBE8C5",'#13#10'"$' + +' '#9'c #EDDAC5",'#13#10'"% '#9'c #F4E8DB",'#13#10'"& '#9'c #FAEDD5",'#13#10 + +'"* '#9'c #F3D49E",'#13#10'"= '#9'c #BF9855",'#13#10'"- '#9'c #C89D55",'#13 + +#10'"; '#9'c #BC8E5A",'#13#10'"> '#9'c #7C6135",'#13#10'", '#9'c #B18655",' + +#13#10'"'' '#9'c #916940",'#13#10'") '#9'c #C3AC93",'#13#10'"! '#9'c #CCA76A' + +'",'#13#10'"~ '#9'c #80684A",'#13#10'"{ '#9'c #DCAA63",'#13#10'"] '#9'c #A88' + +'34A",'#13#10'"^ '#9'c #977443",'#13#10'"/ '#9'c #B99052",'#13#10'"( '#9'c #' + +'947047",'#13#10'"_ '#9'c #896842",'#13#10'": '#9'c #C4955E",'#13#10'"< '#9 + +'c #87653F",'#13#10'"[ '#9'c #A37A4E",'#13#10'"} '#9'c #F0E1CF",'#13#10'"| ' + +#9'c #BD964F",'#13#10'"1 '#9'c #977740",'#13#10'"2 '#9'c #7C6038",'#13#10'"3' + +' '#9'c #9C7749",'#13#10'"4 '#9'c #866340",'#13#10'"5 '#9'c #BA8D59",'#13#10 + +'"6 '#9'c #634430",'#13#10'"7 '#9'c #8A6542",'#13#10'"8 '#9'c #C99761",'#13 + +#10'"9 '#9'c #CC9B62",'#13#10'"0 '#9'c #6C5842",'#13#10'"a '#9'c #82705A",' + +#13#10'"b '#9'c #A47C4F",'#13#10'"c '#9'c #614A2F",'#13#10'"d '#9'c #906C45"' + +','#13#10'"e '#9'c #7C513C",'#13#10'"f '#9'c #AD7F54",'#13#10'"g '#9'c #B788' + +'58",'#13#10'"h '#9'c #A4825B",'#13#10'"i '#9'c #8D7A65",'#13#10'"j '#9'c #9' + +'27D67",'#13#10'"k '#9'c #93705B",'#13#10'"l '#9'c #3F3636",'#13#10'"m '#9'c' + +' #D3D3D3",'#13#10'"n '#9'c #CE9E60",'#13#10'"o '#9'c #755738",'#13#10'"p '#9 + +'c #A77951",'#13#10'"q '#9'c #CE9C63",'#13#10'"r '#9'c #3B271D",'#13#10'"s ' + +#9'c #825F4B",'#13#10'"t '#9'c #D6D5D3",'#13#10'"u '#9'c #EEEAE0",'#13#10'"v' + +' '#9'c #AB7A53",'#13#10'"w '#9'c #745438",'#13#10'"x '#9'c #A77B50",'#13#10 + +'"y '#9'c #948B83",'#13#10'"z '#9'c #261313",'#13#10'"A '#9'c #8B6843",'#13 + +#10'"B '#9'c #634730",'#13#10'"C '#9'c #4B3924",'#13#10'"D '#9'c #B58757",' + +#13#10'"E '#9'c #816347",'#13#10'"F '#9'c #ECEAE0",'#13#10'"G '#9'c #735438"' + +','#13#10'"H '#9'c #A2774E",'#13#10'"I '#9'c #C0915C",'#13#10'"J '#9'c #A37B' + +'4E",'#13#10'"K '#9'c #6D5134",'#13#10'"L '#9'c #7C593C",'#13#10'"M '#9'c #9' + +'17C63",'#13#10'"N '#9'c #99938C",'#13#10'"O '#9'c #B5B1AC",'#13#10'"P '#9'c' + ,' #E8E8E8",'#13#10'"Q '#9'c #866B4D",'#13#10'"R '#9'c #8C6D49",'#13#10'"S '#9 + +'c #684F32",'#13#10'"T '#9'c #1D130E",'#13#10'"U '#9'c #B58657",'#13#10'"V ' + +#9'c #8E6C44",'#13#10'"W '#9'c #A67E50",'#13#10'"X '#9'c #81623E",'#13#10'"Y' + +' '#9'c #6D5234",'#13#10'"Z '#9'c #5F4D37",'#13#10'"` '#9'c #978E85",'#13#10 + +'" .'#9'c #ECEAE2",'#13#10'"..'#9'c #CAC7C4",'#13#10'"+.'#9'c #8F7658",'#13 + +#10'"@.'#9'c #4A3124",'#13#10'"#.'#9'c #B98859",'#13#10'"$.'#9'c #885842",' + +#13#10'"%.'#9'c #463222",'#13#10'"&.'#9'c #CB9A62",'#13#10'"*.'#9'c #3D231E"' + +','#13#10'"=.'#9'c #39271C",'#13#10'"-.'#9'c #876E51",'#13#10'";.'#9'c #9387' + +'78",'#13#10'">.'#9'c #D7D5D3",'#13#10'",.'#9'c #DFDFDF",'#13#10'"''.'#9'c #' + +'9E9891",'#13#10'").'#9'c #908C87",'#13#10'"!.'#9'c #918A88",'#13#10'"~.'#9 + +'c #8F8B87",'#13#10'"{.'#9'c #989188",'#13#10'"].'#9'c #BEBAB5",'#13#10'". .' + +' . . . . . . . . . . . . . . . ",'#13#10'". . . . . . . . . . . . . . . . .' + +' ",'#13#10'". . . . . + @ # $ % . . . . . . . ",'#13#10'". . & * = - ; > , ' + +''' ) . . . . . . ",'#13#10'"! ~ { ] ^ / ( _ : < [ } . . . . . ",'#13#10'"| ' + +'1 2 3 4 5 6 7 8 9 0 a . . . . . ",'#13#10'"b c d e f g h i j k l m . . . . ' + +'. ",'#13#10'"n o p q r s t . . . u . . . . . . ",'#13#10'", q v w x y . . .' + +' . . . . . . . . ",'#13#10'"z A B C D E F . . . . . . . . . . ",'#13#10'"G ' + +'H I J K L M N N O P . . . . . . ",'#13#10'"Q R S T U V W X X Y Z ` .. . . ' + +'. ",'#13#10'". ..+.@.#.$.%.9 q &.*.=.X -.;.>.. ",'#13#10'". . . ,.''.N ).N ' + +'N N !.~.{.-.-.].. ",'#13#10'". . . . . . . . . . . . . . . . . "};'#13#10#9 + +'NumGlyphs'#2#0#7'OnClick'#7#17'FormatButtonClick'#0#0#12'TSpeedButton'#18'I' + +'nsertRemarkButton'#3'Tag'#2#4#6'Height'#2#17#3'Top'#2'D'#5'Width'#2#17#5'Al' + +'ign'#7#5'alTop'#5'Color'#7#9'clBtnFace'#10'Glyph.Data'#10#218#1#0#0#214#1#0 + +#0'/* XPM */'#13#10'static char * InsertRemark_xpm[] = {'#13#10'"17 17 2 1",' + +#13#10'" '#9'c #ECE9D8",'#13#10'".'#9'c #0000FF",'#13#10'" "' + +','#13#10'" ",'#13#10'" ",'#13#10'" ... ' + +' ... ",'#13#10'" .. .. ",'#13#10'" .. .. ",'#13#10'"' + +' .. .. ",'#13#10'" .. .. ",'#13#10'" ... ... ",' + +#13#10'" .. .. ",'#13#10'" .. .. ",'#13#10'" .. ' + +'.. ",'#13#10'" .. .. ",'#13#10'" ... ... ",'#13#10'" ' + +' ",'#13#10'" ",'#13#10'" "};' + +#13#10#9'NumGlyphs'#2#0#7'OnClick'#7#17'FormatButtonClick'#0#0#12'TSpeedButt' + +'on'#18'InsertVarTagButton'#3'Tag'#2#5#6'Height'#2#17#3'Top'#2'U'#5'Width'#2 + +#17#5'Align'#7#5'alTop'#5'Color'#7#9'clBtnFace'#10'Glyph.Data'#10#219#2#0#0 + +#215#2#0#0'/* XPM */'#13#10'static char * InsertVarTag_xpm[] = {'#13#10'"17 ' + +'17 18 1",'#13#10'" '#9'c #ECE9D8",'#13#10'".'#9'c #D4D4D4",'#13#10'"+'#9'c ' + +'#AAAAAA",'#13#10'"@'#9'c #E6E6E6",'#13#10'"#'#9'c #000000",'#13#10'"$'#9'c ' + +'#CCCCCC",'#13#10'"%'#9'c #C4C4C4",'#13#10'"&'#9'c #888888",'#13#10'"*'#9'c ' + +'#444444",'#13#10'"='#9'c #999999",'#13#10'"-'#9'c #666666",'#13#10'";'#9'c ' + +'#222222",'#13#10'">'#9'c #BBBBBB",'#13#10'",'#9'c #5E5E5E",'#13#10'"'''#9'c' + +' #808080",'#13#10'")'#9'c #FFFFFF",'#13#10'"!'#9'c #777777",'#13#10'"~'#9'c' + +' #4C4C4C",'#13#10'" ",'#13#10'" ",'#13#10'"' + +' ",'#13#10'" ",'#13#10'" ",' + +#13#10'" ",'#13#10'" .+++..++ .+++ ",'#13#10'" @#$#@%&*=@-' + +';&> ",'#13#10'" ,*, ;>,'')'''' ",'#13#10'" .;. -!~~>~~> ",'#13#10'"' + +' ",'#13#10'" ",'#13#10'" ",' + +#13#10'" ",'#13#10'" ",'#13#10'" ' + +' ",'#13#10'" "};'#13#10#9'NumGlyphs'#2#0#7'OnClick'#7#17 + +'FormatButtonClick'#0#0#0#11'TOpenDialog'#10'OpenDialog'#5'Title'#6#17'Open ' + +'example file'#6'Filter'#6#28'pascal file|*.pas; *.pp; *.p'#11'FilterIndex'#2 + +#0#4'left'#2'@'#3'top'#2#24#0#0#0 ]); diff --git a/ide/lazdocfrm.pas b/ide/lazdocfrm.pas index 1a1293fdcb..d5bf8fb105 100644 --- a/ide/lazdocfrm.pas +++ b/ide/lazdocfrm.pas @@ -23,9 +23,8 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * *************************************************************************** -} -{ + see for todo list: http://wiki.lazarus.freepascal.org/index.php/LazDoc } @@ -42,27 +41,55 @@ uses LCLProc, LResources, StdCtrls, Buttons, ComCtrls, Controls, Dialogs, ExtCtrls, Forms, Graphics, SynEdit, - CodeToolManager, CodeCache, + CodeAtom, CodeCache, CodeToolManager, Laz_DOM, Laz_XMLRead, Laz_XMLWrite, IDEHelpIntf, LazHelpIntf, - IDEProcs, LazarusIDEStrConsts, LazDoc; - -const - SHORT = 1; - DESCR = 2; - ERRORS = 4; - SEEALSO = 5; - EXAMPLE = 6; - NODEITEMS = EXAMPLE; //always make nodeitems equal to higest element + IDEProcs, LazarusIDEStrConsts, LazDocSelectInherited, LazDoc; type - TFPDocNode = array [1..NODEITEMS] of String; + TFPDocItem = ( + fpdiShort, + fpdiDescription, + fpdiErrors, + fpdiSeeAlso, + fpdiExample + ); + + TFPDocNode = array [TFPDocItem] of String; + TLazDocFormFlag = ( + ldffCaptionNeedsUpdate, + ldffInheritedNeedsUpdate, + ldffInheritedEntriesNeedUpdate + ); + TLazDocFormFlags = set of TLazDocFormFlag; + + { TLazDocInheritedEntry } + + TLazDocInheritedEntry = class + public + SrcFilename: string; + Caret: TPoint; + DocFilename: string; + DocFilenameValid: Boolean; + DocFile: TLazFPDocFile; + DocFileValid: Boolean; + PascalContext: TPascalHelpContextList; + PascalContextValid: Boolean; + DOMNodeValid: Boolean; + DOMNode: TDOMNode; + ValuesValid: Boolean; + Values: TFPDocNode; + destructor Destroy; override; + end; + { TLazDocForm } TLazDocForm = class(TForm) AddLinkButton: TButton; BrowseExampleButton: TButton; + CopyFromInheritedButton: TButton; + MoveToInheritedButton: TButton; InheritedShortEdit: TEdit; ExampleEdit: TEdit; InheritedShortLabel: TLabel; @@ -90,6 +117,7 @@ type SeeAlsoTabSheet: TTabSheet; procedure AddLinkButtonClick(Sender: TObject); procedure BrowseExampleButtonClick(Sender: TObject); + procedure CopyFromInheritedButtonClick(Sender: TObject); procedure DeleteLinkButtonClick(Sender: TObject); procedure DocumentationTagChange(Sender: TObject); procedure FormCreate(Sender: TObject); @@ -98,37 +126,56 @@ type procedure FormatButtonClick(Sender: TObject); procedure LinkChange(Sender: TObject); procedure LinkListBoxClick(Sender: TObject); + procedure ApplicationIdle(Sender: TObject); + procedure MoveToInheritedButtonClick(Sender: TObject); private + FCaretXY: TPoint; FChanged: Boolean; - FCurrentElement: TPascalHelpContextList; - FDoc: TXMLdocument; - FDocFileName: String; FLazDocBoss: TLazDocManager; - FLinkIndex: Integer; - function ElementFromNode(Node: TDOMNode): TFPDocNode; + FFlags: TLazDocFormFlags; + fUpdateLock: Integer; + fEntry: TLazDocInheritedEntry; + fInheritedEntries: TFPList; // list of TLazDocInheritedEntry. Entry 0 is current. + function GetValuesFromNode(Node: TDOMNode): TFPDocNode; + function GetDoc: TXMLdocument; + function GetDocFile: TLazFPDocFile; function GetFirstChildValue(n: TDOMNode): String; - function GetFirstElement: TDOMNode; - function GetModuleNode: TDOMNode; - function GetNearestSourceElement(const SrcFilename: string; + function GetFirstElement(ADoc: TXMLdocument): TDOMNode; + function GetModuleNode(ADoc: TXMLdocument): TDOMNode; + function GetSourceContext(const SrcFilename: string; const CaretPos: TPoint): TPascalHelpContextList; + function GetSourceFilename: string; function MakeLink: String; - function NodeByPascalContext(const AContext: TPascalHelpContextList): TDOMNode; - function GetElementName(const AContext: TPascalHelpContextList): string; - procedure GetElementList; - procedure InsertElement(const ElementName: String); + function NodeByPascalContext(ADoc: TXMLdocument; + const AContext: TPascalHelpContextList): TDOMNode; + function GetContextTitle(const AContext: TPascalHelpContextList): string; + procedure UpdateLinkIdComboBox; procedure Save; - procedure SetDocFileName(const Value: String); + function WriteNode(Entry: TLazDocInheritedEntry; DocNode: TFPDocNode; + Interactive: Boolean): Boolean; procedure UpdateCaption; + procedure UpdateValueControls; + procedure UpdateInheritedControls; + procedure UpdateInherited; + procedure UpdateInheritedEntries(All: Boolean); + procedure ClearInherited(UpdateControls: Boolean); + function FindInheritedEntry: TLazDocInheritedEntry; + procedure MoveToInherited(DestEntry: TLazDocInheritedEntry); public procedure Reset; procedure UpdateLazDoc(const SrcFilename: string; const Caret: TPoint); - property DocFileName: String read FDocFileName write SetDocFileName; - property Doc: TXMLdocument read FDoc; + procedure BeginUpdate; + procedure EndUpdate; + procedure ClearEntry(DoSave: Boolean); + property DocFile: TLazFPDocFile read GetDocFile; + property Doc: TXMLdocument read GetDoc; property LazDocBoss: TLazDocManager read FLazDocBoss; + property SourceFilename: string read GetSourceFilename; + property CaretXY: TPoint read FCaretXY; end; var - LazDocForm: TLazDocForm; + LazDocForm: TLazDocForm = nil; procedure DoShowLazDoc; @@ -144,22 +191,22 @@ begin LazDocForm.Show; end; -function TLazDocForm.GetModuleNode: TDOMNode; +function TLazDocForm.GetModuleNode(ADoc: TXMLdocument): TDOMNode; var n: TDOMNode; begin Result:=nil; - if doc=nil then exit; + if ADoc=nil then exit; - //get first node - n := doc.FindNode('fpdoc-descriptions'); + // get first node + n := ADoc.FindNode('fpdoc-descriptions'); if n=nil then exit; - //proceed to package (could there be more packages in one file??) + // proceed to package (could there be more packages in one file??) n := n.FirstChild; if n=nil then exit; - //proceed to module (could there be more modules in one file??) + // proceed to module (could there be more modules in one file??) n := n.FirstChild; while (n<>nil) and (n.NodeName <> 'module') do n := n.NextSibling; @@ -167,12 +214,12 @@ begin Result := n; end; -function TLazDocForm.GetFirstElement: TDOMNode; +function TLazDocForm.GetFirstElement(ADoc: TXMLdocument): TDOMNode; var Node: TDOMNode; begin //get first module node - Node := GetModuleNode; + Node := GetModuleNode(ADoc); //proceed to element Node := Node.FirstChild; @@ -182,7 +229,7 @@ begin Result := Node; end; -procedure TLazDocForm.GetElementList; +procedure TLazDocForm.UpdateLinkIdComboBox; // fills LinkIdComboBox.Items var n: TDOMNode; @@ -199,7 +246,7 @@ begin end; //get first element node - n := GetFirstElement; + n := GetFirstElement(Doc); //search all elements while Assigned(n) do @@ -217,40 +264,13 @@ begin end; end; -procedure TLazDocForm.SetDocFileName(const Value: String); -begin - LinkIdComboBox.Clear; - - if (Value <> FDocFileName) then begin - // reset Self - Reset; - - FDocFileName := Value; - - if Assigned(doc) then - FreeAndNil(doc); - - if FileExistsCached(Value) then begin - ReadXMLFile(doc, FDocFileName); - end; - - UpdateCaption; - - GetElementList; - - {$ifdef dbgLazDoc} - DebugLn('TLazDocForm.SetDocFileName: document is set: ' + Value); - {$endif} - end; -end; - procedure TLazDocForm.FormCreate(Sender: TObject); begin FLazDocBoss:=TLazDocManager.Create; + fEntry:=TLazDocInheritedEntry.Create; + Caption := lisLazDocMainFormCaption; - FLinkIndex := -1; - with PageControl do begin Page[0].Caption := lisLazDocShortTag; @@ -273,14 +293,19 @@ begin DeleteLinkButton.Caption := lisLazDocDeleteLinkButton; BrowseExampleButton.Caption := lisLazDocBrowseExampleButton; - + + MoveToInheritedButton.Caption:='Move entries to inherited'; + Reset; + + Application.AddOnIdleHandler(@ApplicationIdle); end; procedure TLazDocForm.FormDestroy(Sender: TObject); begin - FreeAndNil(fDoc); - FreeAndNil(FCurrentElement); + ClearInherited(false); + Application.RemoveAllHandlersOfObject(Self); + FreeAndNil(fEntry); FreeAndNil(FLazDocBoss); end; @@ -324,10 +349,10 @@ end; procedure TLazDocForm.LinkChange(Sender: TObject); begin - if FLinkIndex = -1 then + if LinkListBox.ItemIndex<0 then Exit; - LinkListBox.Items.Strings[FLinkIndex] := MakeLink; + LinkListBox.Items.Strings[LinkListBox.ItemIndex] := MakeLink; end; procedure TLazDocForm.LinkListBoxClick(Sender: TObject); @@ -335,22 +360,22 @@ var strTmp: String; intTmp: Integer; intStart: Integer; + LinkIndex: LongInt; begin //split the link into Id and Text - FLinkIndex := LinkListBox.ItemIndex; - - if FLinkIndex = -1 then + LinkIndex := LinkListBox.ItemIndex; + if LinkIndex = -1 then Exit; - intStart := PosEx('"', LinkListBox.Items[FLinkIndex], 1); + intStart := PosEx('"', LinkListBox.Items[LinkIndex], 1); - intTmp := PosEx('"', LinkListBox.Items[FLinkIndex], intStart + 1); + intTmp := PosEx('"', LinkListBox.Items[LinkIndex], intStart + 1); - LinkIdComboBox.Text := Copy(LinkListBox.Items[FLinkIndex], + LinkIdComboBox.Text := Copy(LinkListBox.Items[LinkIndex], intStart + 1, intTmp - intStart - 1); - strTmp := Copy(LinkListBox.Items[FLinkIndex], intTmp + 2, - Length(LinkListBox.Items[FLinkIndex])); + strTmp := Copy(LinkListBox.Items[LinkIndex], intTmp + 2, + Length(LinkListBox.Items[LinkIndex])); if strTmp = '>' then LinkTextEdit.Text := '' @@ -358,66 +383,89 @@ begin LinkTextEdit.Text := Copy(strTmp, 1, Length(strTmp) - Length('')); end; -procedure TLazDocForm.InsertElement(const ElementName: String); -var - n: TDOMNode; - child: TDOMNode; +procedure TLazDocForm.ApplicationIdle(Sender: TObject); begin - if doc=nil then exit; - - // UNUSED. Do we still need this? - Exit; - - // preparations being made for adding nodes - // having to finalize adding comment - - // get first module node - n := GetModuleNode; - if n=nil then exit; - - // TODO: insert element comment (important or not!!) - child := doc.CreateComment('test'); - n.AppendChild(child); - - child := doc.CreateElement('element'); - TDOMElement(child).SetAttribute('name', ElementName); - child.AppendChild(doc.CreateElement('short')); - child.AppendChild(doc.CreateElement('descr')); - child.AppendChild(doc.CreateElement('errors')); - child.AppendChild(doc.CreateElement('seealso')); - child.AppendChild(doc.CreateElement('example')); - n.AppendChild(child); + if ldffInheritedNeedsUpdate in FFlags then + UpdateInherited + else if ldffInheritedEntriesNeedUpdate in FFlags then + UpdateInheritedEntries(false); +end; +procedure TLazDocForm.MoveToInheritedButtonClick(Sender: TObject); +var + i: Integer; + Entry: TLazDocInheritedEntry; + Candidates: TFPList; + LazDocSelectInheritedDlg: TLazDocSelectInheritedDlg; +begin + if fInheritedEntries=nil then exit; + Candidates:=nil; + LazDocSelectInheritedDlg:=nil; try - WriteXMLFile(doc, FDocFileName); - except - on E: Exception do begin - MessageDlg('Write error', - 'unable to write file '+FDocFileName+#13 - +E.Message, - mtError,[mbCancel],0); + // find all entries till the first inherited entry with a description + for i:=1 to fInheritedEntries.Count-1 do begin + Entry:=TLazDocInheritedEntry(fInheritedEntries[i]); + if Entry.ValuesValid then begin + if Candidates=nil then + Candidates:=TFPList.Create; + Candidates.Add(Entry); + if Entry.Values[fpdiShort]<>'' then break; + end; end; + + // choose one entry + if (Candidates=nil) or (Candidates.Count=0) then exit; + if Candidates.Count=1 then begin + // there is only one candidate + Entry:=TLazDocInheritedEntry(Candidates[0]); + if Entry.Values[fpdiShort]<>'' then begin + // the inherited entry already contains a description. + // ask if it should be really replacement + if QuestionDlg('Confirm replace', + GetContextTitle(Entry.PascalContext)+' already contains the help:'+#13 + +Entry.Values[fpdiShort], + mtConfirmation,[mrYes,'Replace',mrCancel],0)<>mrYes then exit; + end; + end else begin + // there is more than one candidate + // => ask which one to replace + LazDocSelectInheritedDlg:=TLazDocSelectInheritedDlg.Create(nil); + LazDocSelectInheritedDlg.InheritedComboBox.Items.Clear; + for i:=0 to Candidates.Count-1 do begin + Entry:=TLazDocInheritedEntry(Candidates[i]); + LazDocSelectInheritedDlg.InheritedComboBox.Items.Add( + GetContextTitle(Entry.PascalContext)); + end; + if LazDocSelectInheritedDlg.ShowModal<>mrOk then exit; + i:=LazDocSelectInheritedDlg.InheritedComboBox.ItemIndex; + if i<0 then exit; + Entry:=TLazDocInheritedEntry(Candidates[i]); + end; + + // move the content of the current entry to the inherited entry + MoveToInherited(Entry); + finally + LazDocSelectInheritedDlg.Free; + Candidates.Free; end; end; -function TLazDocForm.NodeByPascalContext( +function TLazDocForm.NodeByPascalContext(ADoc: TXMLdocument; const AContext: TPascalHelpContextList): TDOMNode; var Node: TDOMNode; ElementName: String; begin Result := Nil; - - if not Assigned(doc) then Exit; + if not Assigned(ADoc) then Exit; // get first element node - ElementName:=GetElementName(AContext); - + ElementName:=GetContextTitle(AContext); if ElementName='' then exit; //DebugLn('TLazDocForm.NodeByPascalContext ElementName="',ElementName,'"'); // search elements for ElementName - Node:=GetFirstElement; + Node:=GetFirstElement(ADoc); while Node<>nil do begin if (Node is TDomElement) and (CompareText(TDomElement(Node).GetAttribute('name'),ElementName)=0) then @@ -440,14 +488,15 @@ begin Result := Node; end; -function TLazDocForm.GetElementName(const AContext: TPascalHelpContextList +function TLazDocForm.GetContextTitle(const AContext: TPascalHelpContextList ): string; -// get codetools path. for example: TButton.Align +// get codetools path. for fpdiExample: TButton.Align var Level: Integer; begin - Level:=0; Result:=''; + if AContext=nil then exit; + Level:=0; while (Levelnil then + Result:=DocFile.Doc + else + Result:=nil; +end; + +function TLazDocForm.GetDocFile: TLazFPDocFile; +begin + Result:=fEntry.DocFile; +end; + +function TLazDocForm.GetSourceContext(const SrcFilename: string; const CaretPos: TPoint): TPascalHelpContextList; begin Result:=LazarusHelp.ConvertSourcePosToPascalHelpContext(CaretPos,SrcFilename); - //if Result<>nil then // DebugLn('TLazDocForm.GetNearestSourceElement Result=',Result.AsString); end; +function TLazDocForm.GetSourceFilename: string; +begin + Result:=fEntry.SrcFilename; +end; + procedure TLazDocForm.UpdateCaption; var strCaption: String; begin + if fUpdateLock>0 then begin + Include(FFlags,ldffCaptionNeedsUpdate); + exit; + end; + Exclude(FFlags,ldffCaptionNeedsUpdate); + strCaption := lisLazDocMainFormCaption + ' - '; - if FCurrentElement <> nil then - strCaption := strCaption + GetElementName(FCurrentElement) + ' - ' + if fEntry.PascalContext <> nil then + strCaption := strCaption + GetContextTitle(fEntry.PascalContext) + ' - ' else strCaption := strCaption + lisLazDocNoTagCaption + ' - '; - if FDocFileName <> '' then - Caption := strCaption + FDocFileName + if DocFile<>nil then + Caption := strCaption + DocFile.Filename else Caption := strCaption + lisLazDocNoTagCaption; + DebugLn(['TLazDocForm.UpdateCaption ',Caption]); +end; + +procedure TLazDocForm.UpdateValueControls; +var + EnabledState: Boolean; +begin + EnabledState := fEntry.DOMNode<>nil; + + if Assigned(fEntry.DOMNode) then + begin + ShortEdit.Text := fEntry.Values[fpdiShort]; + DescrMemo.Lines.Text := ConvertLineEndings(fEntry.Values[fpdiDescription]); + ErrorsMemo.Lines.Text := ConvertLineEndings(fEntry.Values[fpdiErrors]); + LinkListBox.Items.Text := ConvertLineEndings(fEntry.Values[fpdiSeeAlso]); + LinkIdComboBox.Text := ''; + LinkTextEdit.Clear; + ExampleEdit.Text := ConvertLineEndings(fEntry.Values[fpdiExample]); + end + else + begin + ShortEdit.Text := lisLazDocNoDocumentation; + DescrMemo.Lines.Text := lisLazDocNoDocumentation; + ErrorsMemo.Lines.Text := lisLazDocNoDocumentation; + LinkIdComboBox.Text := lisLazDocNoDocumentation; + LinkTextEdit.Text := lisLazDocNoDocumentation; + LinkListBox.Clear; + ExampleEdit.Text := lisLazDocNoDocumentation; + end; + + ShortEdit.Enabled := EnabledState; + DescrMemo.Enabled := EnabledState; + ErrorsMemo.Enabled := EnabledState; + LinkIdComboBox.Enabled := EnabledState; + LinkTextEdit.Enabled := EnabledState; + LinkListBox.Enabled := EnabledState; + AddLinkButton.Enabled := EnabledState; + DeleteLinkButton.Enabled := EnabledState; + ExampleEdit.Enabled := EnabledState; + BrowseExampleButton.Enabled := EnabledState; +end; + +procedure TLazDocForm.UpdateInheritedControls; +var + Entry: TLazDocInheritedEntry; +begin + Entry:=FindInheritedEntry; + DebugLn(['TLazDocForm.UpdateInheritedControls ',dbgsName(Entry)]); + if Entry=nil then begin + InheritedShortEdit.Text:=''; + InheritedShortEdit.Enabled:=false; + InheritedShortLabel.Caption:='no inherited description found'; + end else begin + InheritedShortEdit.Text:=Entry.Values[fpdiShort]; + InheritedShortEdit.Enabled:=true; + InheritedShortLabel.Caption:='Short description of ' + +GetContextTitle(Entry.PascalContext); + end; + MoveToInheritedButton.Enabled:=(fInheritedEntries<>nil) + and (fInheritedEntries.Count>1); +end; + +procedure TLazDocForm.UpdateInherited; +var + ListOfPCodeXYPosition: TFPList; + CurCodePos: PCodeXYPosition; + i: Integer; + CodeBuffer: TCodeBuffer; + NewInherited: TLazDocInheritedEntry; +begin + if fUpdateLock>0 then begin + Include(FFlags,ldffInheritedNeedsUpdate); + exit; + end; + Exclude(FFlags,ldffInheritedNeedsUpdate); + + ClearInherited(true); + DebugLn(['TLazDocForm.UpdateInherited ']); + if DocFile=nil then exit; + if DocFile.CodeBuffer=nil then exit; + CodeBuffer:=CodeToolBoss.LoadFile(SourceFilename,true,false); + if CodeBuffer=nil then exit; + + ListOfPCodeXYPosition:=nil; + try + // get all possible declarations of this identifier + if not CodeToolBoss.FindDeclarationAndOverload(CodeBuffer, + CaretXY.X,CaretXY.Y,ListOfPCodeXYPosition,[]) + then + exit; + debugln('TLazDocForm.UpdateInherited Success Overloads=',dbgs(ListOfPCodeXYPosition.Count)); + // convert the source positions in pascal help context list + if ListOfPCodeXYPosition=nil then exit; + for i:=0 to ListOfPCodeXYPosition.Count-1 do begin + CurCodePos:=PCodeXYPosition(ListOfPCodeXYPosition[i]); + debugln('TLazDocForm.UpdateInherited C ',CurCodePos^.Code.Filename,' X=',dbgs(CurCodePos^.X),' Y=',dbgs(CurCodePos^.Y)); + if fInheritedEntries=nil then + fInheritedEntries:=TFPList.Create; + NewInherited:=TLazDocInheritedEntry.Create; + NewInherited.SrcFilename:=CurCodePos^.Code.Filename; + NewInherited.Caret.X:=CurCodePos^.X; + NewInherited.Caret.Y:=CurCodePos^.Y; + fInheritedEntries.Add(NewInherited); + end; + finally + FreeListOfPCodeXYPosition(ListOfPCodeXYPosition); + end; + Include(FFlags,ldffInheritedEntriesNeedUpdate); +end; + +procedure TLazDocForm.UpdateInheritedEntries(All: Boolean); +var + i: Integer; + Entry: TLazDocInheritedEntry; + CurInheritedEntry: TLazDocInheritedEntry; +begin + if fUpdateLock>0 then begin + Include(FFlags,ldffInheritedEntriesNeedUpdate); + exit; + end; + + CurInheritedEntry:=FindInheritedEntry; + if (CurInheritedEntry=nil) and (fInheritedEntries<>nil) then begin + for i:=0 to fInheritedEntries.Count-1 do begin + Entry:=TLazDocInheritedEntry(fInheritedEntries[i]); + //DebugLn(['TLazDocForm.UpdateInheritedEntries ',Entry.SrcFilename,' ',dbgs(Entry.Caret)]); + // find fpdoc file + if not Entry.DocFilenameValid then begin + Entry.DocFilenameValid:=true; + Entry.DocFilename:= + LazDocBoss.GetFPDocFilenameForSource(Entry.SrcFilename,true); + //DebugLn(['TLazDocForm.UpdateInheritedEntries Source=',Entry.SrcFilename,' -> FPDoc=',Entry.DocFilename]); + if not All then exit; + end; + // read fpdoc file + if not Entry.DocFileValid then begin + Entry.DocFileValid:=true; + //DebugLn(['TLazDocForm.UpdateInheritedEntries Parsing ',Entry.DocFilename,' ...']); + if (Entry.DocFilename<>'') then begin + if not LazDocBoss.LoadFPDocFile(Entry.DocFilename,true,false, + Entry.DocFile) + then + Entry.DocFile:=nil; + if not All then exit; + end; + end; + // get codetools path + if not Entry.PascalContextValid then begin + Entry.PascalContextValid:=true; + Entry.PascalContext:=LazarusHelp.ConvertSourcePosToPascalHelpContext( + Entry.Caret,Entry.SrcFilename); + //DebugLn(['TLazDocForm.UpdateInheritedEntries Pascal=',Entry.PascalContext.AsString]); + if not All then exit; + end; + // get fpdoc values + if (not Entry.ValuesValid) + and Entry.PascalContextValid and (Entry.PascalContext<>nil) + and Entry.DocFileValid and (Entry.DocFile<>nil) + and (Entry.DocFile.Doc<>nil) then begin + //DebugLn(['TLazDocForm.UpdateInheritedEntries get fpdoc values ',Entry.PascalContext.AsString]); + Entry.DOMNode := NodeByPascalContext(Entry.DocFile.Doc,Entry.PascalContext); + Entry.DOMNodeValid:=true; + Entry.ValuesValid:=true; + if Entry.DOMNode<>nil then begin + Entry.Values := GetValuesFromNode(Entry.DOMNode); + if CurInheritedEntry=nil then begin + CurInheritedEntry:=FindInheritedEntry; + if CurInheritedEntry<>nil then + UpdateInheritedControls; + end; + end; + if not All then exit; + end; + end; + end; + Exclude(FFlags,ldffInheritedEntriesNeedUpdate); +end; + +procedure TLazDocForm.ClearInherited(UpdateControls: Boolean); +var + i: Integer; +begin + //DebugLn(['TLazDocForm.ClearInherited UpdateControls=',UpdateControls]); + if fInheritedEntries<>nil then begin + for i:=0 to fInheritedEntries.Count-1 do + TObject(fInheritedEntries[i]).Free; + FreeAndNil(fInheritedEntries); + end; + if UpdateControls then + UpdateInheritedControls; +end; + +function TLazDocForm.FindInheritedEntry: TLazDocInheritedEntry; +var + i: Integer; +begin + if fInheritedEntries=nil then + exit(nil); + for i:=1 to fInheritedEntries.Count-1 do begin + Result:=TLazDocInheritedEntry(fInheritedEntries[i]); + if Result.ValuesValid and (Result.Values[fpdiShort]<>'') then + exit; + end; + Result:=nil; +end; + +procedure TLazDocForm.MoveToInherited(DestEntry: TLazDocInheritedEntry); +begin + DebugLn(['TLazDocForm.MoveToInherited ',DestEntry.PascalContext.AsString]); + if not fEntry.ValuesValid then begin + DebugLn(['TLazDocForm.MoveToInherited not fEntry.NodeValid']); + exit; + end; + if DestEntry.PascalContext=nil then begin + DebugLn(['TLazDocForm.MoveToInherited DestEntry.PascalContext=nil']); + exit; + end; + if fEntry.PascalContext.IsEqual(DestEntry.PascalContext) then begin + DebugLn(['TLazDocForm.MoveToInherited fEntry=DestEntry']); + exit; + end; + DebugLn(['TLazDocForm.MoveToInherited Writing to inherited node ...']); + if WriteNode(DestEntry,fEntry.Values,true) then begin + DebugLn(['TLazDocForm.MoveToInherited clearing current node ...']); + ClearEntry(true); + UpdateInherited; + end; end; procedure TLazDocForm.Reset; begin - FreeAndNil(Doc); - FreeAndNil(FCurrentElement); - FDocFileName := ''; - UpdateCaption; + ClearInherited(true); + FreeAndNil(FEntry.PascalContext); + FEntry.DocFile:=nil; + FEntry.DocFileValid:=false; + FEntry.DOMNode:=nil; + FEntry.DOMNodeValid:=false; + FEntry.ValuesValid:=false; // clear all element editors/viewers ShortEdit.Clear; @@ -567,79 +869,134 @@ end; procedure TLazDocForm.UpdateLazDoc(const SrcFilename: string; const Caret: TPoint); var - dn: TFPDocNode; - n: TDOMNode; - EnabledState: Boolean; NewElement: TPascalHelpContextList; + DocFilename: String; + DocFileChanged: Boolean; begin - if not Assigned(doc) then - begin - {$ifdef dbgLazDoc} - DebugLn('TLazDocForm.UpdateLazDoc: document is not set'); - {$endif} - - Exit; - end; - // save the current changes to documentation Save; - - // check if visible - if not Visible then exit; - - // fetch source context - NewElement:=GetNearestSourceElement(SrcFilename, Caret); - // avoid circles and overhead - if (NewElement<>nil) and (FCurrentElement<>nil) - and (NewElement.IsEqual(FCurrentElement)) then begin - NewElement.Free; - exit; + BeginUpdate; + try + // check if visible + if not Visible then exit; + + if (SrcFilename=SourceFilename) and (CompareCaret(Caret,CaretXY)=0) then + exit; + FCaretXY:=Caret; + DocFileChanged:=false; + + if SrcFilename<>SourceFilename then begin + fEntry.SrcFilename:=SrcFilename; + + // search the fpdoc xml file for this unit + // Note: if this is an include file, find the unit + DocFilename:=LazDocBoss.GetFPDocFilenameForSource(SrcFilename,true); + if (DocFile=nil) or (CompareFilenames(DocFile.Filename,DocFilename)<>0) + then begin + // DocFile changed + DebugLn(['TLazDocForm.UpdateLazDoc DocFilename=',DocFilename]); + DocFileChanged:=true; + Reset; + if DocFilename<>'' then begin + try + //DebugLn(['TLazDocForm.UpdateLazDoc DocFilename=',DocFilename]); + if LazDocBoss.LoadFPDocFile(DocFilename,true,false, + fEntry.DocFile) + then begin + fEntry.DocFileValid:=true; + end else begin + DebugLn(['TLazDocForm.UpdateLazDoc FAILED DocFilename=',DocFilename]); + fEntry.DocFile:=nil; + end; + except + on E: Exception do begin + fEntry.DocFile:=nil; + MessageDlg('Error in LazDoc', + 'File: '+DocFilename+#13 + +'Error: '+E.Message, + mtError,[mbCancel],0); + end; + end; + end; + end; + + UpdateCaption; + UpdateLinkIdComboBox; + end; + + if not Assigned(Doc) then + begin + { $ifdef dbgLazDoc} + DebugLn('TLazDocForm.UpdateLazDoc: document is not set'); + { $endif} + + Exit; + end; + + // fetch source context + NewElement:=GetSourceContext(SrcFilename, Caret); + DebugLn(['TLazDocForm.UpdateLazDoc ',NewElement]); + + // avoid circles and overhead + if (not DocFileChanged) then begin + if ((NewElement<>nil) and (fEntry.PascalContext<>nil) + and (NewElement.IsEqual(fEntry.PascalContext))) + or ((NewElement=nil) and (fEntry.PascalContext=nil)) then begin + DebugLn(['TLazDocForm.UpdateLazDoc Same entry']); + NewElement.Free; + exit; + end; + end; + + FreeAndNil(fEntry.PascalContext); + fEntry.PascalContext := NewElement; + fEntry.PascalContextValid:=true; + + fEntry.DOMNode:=NodeByPascalContext(Doc,fEntry.PascalContext); + fEntry.DOMNodeValid:=true; + + if Assigned(fEntry.DOMNode) then + begin + fEntry.Values := GetValuesFromNode(fEntry.DOMNode); + fEntry.ValuesValid:=true; + end else + fEntry.ValuesValid:=false; + + UpdateCaption; + + UpdateValueControls; + FChanged := False; + + ClearInherited(true); + Include(FFlags,ldffInheritedNeedsUpdate); + finally + EndUpdate; end; +end; - FreeAndNil(FCurrentElement); - FCurrentElement := NewElement; - - UpdateCaption; +procedure TLazDocForm.BeginUpdate; +begin + inc(fUpdateLock); +end; - n := NodeByPascalContext(FCurrentElement); - - EnabledState := Assigned(n); - - if Assigned(n) then - begin - dn := ElementFromNode(n); - - ShortEdit.Text := dn[SHORT]; - DescrMemo.Lines.Text := ConvertLineEndings(dn[DESCR]); - ErrorsMemo.Lines.Text := ConvertLineEndings(dn[ERRORS]); - LinkListBox.Items.Text := ConvertLineEndings(dn[SEEALSO]); - LinkIdComboBox.Text := ''; - LinkTextEdit.Clear; - ExampleEdit.Text := ConvertLineEndings(dn[EXAMPLE]); - end - else - begin - ShortEdit.Text := lisLazDocNoDocumentation; - DescrMemo.Lines.Text := lisLazDocNoDocumentation; - ErrorsMemo.Lines.Text := lisLazDocNoDocumentation; - LinkIdComboBox.Text := lisLazDocNoDocumentation; - LinkTextEdit.Text := lisLazDocNoDocumentation; - LinkListBox.Clear; - ExampleEdit.Text := lisLazDocNoDocumentation; +procedure TLazDocForm.EndUpdate; +begin + dec(fUpdateLock); + if fUpdateLock<0 then RaiseGDBException(''); + if fUpdateLock=0 then begin + if ldffCaptionNeedsUpdate in FFlags then UpdateCaption; end; +end; - FChanged := False; - - ShortEdit.Enabled := EnabledState; - DescrMemo.Enabled := EnabledState; - ErrorsMemo.Enabled := EnabledState; - LinkIdComboBox.Enabled := EnabledState; - LinkTextEdit.Enabled := EnabledState; - LinkListBox.Enabled := EnabledState; - AddLinkButton.Enabled := EnabledState; - DeleteLinkButton.Enabled := EnabledState; - ExampleEdit.Enabled := EnabledState; - BrowseExampleButton.Enabled := EnabledState; +procedure TLazDocForm.ClearEntry(DoSave: Boolean); +begin + FChanged:=true; + ShortEdit.Text:=''; + DescrMemo.Text:=''; + ErrorsMemo.Text:=''; + LinkListBox.Items.Clear; + ExampleEdit.Text:=''; + if DoSave then Save; end; function ToUnixLineEnding(const s: String): String; @@ -667,13 +1024,47 @@ end; procedure TLazDocForm.Save; var - Node: TDOMNode; - S: String; - NodeWritten: array [1..NODEITEMS] of Boolean; - i: Integer; + DocNode: TFPDocNode; +begin + // nothing changed => exit + if not FChanged then Exit; + if Doc=nil then exit; + + DocNode[fpdiShort]:=ShortEdit.Text; + DocNode[fpdiDescription]:=DescrMemo.Text; + DocNode[fpdiErrors]:=ErrorsMemo.Text; + DocNode[fpdiSeeAlso]:=LinkListBox.Items.Text; + DocNode[fpdiExample]:=ExampleEdit.Text; + if not WriteNode(fEntry,DocNode,true) then begin + DebugLn(['TLazDocForm.Save FAILED']); + end else begin + FChanged := False; + end; +end; - procedure CheckAndWriteNode(NodeName: String; NodeText: String; - NodeIndex: Integer); +function TLazDocForm.WriteNode(Entry: TLazDocInheritedEntry; + DocNode: TFPDocNode; Interactive: Boolean): Boolean; +var + Node: TDOMNode; + CurNodeName: String; + NodeWritten: array [TFPDocItem] of Boolean; + i: TFPDocItem; + TopNode: TDOMNode; + + function Check(Test: boolean; const Msg: string): Boolean; + begin + Result:=Test; + if not Test then exit; + DebugLn(['TLazDocForm.WriteNode ERROR ',Msg]); + if Interactive then begin; + MessageDlg('Write error', + 'Error writing "'+Entry.DocFilename+'"'#13 + +Msg,mtError,[mbCancel],0); + end; + end; + + procedure CheckAndWriteNode(const NodeName: String; NodeText: String; + NodeIndex: TFPDocItem); var child: TDOMNode; begin @@ -682,11 +1073,11 @@ var NodeName); {$endif} - if S = NodeName then + if CurNodeName = NodeName then begin if not Assigned(Node.FirstChild) then begin - child := doc.CreateTextNode(ToUnixLineEnding(NodeText)); + child := Entry.DocFile.Doc.CreateTextNode(ToUnixLineEnding(NodeText)); Node.AppendChild(child); end else @@ -695,7 +1086,12 @@ var end; end; - procedure CheckAndWriteExampleNode(NodeText: String); + procedure CheckAndWriteNode(const NodeName: String; NodeType: TFPDocItem); + begin + CheckAndWriteNode(NodeName,DocNode[NodeType],NodeType); + end; + + procedure CheckAndWriteExampleNode(const NodeText: String); var FileAttribute: TDOMAttr; begin @@ -703,16 +1099,16 @@ var DebugLn('TLazDocForm.Save[CheckAndWriteExampleNode]'); {$endif} - if S = 'example' then + if CurNodeName = 'example' then begin - FileAttribute := doc.CreateAttribute('file'); + FileAttribute := Entry.DocFile.Doc.CreateAttribute('file'); FileAttribute.Value := NodeText; - node.Attributes.SetNamedItem(FileAttribute); - NodeWritten[EXAMPLE] := True; + Node.Attributes.SetNamedItem(FileAttribute); + NodeWritten[fpdiExample] := True; end; end; - procedure InsertNodeElement(ElementName: String; ElementText: String); + procedure InsertNodeElement(const ElementName, ElementText: String); var child: TDOMNode; FileAttribute: TDOMAttr; @@ -722,77 +1118,83 @@ var ElementName); {$endif} - child := doc.CreateElement(ElementName); + child := Entry.DocFile.doc.CreateElement(ElementName); if ElementName='example' then begin - FileAttribute := doc.CreateAttribute('file'); + FileAttribute := Entry.DocFile.Doc.CreateAttribute('file'); FileAttribute.Value := ElementText; child.Attributes.SetNamedItem(FileAttribute); end else - child.AppendChild(doc.CreateTextNode(ToUnixLineEnding(ElementText))); - Node.AppendChild(child); + child.AppendChild(Entry.DocFile.Doc.CreateTextNode( + ToUnixLineEnding(ElementText))); + TopNode.AppendChild(child); end; begin - // nothing changed, so exit - if not FChanged then Exit; - if Doc=nil then exit; + Result:=false; + if Check(Entry=nil,'Entry=nil') then exit; + if Check(Entry.DocFile=nil,'Entry.DocFile=nil') then exit; + if Check(Entry.DocFile.Doc=nil,'Entry.DocFile.Doc=nil') then exit; + if Check(Entry.PascalContext=nil,'Entry.PascalContext=nil') then exit; + if Check(not Entry.DOMNodeValid,'not Entry.DOMNodeValid') then exit; - Node := NodeByPascalContext(FCurrentElement); - - if not Assigned(Node) then + if Entry.DOMNode=nil then begin + // no old node found + // TODO: create a new node + Check(false,'no old node found. TODO: implement creating a new.'); Exit; + end; + + TopNode := Entry.DOMNode; // reset all nodes - for i := 1 to NODEITEMS do + for i := Low(TFPDocItem) to High(TFPDocItem) do NodeWritten[i] := False; // write all known nodes to XML - Node := Node.FirstChild; + Node := TopNode.FirstChild; while Assigned(Node) do begin if (Node.NodeType = ELEMENT_NODE) then begin - S := Node.NodeName; - - CheckAndWriteNode('short', ShortEdit.Text, SHORT); - CheckAndWriteNode('descr', DescrMemo.Text, DESCR); - CheckAndWriteNode('errors', ErrorsMemo.Text, ERRORS); - CheckAndWriteNode('seealso', LinkListBox.Caption, SEEALSO); - CheckAndWriteExampleNode(ExampleEdit.Text); + CurNodeName := Node.NodeName; + CheckAndWriteNode('short', fpdiShort); + CheckAndWriteNode('descr', fpdiDescription); + CheckAndWriteNode('errors', fpdiErrors); + CheckAndWriteNode('seealso', fpdiSeeAlso); + CheckAndWriteExampleNode(DocNode[fpdiExample]); end; Node := Node.NextSibling; end; // add new nodes to XML if not already updated - Node := NodeByPascalContext(FCurrentElement); - for i := 1 to NODEITEMS do + for i := Low(TFPDocItem) to High(TFPDocItem) do if NodeWritten[i] = False then case i of - SHORT: - InsertNodeElement('short', ShortEdit.Text); - DESCR: - InsertNodeElement('descr', DescrMemo.Text); - ERRORS: - InsertNodeElement('errors', ErrorsMemo.Text); - SEEALSO: - InsertNodeElement('seealso', LinkListBox.Caption); - EXAMPLE: - InsertNodeElement('example', ExampleEdit.Text); + fpdiShort: + InsertNodeElement('short', DocNode[fpdiShort]); + fpdiDescription: + InsertNodeElement('descr', DocNode[fpdiDescription]); + fpdiErrors: + InsertNodeElement('errors', DocNode[fpdiErrors]); + fpdiSeeAlso: + InsertNodeElement('seealso', DocNode[fpdiSeeAlso]); + fpdiExample: + InsertNodeElement('example', DocNode[fpdiExample]); end; + // write fpdoc xml file try - WriteXMLFile(doc, FDocFileName); + WriteXMLFile(Doc, DocFile.Filename); + Result:=true; except on E: Exception do begin MessageDlg('Write error', - 'unable to write file '+FDocFileName+#13 + 'unable to write file '+DocFile.Filename+#13 +E.Message, mtError,[mbCancel],0); end; end; - - FChanged := False; end; procedure TLazDocForm.DocumentationTagChange(Sender: TObject); @@ -811,35 +1213,58 @@ end; procedure TLazDocForm.AddLinkButtonClick(Sender: TObject); begin - FLinkIndex := -1; - if Trim(LinkIdComboBox.Text) <> '' then begin LinkListBox.Items.Add(MakeLink); - FChanged := True; end; end; procedure TLazDocForm.BrowseExampleButtonClick(Sender: TObject); begin + if Doc=nil then exit; if OpenDialog.Execute then ExampleEdit.Text := SetDirSeparators(ExtractRelativepath( - ExtractFilePath(FDocFileName), OpenDialog.FileName)); + ExtractFilePath(DocFile.Filename), OpenDialog.FileName)); +end; + +procedure TLazDocForm.CopyFromInheritedButtonClick(Sender: TObject); +var + InhEntry: TLazDocInheritedEntry; +begin + InhEntry:=FindInheritedEntry; + if InhEntry=nil then exit; + if (not InhEntry.ValuesValid) then exit; + if InhEntry.Values[fpdiShort]='' then exit; + if ShortEdit.Text<>'' then begin + if QuestionDlg('Confirm replace', + GetContextTitle(fEntry.PascalContext)+' already contains the help:'+#13 + +ShortEdit.Text, + mtConfirmation,[mrYes,'Replace',mrCancel],0)<>mrYes then exit; + end; + fEntry.Values:=InhEntry.Values; + fEntry.ValuesValid:=true; + + UpdateValueControls; + FChanged:=true; end; procedure TLazDocForm.DeleteLinkButtonClick(Sender: TObject); begin - if FLinkIndex >= 0 then - begin - LinkListBox.Items.Delete(FLinkIndex); - - FLinkIndex := -1; - + if LinkListBox.ItemIndex >= 0 then begin + LinkListBox.Items.Delete(LinkListBox.ItemIndex); FChanged := True; end; end; +{ TLazDocInheritedEntry } + +destructor TLazDocInheritedEntry.Destroy; +begin + FreeAndNil(PascalContext); + inherited Destroy; +end; + initialization {$I lazdocfrm.lrs} diff --git a/ide/lazdocselectinherited.lfm b/ide/lazdocselectinherited.lfm new file mode 100644 index 0000000000..e73a9c2f55 --- /dev/null +++ b/ide/lazdocselectinherited.lfm @@ -0,0 +1,43 @@ +object LazDocSelectInheritedDlg: TLazDocSelectInheritedDlg + Left = 294 + Height = 75 + Top = 164 + Width = 330 + HorzScrollBar.Page = 329 + VertScrollBar.Page = 74 + Caption = 'LazDocSelectInheritedDlg' + OnCreate = FormCreate + object InheritedComboBox: TComboBox + Left = 8 + Height = 25 + Top = 8 + Width = 312 + Anchors = [akTop, akLeft, akRight] + AutoCompleteText = [cbactEndOfLineComplete, cbactSearchAscending] + MaxLength = 0 + TabOrder = 0 + Text = 'InheritedComboBox' + end + object OkButton: TButton + Left = 24 + Height = 25 + Top = 40 + Width = 75 + BorderSpacing.InnerBorder = 4 + Caption = 'OkButton' + Default = True + ModalResult = 1 + TabOrder = 1 + end + object CancelButton: TButton + Left = 136 + Height = 25 + Top = 40 + Width = 75 + BorderSpacing.InnerBorder = 4 + Cancel = True + Caption = 'CancelButton' + ModalResult = 2 + TabOrder = 2 + end +end diff --git a/ide/lazdocselectinherited.lrs b/ide/lazdocselectinherited.lrs new file mode 100644 index 0000000000..076499d1db --- /dev/null +++ b/ide/lazdocselectinherited.lrs @@ -0,0 +1,17 @@ +{ This is an automatically generated lazarus resource file } + +LazarusResources.Add('TLazDocSelectInheritedDlg','FORMDATA',[ + 'TPF0'#25'TLazDocSelectInheritedDlg'#24'LazDocSelectInheritedDlg'#4'Left'#3'&' + +#1#6'Height'#2'K'#3'Top'#3#164#0#5'Width'#3'J'#1#18'HorzScrollBar.Page'#3'I' + +#1#18'VertScrollBar.Page'#2'J'#7'Caption'#6#24'LazDocSelectInheritedDlg'#8'O' + +'nCreate'#7#10'FormCreate'#0#9'TComboBox'#17'InheritedComboBox'#4'Left'#2#8#6 + +'Height'#2#25#3'Top'#2#8#5'Width'#3'8'#1#7'Anchors'#11#5'akTop'#6'akLeft'#7 + +'akRight'#0#16'AutoCompleteText'#11#22'cbactEndOfLineComplete'#20'cbactSearc' + +'hAscending'#0#9'MaxLength'#2#0#8'TabOrder'#2#0#4'Text'#6#17'InheritedComboB' + +'ox'#0#0#7'TButton'#8'OkButton'#4'Left'#2#24#6'Height'#2#25#3'Top'#2'('#5'Wi' + +'dth'#2'K'#25'BorderSpacing.InnerBorder'#2#4#7'Caption'#6#8'OkButton'#7'Defa' + +'ult'#9#11'ModalResult'#2#1#8'TabOrder'#2#1#0#0#7'TButton'#12'CancelButton'#4 + +'Left'#3#136#0#6'Height'#2#25#3'Top'#2'('#5'Width'#2'K'#25'BorderSpacing.Inn' + +'erBorder'#2#4#6'Cancel'#9#7'Caption'#6#12'CancelButton'#11'ModalResult'#2#2 + +#8'TabOrder'#2#2#0#0#0 +]); diff --git a/ide/lazdocselectinherited.pas b/ide/lazdocselectinherited.pas new file mode 100644 index 0000000000..dd42f5190d --- /dev/null +++ b/ide/lazdocselectinherited.pas @@ -0,0 +1,63 @@ +{ +/*************************************************************************** + LazDocFrm.pas + ------------- + + ***************************************************************************/ + + *************************************************************************** + * * + * 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 . You can also * + * obtain it by writing to the Free Software Foundation, * + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + *************************************************************************** +} +unit LazDocSelectInherited; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls, + Buttons; + +type + + { TLazDocSelectInheritedDlg } + + TLazDocSelectInheritedDlg = class(TForm) + OkButton: TButton; + CancelButton: TButton; + InheritedComboBox: TComboBox; + procedure FormCreate(Sender: TObject); + end; + +implementation + +{ TLazDocSelectInheritedDlg } + +procedure TLazDocSelectInheritedDlg.FormCreate(Sender: TObject); +begin + Caption:='Select an inherited entry'; + OkButton.Caption:='Ok'; + CancelButton.Caption:='Cancel'; +end; + +initialization + {$I lazdocselectinherited.lrs} + +end. + diff --git a/ide/project.pp b/ide/project.pp index a15e00a3b5..c51dfe3124 100644 --- a/ide/project.pp +++ b/ide/project.pp @@ -422,14 +422,6 @@ type { TProject } - TProjectFileSearchFlag = ( - pfsfResolveFileLinks, - pfsfOnlyEditorFiles, - pfsfOnlyVirtualFiles, - pfsfOnlyProjectFiles - ); - TProjectFileSearchFlags = set of TProjectFileSearchFlag; - TEndUpdateProjectEvent = procedure(Sender: TObject; ProjectChanged: boolean) of object; @@ -590,6 +582,8 @@ type function UnitWithUnitname(const AnUnitname: string): TUnitInfo; function SearchFile(const ShortFilename: string; SearchFlags: TSearchIDEFileFlags): TUnitInfo; + function FindFile(const AFilename: string; + SearchFlags: TProjectFileSearchFlags): TLazProjectFile; override; // units in editor procedure CloseEditorIndex(EditorIndex:integer); @@ -3426,6 +3420,12 @@ begin end; end; +function TProject.FindFile(const AFilename: string; + SearchFlags: TProjectFileSearchFlags): TLazProjectFile; +begin + Result:=UnitInfoWithFilename(AFilename, SearchFlags); +end; + function TProject.IndexOfFilename(const AFilename: string): integer; begin Result:=UnitCount-1; diff --git a/ide/revision.inc b/ide/revision.inc index 96568f847c..b73d5d9d23 100644 --- a/ide/revision.inc +++ b/ide/revision.inc @@ -1,2 +1,2 @@ // Created by Svn2RevisionInc -const RevisionStr = '9724:9725M'; +const RevisionStr = '9728M'; diff --git a/ide/uniteditor.pp b/ide/uniteditor.pp index d5c4311b6b..3bf2c950fb 100644 --- a/ide/uniteditor.pp +++ b/ide/uniteditor.pp @@ -579,7 +579,6 @@ type procedure ShowLazDoc; procedure UpdateLazDoc; - procedure LazDocNewPage; property Editors[Index:integer]:TSourceEditor read GetEditors; function EditorCount:integer; @@ -2864,99 +2863,19 @@ end; procedure TSourceNotebook.ShowLazDoc; begin DoShowLazDoc; - LazDocNewPage; -end; - -function FindLazDocPathFromFile(const AFileName: string): string; -var - i: integer; - fn: string; - SearchPaths: String; - PathList: TStrings; -begin - Result := ''; - if not FilenameIsAbsolute(AFileName) then exit; - if not FilenameIsPascalSource(AFileName) then exit; - - // add global lazdoc paths - SearchPaths:=EnvironmentOptions.LazDocPaths; - // if this is a project file then add project lazdoc paths - if Project1.UnitInfoWithFilename(AFileName,[pfsfOnlyProjectFiles])<>nil then - SearchPaths:=LazarusIDE.ActiveProject.LazDocPaths+';'+SearchPaths; - - // replace macros - IDEMacros.SubstituteMacros(SearchPaths); - SearchPaths:=TrimSearchPath(SearchPaths,''); - - //DebugLn('FindLazDocPathFromFile AFileName="',AFileName,'" SearchPaths="',SearchPaths,'"'); - - // search xml file in all directories - fn := PathDelim + ChangeFileExt(ExtractFileName(AFileName), '.xml'); - PathList:=SplitString(SearchPaths,';'); - try - for i:=0 to PathList.Count-1 do begin - if FilenameIsAbsolute(PathList[i]) - and FileExistsCached(TrimFilename(PathList[i] + fn)) then - begin - Result := PathList[i]; - break; - end; - end; - finally - PathList.Free; - end; - //DebugLn('FindLazDocPathFromFile Result="',Result,'"'); -end; - -procedure TSourceNotebook.LazDocNewPage; -var - SrcEdit: TSourceEditor; - DocPath: string; - NewDocPath: string; -begin - //DebugLn('TSourceNotebook.LazDocNewPage ',dbgs(Assigned(LazDocForm))); - if Assigned(LazDocForm) then - begin - SrcEdit:=GetActiveSE; - if SrcEdit=nil then exit; - - DocPath := FindLazDocPathFromFile(SrcEdit.FileName); - - if DocPath <> '' then - begin - // load the .xml file - NewDocPath:=DocPath + PathDelim + - ChangeFileExt(ExtractFileName(SrcEdit.FileName),'.xml'); - if NewDocPath<>LazDocForm.DocFileName then begin - LazDocForm.DocFileName := NewDocPath; - UpdateLazDoc; - end; - end - else - LazDocForm.Reset; - end; + UpdateLazDoc; end; procedure TSourceNotebook.UpdateLazDoc; var SrcEdit: TSourceEditor; - DocPath: string; CaretPos: TPoint; begin if LazDocForm = nil then exit; - SrcEdit:=GetActiveSE; - - // find a path that contains the .xml file - DocPath := FindLazDocPathFromFile(SrcEdit.FileName); - - if DocPath <> '' then - begin - CaretPos := SrcEdit.EditorComponent.CaretXY; - LazDocForm.UpdateLazDoc(SrcEdit.Filename,CaretPos); - end - else - LazDocForm.Reset; + if SrcEdit=nil then exit; + CaretPos := SrcEdit.EditorComponent.CaretXY; + LazDocForm.UpdateLazDoc(SrcEdit.Filename,CaretPos); end; function TSourceNotebook.OnSynCompletionPaintItem(const AKey: string; @@ -5274,8 +5193,6 @@ var TempEditor:TSourceEditor; Begin TempEditor:=GetActiveSE; - LazDocNewPage; - //writeln('TSourceNotebook.NotebookPageChanged ',Notebook.Pageindex,' ',TempEditor <> nil,' fAutoFocusLock=',fAutoFocusLock); if TempEditor <> nil then begin @@ -5298,6 +5215,8 @@ Begin FOnEditorVisibleChanged(sender); CheckCurrentCodeBufferChanged; end; + + UpdateLazDoc; end; Procedure TSourceNotebook.ProcessParentCommand(Sender: TObject; diff --git a/ideintf/projectintf.pas b/ideintf/projectintf.pas index 375a800254..a8b21e7370 100644 --- a/ideintf/projectintf.pas +++ b/ideintf/projectintf.pas @@ -498,6 +498,14 @@ type { TLazProject - interface class to a Lazarus project } + TProjectFileSearchFlag = ( + pfsfResolveFileLinks, + pfsfOnlyEditorFiles, + pfsfOnlyVirtualFiles, + pfsfOnlyProjectFiles + ); + TProjectFileSearchFlags = set of TProjectFileSearchFlag; + TLazProject = class(TPersistent) private FLazCompilerOptions: TLazCompilerOptions; @@ -535,6 +543,8 @@ type procedure AddPackageDependency(const PackageName: string); virtual; abstract; function ShortDescription: string; procedure ClearModifieds; + function FindFile(const AFilename: string; + SearchFlags: TProjectFileSearchFlags): TLazProjectFile; virtual; abstract; public property MainFileID: Integer read GetMainFileID write SetMainFileID; property Files[Index: integer]: TLazProjectFile read GetFiles; diff --git a/lcl/interfaces/gtk/gtkproc.inc b/lcl/interfaces/gtk/gtkproc.inc index a4c182ab3e..911ff18b7f 100644 --- a/lcl/interfaces/gtk/gtkproc.inc +++ b/lcl/interfaces/gtk/gtkproc.inc @@ -369,19 +369,6 @@ begin result := gdk_window_get_colormap(Drawable); end; -function FormToX11Window(const AForm: TCustomForm): X.TWindow; -var - GdkWindow: PGdkWindowPrivate; - Widget: PGtkWidget; -begin - Result:=0; - if (AForm=nil) or (not AForm.HandleAllocated) then exit; - Widget:=PGtkWidget(AForm.Handle); - GdkWindow := PGdkWindowPrivate(Widget^.window); - if GdkWindow=nil then exit; - Result := GdkWindow^.xwindow; -end; - {$EndIf} {$Ifdef GTK2} @@ -1097,6 +1084,21 @@ begin {$ENDIF} end; +{$IFDEF HasGtkX} +function FormToX11Window(const AForm: TCustomForm): X.TWindow; +var + GdkWindow: PGdkWindowPrivate; + Widget: PGtkWidget; +begin + Result:=0; + if (AForm=nil) or (not AForm.HandleAllocated) then exit; + Widget:=PGtkWidget(AForm.Handle); + GdkWindow := PGdkWindowPrivate(Widget^.window); + if GdkWindow=nil then exit; + Result := GdkWindow^.xwindow; +end; +{$ENDIF} + {------------------------------------------------------------------------------ procedure SetComboBoxText(ComboWidget: PGtkCombo; const NewText: string);