{ /*************************************************************************** initialsetupdlgs.pas -------------------- Contains the dialogs to help users setup basic settings. ***************************************************************************/ *************************************************************************** * * * 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** Author: Mattias Gaertner Abstract: Contains the dialogs to help users setup basic settings. } unit InitialSetupDlgs; {$mode objfpc}{$H+} {off $DEFINE VerboseFPCSrcScanThead} interface uses // RTL + FCL Classes, SysUtils, fgl, pkgglobals, fpmkunit, // LCL Forms, Controls, Buttons, Dialogs, Graphics, ComCtrls, ExtCtrls, StdCtrls, // CodeTools FileProcs, CodeToolManager, DefineTemplates, // LazUtils FPCAdds, FileUtil, LazUTF8, LazFileUtils, LazFileCache, LazLoggerBase, // IdeIntf IdeIntfStrConsts, MacroDefIntf, IDEDialogs, IDEImagesIntf, IDEUtils, // DebuggerIntf DbgIntfDebuggerBase, // LazDebuggerGdbmi GDBMIDebugger, DividerBevel, // IdeConfig LazConf, EnvironmentOpts, TransferMacros, IDEProcs, // IDE LazarusIDEStrConsts, IDETranslations, BaseBuildManager, InitialSetupProc, GenerateFppkgConfigurationDlg, LazarusPackageIntf, InitialSetupDlgDebuggerFrame, IdeDebuggerOpts; type TInitialSetupDialog = class; TSetupFrameInfo = record Node: TTreeNode; Page: TTabSheet; State: TInitSetupDlgFrameState; Action: TInitSetupDlgFrameAction; Group: String; end; TSetupDlgFrameMap = specialize TFPGMap; TGroupMap = specialize TFPGMap; { TSearchFpcSourceThread } TSearchFpcSourceThread = class(TThread) private fSetupDialog: TInitialSetupDialog; fFPCVer: string; fFoundFPCSrc: TSDFileInfo; {$IFDEF VerboseFPCSrcScanThead} fPath: string; fFileInfo: TSearchRec; procedure Debug; {$ENDIF} function CheckFPCSrcDir(Dir: string): TSDFileInfo; procedure DoSearch(const APath: String); procedure UpdateFPCSrcDir; procedure Finishing; protected procedure Execute; override; public constructor Create(aSetupDialog: TInitialSetupDialog); destructor Destroy; override; end; { TInitialSetupDialog } TInitialSetupDialog = class(TForm, ISetupDlgProvider) BtnPanel: TPanel; CompilerBrowseButton: TButton; CompilerComboBox: TComboBox; CompilerLabel: TLabel; CompilerMemo: TMemo; CompilerTabSheet: TTabSheet; DebuggerTabSheet: TTabSheet; FPCSourcesTabSheet: TTabSheet; FPCSrcDirBrowseButton: TButton; FPCSrcDirComboBox: TComboBox; FPCSrcDirLabel: TLabel; FPCSrcDirMemo: TMemo; ImageList1: TImageList; LazarusTabSheet: TTabSheet; LazDirBrowseButton: TButton; LazDirComboBox: TComboBox; LazDirLabel: TLabel; LazDirMemo: TMemo; MakeExeBrowseButton: TButton; MakeExeComboBox: TComboBox; MakeExeLabel: TLabel; MakeExeMemo: TMemo; MakeExeTabSheet: TTabSheet; PropertiesPageControl: TPageControl; PropertiesTreeView: TTreeView; ScanLabel: TLabel; ScanProgressBar: TProgressBar; Splitter1: TSplitter; StartIDEBitBtn: TBitBtn; StopScanButton: TBitBtn; WelcomePaintBox: TPaintBox; FppkgTabSheet: TTabSheet; FppkgComboBox: TComboBox; FppkgLabel: TLabel; FppkgBrowseButton: TButton; FppkgMemo: TMemo; FppkgWriteConfigButton: TButton; procedure CompilerBrowseButtonClick(Sender: TObject); procedure CompilerComboBoxChange(Sender: TObject); procedure CompilerComboBoxExit(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FPCSrcDirBrowseButtonClick(Sender: TObject); procedure FPCSrcDirComboBoxChange(Sender: TObject); procedure LazDirBrowseButtonClick(Sender: TObject); procedure LazDirComboBoxChange(Sender: TObject); procedure MakeExeBrowseButtonClick(Sender: TObject); procedure MakeExeComboBoxChange(Sender: TObject); procedure OnAppActivate(Sender: TObject); procedure PropertiesPageControlChange(Sender: TObject); procedure PropertiesTreeViewSelectionChanged(Sender: TObject); procedure StartIDEBitBtnClick(Sender: TObject); procedure StopScanButtonClick(Sender: TObject); procedure WelcomePaintBoxPaint(Sender: TObject); procedure OnIdle(Sender: TObject; var {%H-}Done: Boolean); procedure FppkgComboBoxChange(Sender: TObject); procedure FppkgBrowseButtonClick(Sender: TObject); procedure FppkgWriteConfigButtonClick(Sender: TObject); private FInitDebuggerFrame: TInitDebuggerFrame; FSetupDlgFrameMap: TSetupDlgFrameMap; FSetupDlgGroupMap: TGroupMap; FFlags: TSDFlags; FLastParsedLazDir: string; fLastParsedCompiler: string; fLastParsedFPCSrcDir: string; fLastParsedMakeExe: string; fLastParsedFppkgConfigFile: string; FIdleConnected: boolean; ImgIDFatal: LongInt; ImgIDError: LongInt; ImgIDWarning: LongInt; ImgIDNote: LongInt; ImgIDHint: LongInt; ImgIDInfo: LongInt; FHeadGraphic: TPortableNetworkGraphic; FSelectingPage: boolean; FCandidates: array[TSDFilenameType] of TSDFileInfoList; // list of TSDFileInfo fSearchFpcSourceThread: TSearchFpcSourceThread; procedure DoDbgFrameStateChanged(AState: TSDFilenameQuality); procedure FrameStateChanged(AnSender: ISetupDlgFrame; AState: TInitSetupDlgFrameState; AnAction: TInitSetupDlgFrameAction); procedure SetGroupCaption(AGroupId, AName: String); procedure UpdateCaptions; procedure SelectPage(const ATreeNode: TTreeNode; AnUserSelect: Boolean = False); function SelectDirectory(aTitle: string): string; function SelectDirectory(aTitle: string; aPathFileName: string; aEnvOptParseType: TEnvOptParseType): string; overload; procedure StartFPCSrcThread; procedure UpdateLazarusDirCandidates; procedure UpdateCompilerFilenameCandidates; procedure UpdateFPCSrcDirCandidates; procedure UpdateFPCSrcDirCandidate(aFPCSrcDirInfo: TSDFileInfo); procedure UpdateMakeExeCandidates(aStopIfFits: boolean = False); procedure UpdateFppkgCandidates; procedure FillComboboxWithFileInfoList(ABox: TComboBox; List: TSDFileInfoList; ItemIndex: integer = 0); procedure SetIdleConnected(const AValue: boolean); procedure UpdateLazDirNote; procedure UpdateCompilerNote(aQuiet: boolean = False); procedure UpdateFPCSrcDirNote; procedure UpdateMakeExeNote; procedure UpdateFppkgNote; function FirstErrorNode: TTreeNode; function FirstWarningNode: TTreeNode; function GetFirstCandidate(Candidates: TSDFileInfoList; MinQuality: TSDFilenameQuality = sddqCompatible): TSDFileInfo; function QualityToImgIndex(Quality: TSDFilenameQuality): integer; procedure ShowHideScanControls(aShow: Boolean); procedure ThreadTerminated(Sender: TObject); // called in main thread by fSearchFpcSourceThread.OnTerminate procedure TranslateResourceStrings; public TVNodeLazarus: TTreeNode; TVNodeCompiler: TTreeNode; TVNodeFPCSources: TTreeNode; TVNodeMakeExe: TTreeNode; TVNodeDebugger: TTreeNode; TVNodeFppkg: TTreeNode; constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure Init; //Check for config errors, find and show alternatives property IdleConnected: boolean read FIdleConnected write SetIdleConnected; end; function ShowInitialSetupDialog: TModalResult; // Debugger // Search debugger candidates and add them to list, including quality level implementation type { TSetupMacros } TSetupMacros = class(TTransferMacroList) protected procedure DoSubstitution({%H-}TheMacro: TTransferMacro; const MacroName: string; var s: string; const {%H-}Data: PtrInt; var Handled, {%H-}Abort: boolean; {%H-}Depth: integer); override; public FPCVer: string; LazarusDir: string; end; function ShowInitialSetupDialog: TModalResult; var InitialSetupDialog: TInitialSetupDialog; begin InitialSetupDialog:=TInitialSetupDialog.Create(nil); try Application.TaskBarBehavior:=tbMultiButton; InitialSetupDialog.Init; Result:=InitialSetupDialog.ShowModal; finally InitialSetupDialog.Free; Application.TaskBarBehavior:=tbDefault; end; end; { TSearchFpcSourceThread } function DoCompFrameList(const Item1, Item2: ISetupDlgFrame): Integer; begin Result := Item1.SortOrder - Item2.SortOrder; if Result = 0 then begin if Item1.UniqueId < Item2.UniqueId then Result := -1; if Item1.UniqueId > Item2.UniqueId then Result := 1; end; end; constructor TSearchFpcSourceThread.Create(aSetupDialog: TInitialSetupDialog); begin inherited Create(True); FreeOnTerminate:=True; fSetupDialog:=aSetupDialog; end; destructor TSearchFpcSourceThread.Destroy; begin inherited Destroy; end; procedure TSearchFpcSourceThread.Execute; var RootDir: String; begin // ToDo: RootDir must be changed for Windows and maybe other systems. // GetUserDir returns the user profile dir on Windows. RootDir:=GetUserDir; // Scan directories under root directory. DoSearch(AppendPathDelim(RootDir)); if Assigned(fFoundFPCSrc) then Synchronize(@UpdateFPCSrcDir); // Update GUI in main thread. Synchronize(@Finishing); end; function TSearchFpcSourceThread.CheckFPCSrcDir(Dir: string): TSDFileInfo; var RealDir: String; begin Result:=Nil; RealDir:=TrimFilename(Dir); if RealDir='' then exit; if not DirPathExistsCached(RealDir) then exit; // check if exists Result:=TSDFileInfo.Create; Result.Filename:=RealDir; Result.Caption:=Dir; // check quality Result.Quality:=CheckFPCSrcDirQuality(RealDir, Result.Note, fFPCVer, False); if Result.Quality<>sddqCompatible then // return only exact matches FreeAndNil(Result); end; procedure TSearchFpcSourceThread.DoSearch(const APath: String); var PathInfo: TSearchRec; FPCSrc: TSDFileInfo; begin if FindFirstUTF8(APath+AllDirectoryEntriesMask, faDirectory, PathInfo) = 0 then try repeat if Terminated then Break; if (PathInfo.Name='') or (PathInfo.Name[1]='.') or ((PathInfo.Attr and faDirectory) = 0) then Continue; case lowercase(PathInfo.Name) of 'pictures', 'music', 'photos', 'movies', 'videos', 'calendar', 'calendars', 'mail', 'messages', 'contacts', 'cache', 'caches', 'trash', 'containers', {$IFDEF darwin} 'applications', {$ENDIF} {$IFDEF Linux} 'proc', 'sys', 'dev', {$ENDIF} 'tmp': continue; end; {$IFDEF VerboseFPCSrcScanThead} fPath := APath; fFileInfo := PathInfo; Synchronize(@Debug); {$ENDIF} DoSearch(AppendPathDelim(APath+PathInfo.Name)); // Recursive call FPCSrc:=CheckFPCSrcDir(APath+PathInfo.Name); if Assigned(FPCSrc) then begin fFoundFPCSrc:=FPCSrc; // An exact match was found. Terminate; end; until (FindNextUTF8(PathInfo) <> 0); finally FindCloseUTF8(PathInfo); end; end; {$IFDEF VerboseFPCSrcScanThead} procedure TSearchFpcSourceThread.Debug; begin DebugLn(['* TSearchFpcSourceThread.Debug: Path=', fPath, ', Name=', fFileInfo.Name]); end; {$ENDIF} procedure TSearchFpcSourceThread.UpdateFPCSrcDir; begin DebugLn(['TSearchFpcSourceThread.UpdateFPCSrcDir']); fSetupDialog.UpdateFPCSrcDirCandidate(fFoundFPCSrc); fSetupDialog.UpdateFPCSrcDirNote; end; procedure TSearchFpcSourceThread.Finishing; begin DebugLn(['TSearchFpcSourceThread.Finishing']); fSetupDialog.ShowHideScanControls(False); // Hide scan controls end; { TSetupMacros } procedure TSetupMacros.DoSubstitution(TheMacro: TTransferMacro; const MacroName: string; var s: string; const Data: PtrInt; var Handled, Abort: boolean; Depth: integer); begin Handled:=true; if CompareText(MacroName,'ENV')=0 then s:=GetEnvironmentVariableUTF8(MacroName) else if CompareText(MacroName,'PrimaryConfigPath')=0 then s:=GetPrimaryConfigPath else if CompareText(MacroName,'SecondaryConfigPath')=0 then s:=GetSecondaryConfigPath else if CompareText(MacroName,'FPCVer')=0 then begin if FPCVer<>'' then s:=FPCVer else s:={$I %FPCVERSION%}; end else if CompareText(MacroName,'LazarusDir')=0 then begin if LazarusDir<>'' then s:=LazarusDir else s:=''; end else if (CompareText(MacroName,'TargetOS')=0) then s:=GetCompiledTargetOS else if (CompareText(MacroName,'TargetCPU')=0) then s:=GetCompiledTargetCPU else if (CompareText(MacroName,'SrcOS')=0) then s:=GetDefaultSrcOSForTargetOS(GetCompiledTargetOS) else Handled:=false; //debugln(['TSetupMacros.DoSubstitution MacroName=',MacroName,' Value="',s,'"']); end; {$R *.lfm} { TInitialSetupDialog } procedure TInitialSetupDialog.FormCreate(Sender: TObject); var FrameList: TSetupDlgFrameList; i, GrpIdx: Integer; NewNode: TTreeNode; NewTab: TTabSheet; ScrollBox: TScrollBox; NewParent: TWinControl; CurFrame: ISetupDlgFrame; Info, GrpInfo: TSetupFrameInfo; Grp: String; NewDiv: TDividerBevel; begin LazarusTabSheet.Caption:='Lazarus'; CompilerTabSheet.Caption:=lisCompiler; FPCSourcesTabSheet.Caption:=lisFPCSources; MakeExeTabSheet.Caption:='Make'; DebuggerTabSheet.Caption:=lisDebugger; FppkgTabSheet.Caption := 'Fppkg'; FHeadGraphic:=TPortableNetworkGraphic.Create; FHeadGraphic.LoadFromResourceName(HInstance, 'ide_icon48x48'); TVNodeLazarus:=PropertiesTreeView.Items.Add(nil,LazarusTabSheet.Caption); TVNodeCompiler:=PropertiesTreeView.Items.Add(nil,CompilerTabSheet.Caption); TVNodeFPCSources:=PropertiesTreeView.Items.Add(nil,FPCSourcesTabSheet.Caption); TVNodeMakeExe:=PropertiesTreeView.Items.Add(nil,MakeExeTabSheet.Caption); TVNodeDebugger:=PropertiesTreeView.Items.Add(nil,DebuggerTabSheet.Caption); LazarusTabSheet.Tag := PtrUInt(Pointer(TVNodeLazarus)); CompilerTabSheet.Tag := PtrUInt(Pointer(TVNodeCompiler)); FPCSourcesTabSheet.Tag := PtrUInt(Pointer(TVNodeFPCSources)); MakeExeTabSheet.Tag := PtrUInt(Pointer(TVNodeMakeExe)); DebuggerTabSheet.Tag := PtrUInt(Pointer(TVNodeDebugger)); FppkgTabSheet.TabVisible := EnvironmentOptions.FppkgCheck; if FppkgTabSheet.TabVisible then begin TVNodeFppkg:=PropertiesTreeView.Items.Add(nil,FppkgTabSheet.Caption); FppkgTabSheet.Tag := PtrUInt(Pointer(TVNodeFppkg)); end; ImgIDFatal := Imagelist1.AddResourceName(HInstance, 'state_fatal'); ImgIDError := Imagelist1.AddResourceName(HInstance, 'state_error'); ImgIDWarning := Imagelist1.AddResourceName(HInstance, 'state_warning'); ImgIDNote := Imagelist1.AddResourceName(HInstance, 'state_note'); ImgIDHint := Imagelist1.AddResourceName(HInstance, 'state_hint'); ImgIDInfo := Imagelist1.AddResourceName(HInstance, 'state_information'); IDEImages.AssignImage(StopScanButton, 'menu_stop'); FrameList := SetupDlgFrameList; FrameList.Sort(@DoCompFrameList); DisableAutoSizing; try for i := 0 to FrameList.Count - 1 do begin CurFrame := FrameList[i]; Grp := CurFrame.GroupId; GrpIdx := -1; NewNode := nil; if Grp <> '' then begin GrpIdx := FSetupDlgGroupMap.IndexOf(Grp); if GrpIdx >= 0 then begin GrpInfo := FSetupDlgGroupMap.Data[GrpIdx]; NewNode := GrpInfo.Node; NewTab := GrpInfo.Page; ScrollBox := NewTab.Controls[0] as TScrollBox; end; end; if NewNode = nil then begin NewNode := PropertiesTreeView.Items.Add(nil, CurFrame.Caption); NewTab := PropertiesPageControl.AddTabSheet; NewTab.Caption := CurFrame.Caption; NewTab.Tag := PtrUInt(NewNode); ScrollBox := TScrollBox.Create(Self); ScrollBox.Parent := NewTab; ScrollBox.Align := alClient; ScrollBox.HorzScrollBar.Visible := False; NewParent := ScrollBox; if (GrpIdx < 0) and (Grp <> '') then begin GrpInfo.Node := NewNode; GrpInfo.Page := NewTab; GrpInfo.State := issOk; GrpInfo.Action := isaReady; GrpIdx := FSetupDlgGroupMap.Add(Grp, GrpInfo); end; end; if GrpIdx >= 0 then begin NewDiv := TDividerBevel.Create(Self); NewDiv.Parent := ScrollBox; if ScrollBox.ControlCount > 1 then begin NewDiv.AnchorSide[akTop].Side := asrBottom; NewDiv.AnchorSide[akTop].Control := ScrollBox.Controls[ScrollBox.ControlCount - 2]; NewDiv.BorderSpacing.Top := 10; end else begin NewDiv.AnchorSide[akTop].Side := asrTop; NewDiv.AnchorSide[akTop].Control := ScrollBox; end; NewDiv.AnchorSide[akLeft].Side := asrTop; NewDiv.AnchorSide[akLeft].Control := ScrollBox; NewDiv.AnchorSide[akRight].Side := asrBottom; NewDiv.AnchorSide[akRight].Control := ScrollBox; NewDiv.Anchors := [akTop, akLeft, akRight]; NewDiv.Caption := CurFrame.Caption; NewParent := TPanel.Create(Self); TPanel(NewParent).Parent := ScrollBox; TPanel(NewParent).AnchorSide[akTop].Side := asrBottom; TPanel(NewParent).AnchorSide[akTop].Control := NewDiv; TPanel(NewParent).AnchorSide[akLeft].Side := asrTop; TPanel(NewParent).AnchorSide[akLeft].Control := ScrollBox; TPanel(NewParent).AnchorSide[akRight].Side := asrBottom; TPanel(NewParent).AnchorSide[akRight].Control := ScrollBox; TPanel(NewParent).Anchors := [akTop, akLeft, akRight]; TPanel(NewParent).AutoSize := True; TPanel(NewParent).BevelInner := bvNone; TPanel(NewParent).BevelOuter := bvNone; end; Info.Node := NewNode; Info.Page := NewTab; Info.State := issOk; Info.Action := isaReady; Info.Group := Grp; FSetupDlgFrameMap.Add(Pointer(CurFrame), Info); CurFrame.AddToDialog(Self, NewParent, Self); end; finally EnableAutoSizing; end; UpdateCaptions; Application.AddOnActivateHandler(@OnAppActivate); end; procedure TInitialSetupDialog.CompilerComboBoxChange(Sender: TObject); begin UpdateCompilerNote({Quiet} True); UpdateFPCSrcDirNote; end; procedure TInitialSetupDialog.CompilerComboBoxExit(Sender: TObject); begin UpdateCompilerNote({Quiet} False); UpdateFPCSrcDirNote; end; procedure TInitialSetupDialog.CompilerBrowseButtonClick(Sender: TObject); var lExpandedName: string; // Expanded name before Dialog lDirName, lFileName: string; lTitle: string; lChanged: boolean=False; Dlg: TIDEOpenDialog; Filter: String; begin Dlg := IDEOpenDialogClass.Create(nil); try lTitle := 'fpc'+GetExecutableExt; Dlg.Title := SimpleFormat(lisSelectPathTo, [lTitle]); lExpandedName := EnvironmentOptions.GetParsedValue(eopCompilerFilename, CompilerComboBox.Text); lDirName := GetValidDirectory(lExpandedName, {out} lFileName); Dlg.Options := Dlg.Options+[ofFileMustExist]; if lFileName='' then lFileName := lTitle; Filter := dlgFilterAll+'|'+GetAllFilesMask; if ExtractFileExt(lFileName)<>'' then Filter := dlgFilterExecutable+'|*'+ExtractFileExt(lFileName)+'|'+Filter; Dlg.Filter := Filter; Dlg.InitialDir := lDirName; Dlg.FileName := lFileName; if not Dlg.Execute then exit; lFileName := CleanAndExpandFilename(Dlg.Filename); lChanged := UpperCase(lExpandedName)<>UpperCase(lFileName); finally Dlg.Free; end; if lChanged then begin // Avoid loosing $(macros) CompilerComboBox.Text := lFileName; UpdateCompilerNote; end; end; procedure TInitialSetupDialog.FormDestroy(Sender: TObject); var d: TSDFilenameType; begin IdleConnected:=false; if Assigned(fSearchFpcSourceThread) then begin fSearchFpcSourceThread.Terminate; fSearchFpcSourceThread.WaitFor; end; for d:=low(FCandidates) to high(FCandidates) do FreeAndNil(FCandidates[d]); FreeAndNil(FHeadGraphic); end; procedure TInitialSetupDialog.FPCSrcDirBrowseButtonClick(Sender: TObject); var Dir: String; begin Dir:=SelectDirectory(lisSelectFPCSourceDirectory, FPCSrcDirComboBox.Text,eopFPCSourceDirectory); if Dir='' then exit; FPCSrcDirComboBox.Text:=Dir; UpdateFPCSrcDirNote; end; procedure TInitialSetupDialog.FPCSrcDirComboBoxChange(Sender: TObject); begin UpdateFPCSrcDirNote; end; procedure TInitialSetupDialog.LazDirBrowseButtonClick(Sender: TObject); var Dir: String; begin Dir:=SelectDirectory(lisSelectLazarusSourceDirectory,LazDirComboBox.Text,eopLazarusDirectory); if Dir='' then exit; LazDirComboBox.Text:=Dir; UpdateLazDirNote; end; procedure TInitialSetupDialog.LazDirComboBoxChange(Sender: TObject); begin UpdateLazDirNote; end; procedure TInitialSetupDialog.MakeExeBrowseButtonClick(Sender: TObject); var lExpandedName: string; // Expanded name before Dialog lDirName, lFileName: string; lTitle: string; lChanged: boolean=False; Dlg: TIDEOpenDialog; Filter: String; begin Dlg := IDEOpenDialogClass.Create(nil); try lTitle := 'make'+GetExecutableExt; Dlg.Title := SimpleFormat(lisSelectPathTo, [lTitle]); lExpandedName := EnvironmentOptions.GetParsedValue(eopMakeFilename, MakeExeComboBox.Text); lDirName := GetValidDirectory(lExpandedName, {out} lFileName); Dlg.Options := Dlg.Options+[ofFileMustExist]; if lFileName='' then lFileName := lTitle; Filter := dlgFilterAll+'|'+GetAllFilesMask; if ExtractFileExt(lFileName)<>'' then Filter := dlgFilterExecutable+'|*'+ExtractFileExt(lFileName)+'|'+Filter; Dlg.Filter := Filter; Dlg.InitialDir := lDirName; Dlg.FileName := lFileName; if not Dlg.Execute then exit; lFileName := CleanAndExpandFilename(Dlg.Filename); lChanged := UpperCase(lExpandedName)<>UpperCase(lFileName); finally Dlg.Free; end; if lChanged then begin // Avoid loosing $(macros) MakeExeComboBox.Text := lFileName; UpdateMakeExeNote; end; end; procedure TInitialSetupDialog.MakeExeComboBoxChange(Sender: TObject); begin UpdateMakeExeNote; end; procedure TInitialSetupDialog.OnAppActivate(Sender: TObject); begin // switched back from another application InvalidateFileStateCache; end; procedure TInitialSetupDialog.PropertiesPageControlChange(Sender: TObject); var i: Integer; t: PtrInt; begin if PropertiesPageControl.ActivePage=nil then exit; t:=PropertiesPageControl.ActivePage.tag; for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do if PtrUInt(PropertiesTreeView.Items.TopLvlItems[i])=t then SelectPage(PropertiesTreeView.Items.TopLvlItems[i], True); end; procedure TInitialSetupDialog.PropertiesTreeViewSelectionChanged(Sender: TObject); begin if PropertiesTreeView.Selected=nil then SelectPage(TVNodeLazarus) else SelectPage(PropertiesTreeView.Selected, True); end; procedure TInitialSetupDialog.StartIDEBitBtnClick(Sender: TObject); var Node: TTreeNode; s: String; MsgResult: TModalResult; i: Integer; begin Node:=FirstErrorNode; s:=''; if Node=TVNodeLazarus then s:=lisWithoutAProperLazarusDirectoryYouWillGetALotOfWarn else if Node=TVNodeCompiler then s:=lisWithoutAProperCompilerTheCodeBrowsingAndCompilingW else if Node=TVNodeFPCSources then s:=lisWithoutTheProperFPCSourcesCodeBrowsingAndCompletio else if Node=TVNodeMakeExe then s:=lisWithoutAProperMakeExecutableTheCompilingOfTheIDEIs else if Node=TVNodeDebugger then s:=lisWithoutAProperDebuggerDebuggingWillBeDisappointing; if s<>'' then begin MsgResult:=MessageDlg(lisCCOWarningCaption, s, mtWarning, [mbIgnore, mbCancel], 0); if MsgResult<>mrIgnore then exit; end; s:=LazDirComboBox.Text; if s<>'' then EnvironmentOptions.LazarusDirectory:=s; s:=CompilerComboBox.Text; if s<>'' then EnvironmentOptions.CompilerFilename:=s; s:=FPCSrcDirComboBox.Text; if s<>'' then EnvironmentOptions.FPCSourceDirectory:=s; s:=MakeExeComboBox.Text; if s<>'' then EnvironmentOptions.MakeFilename:=s; FInitDebuggerFrame.ApplySelection; for i := 0 to SetupDlgFrameList.Count - 1 do SetupDlgFrameList[i].ApplySelection; ModalResult:=mrOk; end; procedure TInitialSetupDialog.StopScanButtonClick(Sender: TObject); begin if fSearchFpcSourceThread<>nil then fSearchFpcSourceThread.Terminate; end; procedure TInitialSetupDialog.WelcomePaintBoxPaint(Sender: TObject); begin with WelcomePaintBox.Canvas do begin GradientFill(WelcomePaintBox.ClientRect,$854b32,$c88e60,gdHorizontal); Draw(0,WelcomePaintBox.ClientHeight-FHeadGraphic.Height,FHeadGraphic); Font.Color:=clWhite; Font.Height:=30; Brush.Style:=bsClear; TextOut(FHeadGraphic.Width+15, 5, lisConfigureLazarusIDE); end; end; procedure TInitialSetupDialog.OnIdle(Sender: TObject; var Done: Boolean); var f: Boolean; i: Integer; begin f := FFlags <> []; if sdfCompilerFilenameNeedsUpdate in FFlags then begin UpdateCompilerFilenameCandidates; UpdateCompilerNote; end else if sdfFPCSrcDirNeedsUpdate in FFlags then begin UpdateFPCSrcDirCandidates; UpdateFPCSrcDirNote; end else if sdfMakeExeFilenameNeedsUpdate in FFlags then begin UpdateMakeExeCandidates; UpdateMakeExeNote; end else if sdfDebuggerFilenameNeedsUpdate in FFlags then begin DoDbgFrameStateChanged(FInitDebuggerFrame.UpdateState); Exclude(FFlags,sdfDebuggerFilenameNeedsUpdate); IdleConnected:=True; end else if sdfFppkgConfigFileNeedsUpdate in FFlags then begin fLastParsedFppkgConfigFile := ' '; UpdateFppkgCandidates; UpdateFppkgNote; end else IdleConnected:=false; if f then begin for i := 0 to SetupDlgFrameList.Count - 1 do SetupDlgFrameList[i].UpdateState; end; end; procedure TInitialSetupDialog.UpdateCaptions; begin Caption:=SimpleFormat(lisWelcomeToLazarusIDE, [LazarusVersionStr]); StartIDEBitBtn.Caption:=lisStartIDE; LazarusTabSheet.Caption:='Lazarus'; CompilerTabSheet.Caption:=lisCompiler; FPCSourcesTabSheet.Caption:=lisFPCSources; MakeExeTabSheet.Caption:='Make'; DebuggerTabSheet.Caption:=lisDebugger; FppkgTabSheet.Caption:='Fppkg'; TVNodeLazarus.Text:=LazarusTabSheet.Caption; TVNodeCompiler.Text:=CompilerTabSheet.Caption; TVNodeFPCSources.Text:=FPCSourcesTabSheet.Caption; TVNodeMakeExe.Text:=MakeExeTabSheet.Caption; TVNodeDebugger.Text:=DebuggerTabSheet.Caption; if TVNodeFppkg<>nil then TVNodeFppkg.Text:=FppkgTabSheet.Caption; LazDirBrowseButton.Caption:=lisPathEditBrowse; LazDirLabel.Caption:=SimpleFormat( lisTheLazarusDirectoryContainsTheSourcesOfTheIDEAndTh, [PathDelim]); FppkgLabel.Caption:=lisFppkgConfiguration; FppkgBrowseButton.Caption:=lisPathEditBrowse; FppkgWriteConfigButton.Caption:=lisCreateFppkgConfig; CompilerBrowseButton.Caption:=lisPathEditBrowse; CompilerLabel.Caption:=SimpleFormat(lisTheFreePascalCompilerExecutableTypicallyHasTheName, [DefineTemplates.GetDefaultCompilerFilename, DefineTemplates.GetDefaultCompilerFilename(GetCompiledTargetCPU)]); FPCSrcDirBrowseButton.Caption:=lisPathEditBrowse; FPCSrcDirLabel.Caption:=SimpleFormat(lisTheSourcesOfTheFreePascalPackagesAreRequiredForBro, [GetForcedPathDelims('rtl/linux/system.pp')]); ScanLabel.Caption := lisScanning; StopScanButton.Caption:=lisStop; MakeExeBrowseButton.Caption:=lisPathEditBrowse; MakeExeLabel.Caption:=SimpleFormat( lisTheMakeExecutableTypicallyHasTheName, ['make'+GetExecutableExt('')]); end; procedure TInitialSetupDialog.DoDbgFrameStateChanged(AState: TSDFilenameQuality ); var ImageIndex: Integer; begin ImageIndex:=QualityToImgIndex(AState); TVNodeDebugger.ImageIndex:=ImageIndex; TVNodeDebugger.SelectedIndex:=ImageIndex; end; procedure TInitialSetupDialog.FrameStateChanged(AnSender: ISetupDlgFrame; AState: TInitSetupDlgFrameState; AnAction: TInitSetupDlgFrameAction); var ImageIndex, i, j: Integer; nd: TTreeNode; info, info2: TSetupFrameInfo; begin i := FSetupDlgFrameMap.IndexOf(Pointer(AnSender)); if i < 0 then exit; info := FSetupDlgFrameMap.Data[i]; nd := info.Node; info.State := AState; info.Action := AnAction; FSetupDlgFrameMap.Data[i] := info; if info.Group <> '' then begin for j := 0 to FSetupDlgFrameMap.Count - 1 do begin info2 := FSetupDlgFrameMap.Data[j]; if (info2.Group = info.Group) then begin if (info2.State > AState) then AState := info2.State; end; end; end; ImageIndex := -1; case AState of issOk: ImageIndex := -1; issInfo: ImageIndex := ImgIDInfo; issHint: ImageIndex := ImgIDHint; issNote: ImageIndex := ImgIDNote; issWarning: ImageIndex := ImgIDWarning; issError: ImageIndex := ImgIDError; issFatal: ImageIndex := ImgIDFatal; end; nd.ImageIndex:=ImageIndex; nd.SelectedIndex:=ImageIndex; end; procedure TInitialSetupDialog.SetGroupCaption(AGroupId, AName: String); var GrpIdx: Integer; GrpInfo: TSetupFrameInfo; begin GrpIdx := FSetupDlgGroupMap.IndexOf(AGroupId); if GrpIdx >= 0 then begin GrpInfo := FSetupDlgGroupMap.Data[GrpIdx]; GrpInfo.Page.Caption := AName; GrpInfo.Node.Text := AName; end; end; procedure TInitialSetupDialog.SelectPage(const ATreeNode: TTreeNode; AnUserSelect: Boolean); var i: Integer; Node: TTreeNode; info: TSetupFrameInfo; begin if FSelectingPage then exit; FSelectingPage:=true; try for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do begin Node:=PropertiesTreeView.Items.TopLvlItems[i]; if Node=ATreeNode then begin PropertiesTreeView.Selected:=Node; break; end; end; for i:=0 to PropertiesPageControl.PageCount-1 do begin if PropertiesPageControl.Pages[i].Tag=PtrUInt(ATreeNode) then begin PropertiesPageControl.ActivePageIndex:=i; break; end; end; for i := 0 to FSetupDlgFrameMap.Count - 1 do begin info := FSetupDlgFrameMap.Data[i]; if info.Node = ATreeNode then ISetupDlgFrame(FSetupDlgFrameMap.Keys[i]).PageSelected(AnUserSelect); end; finally FSelectingPage:=false; end; end; function TInitialSetupDialog.SelectDirectory(aTitle: string): string; var DirDlg: TSelectDirectoryDialog; begin Result:=''; DirDlg:=TSelectDirectoryDialog.Create(nil); try DirDlg.Title:=aTitle; DirDlg.Options:=DirDlg.Options+[ofPathMustExist,ofFileMustExist]; if not DirDlg.Execute then exit; Result:=DirDlg.FileName; finally DirDlg.Free; end; end; function TInitialSetupDialog.SelectDirectory(aTitle: string; aPathFileName: string; aEnvOptParseType: TEnvOptParseType): string; var DirDlg: TSelectDirectoryDialog; lCurDirName: string; lDirPath: string; lDirName: string; begin Result := ''; if aPathFileName='' then case aEnvOptParseType of eopLazarusDirectory: lDirPath := EnvironmentOptions.GetParsedLazarusDirectory; eopFPCSourceDirectory: lDirPath := EnvironmentOptions.GetParsedFPCSourceDirectory; end else lDirPath := EnvironmentOptions.GetParsedValue(eopLazarusDirectory, aPathFileName); lCurDirName := CleanAndExpandFilename(ExcludeTrailingBackSlash(lDirPath)); lDirPath := GetValidDirectoryAndFilename(lCurDirName, {out} lDirName); lDirPath := ExcludeTrailingBackSlash(lDirPath); DirDlg := TSelectDirectoryDialog.Create(nil); try DirDlg.Title := aTitle; DirDlg.InitialDir := lDirPath; DirDlg.FileName := lDirName; DirDlg.Options := DirDlg.Options + [ofExtensionDifferent, ofPathMustExist]; if DirDlg.Execute then begin lDirName := CleanAndExpandFilename(DirDlg.FileName); if UpperCase(lCurDirName)<>UpperCase(lDirName) then Result := lDirName; end; finally DirDlg.Free; end; end; procedure TInitialSetupDialog.StartFPCSrcThread; begin fSearchFpcSourceThread:=TSearchFpcSourceThread.Create(Self); fSearchFpcSourceThread.OnTerminate:=@ThreadTerminated; fSearchFpcSourceThread.fFPCVer:=GetFPCVer; ShowHideScanControls(True); // Show scan controls while thread is running fSearchFpcSourceThread.Start; end; procedure TInitialSetupDialog.UpdateLazarusDirCandidates; var Dirs: TSDFileInfoList; begin Dirs:=SearchLazarusDirectoryCandidates(false); FreeAndNil(FCandidates[sddtLazarusSrcDir]); FCandidates[sddtLazarusSrcDir]:=Dirs; FillComboboxWithFileInfoList(LazDirComboBox,Dirs); end; procedure TInitialSetupDialog.UpdateCompilerFilenameCandidates; var Files: TSDFileInfoList; begin Exclude(FFlags,sdfCompilerFilenameNeedsUpdate); Files:=SearchFPCExeCandidates(false,CodeToolBoss.CompilerDefinesCache.TestFilename); FreeAndNil(FCandidates[sddtCompilerFilename]); FCandidates[sddtCompilerFilename]:=Files; FillComboboxWithFileInfoList(CompilerComboBox,Files); end; procedure TInitialSetupDialog.UpdateFPCSrcDirCandidates; var Dirs: TSDFileInfoList; begin Exclude(FFlags,sdfFPCSrcDirNeedsUpdate); Dirs:=SearchFPCSrcDirCandidates(false,GetFPCVer); FreeAndNil(FCandidates[sddtFPCSrcDir]); FCandidates[sddtFPCSrcDir]:=Dirs; FillComboboxWithFileInfoList(FPCSrcDirComboBox,Dirs); end; procedure TInitialSetupDialog.UpdateFPCSrcDirCandidate(aFPCSrcDirInfo: TSDFileInfo); var Dirs: TSDFileInfoList; begin Exclude(FFlags,sdfFPCSrcDirNeedsUpdate); FreeAndNil(FCandidates[sddtFPCSrcDir]); Dirs:=TSDFileInfoList.Create; Dirs.Add(aFPCSrcDirInfo); FCandidates[sddtFPCSrcDir]:=Dirs; FillComboboxWithFileInfoList(FPCSrcDirComboBox,Dirs); end; procedure TInitialSetupDialog.UpdateMakeExeCandidates(aStopIfFits: boolean); var Files: TSDFileInfoList; begin Exclude(FFlags,sdfMakeExeFilenameNeedsUpdate); Files:=SearchMakeExeCandidates(aStopIfFits); FreeAndNil(FCandidates[sddtMakeExeFileName]); FCandidates[sddtMakeExeFileName]:=Files; FillComboboxWithFileInfoList(MakeExeComboBox,Files); end; procedure TInitialSetupDialog.FillComboboxWithFileInfoList(ABox: TComboBox; List: TSDFileInfoList; ItemIndex: integer); var sl: TStringList; i: Integer; begin sl:=TStringList.Create; try if List<>nil then for i:=0 to List.Count-1 do sl.Add(TSDFileInfo(List[i]).Caption); ABox.Items.Assign(sl); if (ItemIndex>=0) and (ItemIndexEnvironmentOptions.GetParsedLazarusDirectory then s:=lisDirectory+EnvironmentOptions.GetParsedLazarusDirectory+LineEnding+ LineEnding+s; LazDirMemo.Text:=s+Note; ImageIndex:=QualityToImgIndex(Quality); TVNodeLazarus.ImageIndex:=ImageIndex; TVNodeLazarus.SelectedIndex:=ImageIndex; FFlags:=FFlags+[sdfCompilerFilenameNeedsUpdate,sdfFPCSrcDirNeedsUpdate, sdfMakeExeFilenameNeedsUpdate,sdfDebuggerFilenameNeedsUpdate]; IdleConnected:=true; end; procedure TInitialSetupDialog.UpdateCompilerNote(aQuiet: boolean); var CurCaption, ParsedC, Note, s: String; Quality: TSDFilenameQuality; ImageIndex: Integer; CfgCache: TPCTargetConfigCache; begin if csDestroying in ComponentState then exit; CurCaption:=CompilerComboBox.Text; EnvironmentOptions.CompilerFilename:=CurCaption; ParsedC:=EnvironmentOptions.GetParsedCompilerFilename; if fLastParsedCompiler=ParsedC then exit; fLastParsedCompiler:=ParsedC; Quality:=CheckFPCExeQuality(fLastParsedCompiler,Note, CodeToolBoss.CompilerDefinesCache.TestFilename); if Quality=sddqCompatible then begin // check compiler again CfgCache:=CodeToolBoss.CompilerDefinesCache.ConfigCaches.Find( fLastParsedCompiler,true); CfgCache.CompilerDate:=0; // force update if CfgCache.NeedsUpdate then CfgCache.Update(CodeToolBoss.CompilerDefinesCache.TestFilename); BuildBoss.SetBuildTargetIDE(aQuiet); end; case Quality of sddqInvalid: s:=lisError; sddqCompatible: s:=''; else s:=lisWarning; end; ParsedC:=EnvironmentOptions.GetParsedCompilerFilename; if EnvironmentOptions.CompilerFilename<>ParsedC then s:=lisFile2+ParsedC+LineEnding+LineEnding+s; CompilerMemo.Text:=s+Note; ImageIndex:=QualityToImgIndex(Quality); TVNodeCompiler.ImageIndex:=ImageIndex; TVNodeCompiler.SelectedIndex:=ImageIndex; FFlags:=FFlags+[sdfFPCSrcDirNeedsUpdate, sdfMakeExeFilenameNeedsUpdate,sdfDebuggerFilenameNeedsUpdate]; if FppkgTabSheet.TabVisible then Include(FFlags,sdfFppkgConfigFileNeedsUpdate); IdleConnected:=true; end; procedure TInitialSetupDialog.UpdateFPCSrcDirNote; var CurCaption: String; Note: string; Quality: TSDFilenameQuality; s: String; ImageIndex: Integer; begin if csDestroying in ComponentState then exit; CurCaption:=FPCSrcDirComboBox.Text; CurCaption:=ChompPathDelim(CurCaption); EnvironmentOptions.FPCSourceDirectory:=CurCaption; if fLastParsedFPCSrcDir=EnvironmentOptions.GetParsedFPCSourceDirectory then exit; fLastParsedFPCSrcDir:=EnvironmentOptions.GetParsedFPCSourceDirectory; //debugln(['TInitialSetupDialog.UpdateFPCSrcDirNote ',fLastParsedFPCSrcDir]); Quality:=CheckFPCSrcDirQuality(fLastParsedFPCSrcDir,Note,GetFPCVer); case Quality of sddqInvalid: s:=lisError; sddqCompatible: s:=''; else s:=lisWarning; end; if EnvironmentOptions.FPCSourceDirectory<>EnvironmentOptions.GetParsedFPCSourceDirectory then s:=lisDirectory+EnvironmentOptions.GetParsedFPCSourceDirectory+LineEnding+ LineEnding+s; s+=Note; if Quality<>sddqCompatible then s+=#13+lisYouCanDownloadFPCAndTheFPCSourcesFromHttpSourcefor; FPCSrcDirMemo.Text:=s; ImageIndex:=QualityToImgIndex(Quality); TVNodeFPCSources.ImageIndex:=ImageIndex; TVNodeFPCSources.SelectedIndex:=ImageIndex; end; procedure TInitialSetupDialog.UpdateMakeExeNote; var CurCaption: String; Note: string; Quality: TSDFilenameQuality; s: String; ImageIndex: Integer; begin if csDestroying in ComponentState then exit; CurCaption:=MakeExeComboBox.Text; EnvironmentOptions.MakeFilename:=CurCaption; if fLastParsedMakeExe=EnvironmentOptions.GetParsedMakeFilename then exit; fLastParsedMakeExe:=EnvironmentOptions.GetParsedMakeFilename; //debugln(['TInitialSetupDialog.UpdateMakeExeNote ',fLastParsedMakeExe]); Quality:=CheckMakeExeQuality(fLastParsedMakeExe,Note); case Quality of sddqInvalid: s:=lisError; sddqCompatible: s:=''; else s:=lisWarning; end; if EnvironmentOptions.MakeFilename<>EnvironmentOptions.GetParsedMakeFilename then s:=lisFile2+EnvironmentOptions.GetParsedMakeFilename+LineEnding+ LineEnding+s; MakeExeMemo.Text:=s+Note; ImageIndex:=QualityToImgIndex(Quality); TVNodeMakeExe.ImageIndex:=ImageIndex; TVNodeMakeExe.SelectedIndex:=ImageIndex; IdleConnected:=true; end; function TInitialSetupDialog.FirstErrorNode: TTreeNode; var i: Integer; begin for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do begin Result:=PropertiesTreeView.Items.TopLvlItems[i]; if Result.ImageIndex=ImgIDFatal then exit; end; for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do begin Result:=PropertiesTreeView.Items.TopLvlItems[i]; if Result.ImageIndex=ImgIDError then exit; end; Result:=FirstWarningNode; end; function TInitialSetupDialog.FirstWarningNode: TTreeNode; var i: Integer; begin for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do begin Result:=PropertiesTreeView.Items.TopLvlItems[i]; if Result.ImageIndex=ImgIDWarning then exit; end; for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do begin Result:=PropertiesTreeView.Items.TopLvlItems[i]; if Result.ImageIndex=ImgIDNote then exit; end; for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do begin Result:=PropertiesTreeView.Items.TopLvlItems[i]; if Result.ImageIndex=ImgIDHint then exit; end; for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do begin Result:=PropertiesTreeView.Items.TopLvlItems[i]; if Result.ImageIndex=ImgIDInfo then exit; end; Result:=nil; end; function TInitialSetupDialog.GetFirstCandidate(Candidates: TSDFileInfoList; MinQuality: TSDFilenameQuality): TSDFileInfo; var i: Integer; begin if Candidates<>nil then for i:=0 to Candidates.Count-1 do begin Result:=TSDFileInfo(Candidates[i]); if Result.Quality>=MinQuality then exit; end; Result:=nil; end; function TInitialSetupDialog.QualityToImgIndex(Quality: TSDFilenameQuality): integer; begin if Quality=sddqCompatible then Result:=-1 else if Quality=sddqWrongMinorVersion then Result:=ImgIDWarning else if Quality=sddqIncomplete then Result:=ImgIDWarning else if Quality=sddqMakeNotWithFpc then Result:=ImgIDWarning else if Quality=sddqHint then Result:=ImgIDHint else Result:=ImgIDError; end; procedure TInitialSetupDialog.ShowHideScanControls(aShow: Boolean); begin // Show ProgressBar and Stop button durin scanning ScanLabel.Visible:=aShow; ScanProgressBar.Visible:=aShow; StopScanButton.Visible:=aShow; // At the same time disable other GUI controls so a user can not mess with it StartIDEBitBtn.Enabled:=not aShow; FPCSrcDirBrowseButton.Enabled:=not aShow; FPCSrcDirComboBox.Enabled:=not aShow; // FPCSrcDirMemo.Enabled:=not aShow; end; procedure TInitialSetupDialog.ThreadTerminated(Sender: TObject); begin debugln(['TInitialSetupDialog.ThreadTerminated ']); fSearchFpcSourceThread:=nil; // Thread will free itself. Make the variable nil, too. ShowHideScanControls(false); end; procedure TInitialSetupDialog.TranslateResourceStrings; begin IDETranslations.TranslateResourceStrings( EnvironmentOptions.GetParsedLazarusDirectory, EnvironmentOptions.LanguageID); UpdateCaptions; end; constructor TInitialSetupDialog.Create(TheOwner: TComponent); begin inherited Create(TheOwner); FSetupDlgFrameMap := TSetupDlgFrameMap.Create; FSetupDlgGroupMap := TGroupMap.Create; FInitDebuggerFrame := TInitDebuggerFrame.Create(Self); FInitDebuggerFrame.Parent := DebuggerTabSheet; FInitDebuggerFrame.Align := alClient; FInitDebuggerFrame.OnStateChanged := @DoDbgFrameStateChanged; FInitDebuggerFrame.Init; end; destructor TInitialSetupDialog.Destroy; var i: Integer; begin for i := 0 to SetupDlgFrameList.Count - 1 do SetupDlgFrameList[i].Done; inherited Destroy; FSetupDlgFrameMap.Free; FSetupDlgGroupMap.Free; end; procedure TInitialSetupDialog.Init; var Node: TTreeNode; Candidate: TSDFileInfo; IsFirstStart: Boolean; PrimaryFilename: String; SecondaryFilename: String; PrimaryEnvs: TStringList; SecondaryEnvs: TStringList; i: Integer; begin IsFirstStart:=not FileExistsCached(EnvironmentOptions.Filename); if not IsFirstStart then begin IsFirstStart:= False; PrimaryFilename:=EnvironmentOptions.Filename; SecondaryFilename:=AppendPathDelim(GetSecondaryConfigPath)+ExtractFilename(PrimaryFilename); if FileExistsUTF8(PrimaryFilename) and FileExistsUTF8(SecondaryFilename) then begin // compare content of primary and secondary config PrimaryEnvs:=TStringList.Create; SecondaryEnvs:=TStringList.Create; try PrimaryEnvs.LoadFromFile(PrimaryFilename); except on E: Exception do debugln(['TInitialSetupDialog.Init unable to read "'+PrimaryFilename+'": '+E.Message]); end; try SecondaryEnvs.LoadFromFile(SecondaryFilename); except on E: Exception do debugln(['TInitialSetupDialog.Init unable to read "'+SecondaryFilename+'": '+E.Message]); end; // IsFirstStart:=PrimaryEnvs.Text=SecondaryEnvs.Text; PrimaryEnvs.Free; SecondaryEnvs.Free; end; end else IsFirstStart := True; //debugln(['TInitialSetupDialog.Init IsFirstStart=',IsFirstStart,' ',EnvironmentOptions.Filename]); // Lazarus directory UpdateLazarusDirCandidates; if IsFirstStart or (not FileExistsCached(EnvironmentOptions.GetParsedLazarusDirectory)) then begin // first start => choose first best candidate Candidate:=GetFirstCandidate(FCandidates[sddtLazarusSrcDir]); if Candidate<>nil then begin EnvironmentOptions.LazarusDirectory:=Candidate.Caption; if Candidate.Quality=sddqCompatible then TranslateResourceStrings; end; end; LazDirComboBox.Text:=EnvironmentOptions.LazarusDirectory; FLastParsedLazDir:='. .'; UpdateLazDirNote; // compiler filename UpdateCompilerFilenameCandidates; if IsFirstStart or (EnvironmentOptions.CompilerFilename='') or (not FileExistsCached(EnvironmentOptions.GetParsedCompilerFilename)) then begin // first start => choose first best candidate Candidate:=GetFirstCandidate(FCandidates[sddtCompilerFilename]); if Candidate<>nil then EnvironmentOptions.CompilerFilename:=Candidate.Caption; end; CompilerComboBox.Text:=EnvironmentOptions.CompilerFilename; fLastParsedCompiler:='. .'; UpdateCompilerNote; // FPC source directory UpdateFPCSrcDirCandidates; {$IFDEF DebugSearchFPCSrcThread} IsFirstStart:=true; {$ENDIF} if IsFirstStart or (EnvironmentOptions.FPCSourceDirectory='') or (not FileExistsCached(EnvironmentOptions.GetParsedFPCSourceDirectory)) then begin // first start => choose first best candidate {$IFDEF DebugSearchFPCSrcThread} Candidate:=nil; {$ELSE} Candidate:=GetFirstCandidate(FCandidates[sddtFPCSrcDir]); {$ENDIF} if Candidate<>nil then begin EnvironmentOptions.FPCSourceDirectory:=Candidate.Caption; end else begin // No candidates found => start a thread to scan the file system. {$IFNDEF LCLCarbon} // carbon interface does not support Synchronize outside Application.Run StartFPCSrcThread; SelectPage(TVNodeFPCSources); {$ENDIF} end; end; ShowHideScanControls(fSearchFpcSourceThread<>nil); FPCSrcDirComboBox.Text:=EnvironmentOptions.FPCSourceDirectory; fLastParsedFPCSrcDir:='. .'; UpdateFPCSrcDirNote; // Make executable UpdateMakeExeCandidates({aStopIfFits} True); if IsFirstStart or (EnvironmentOptions.MakeFilename='') or (not FileExistsCached(EnvironmentOptions.GetParsedMakeFilename)) then begin // first start => choose first best candidate Candidate:=GetFirstCandidate(FCandidates[sddtMakeExeFilename]); if Candidate<>nil then EnvironmentOptions.MakeFilename:=Candidate.Caption else begin // second chance => better an incomplete instead of none (especially for windows) Candidate:=GetFirstCandidate(FCandidates[sddtMakeExeFilename], sddqIncomplete); if Candidate<>nil then EnvironmentOptions.MakeFilename:=Candidate.Caption; end; end; MakeExeComboBox.Text:=EnvironmentOptions.MakeFilename; fLastParsedMakeExe:='. .'; UpdateMakeExeNote; // Debugger DoDbgFrameStateChanged(FInitDebuggerFrame.UpdateState); // Fppkg fLastParsedFppkgConfigFile := ' '; if FppkgTabSheet.TabVisible then begin FppkgComboBox.Text := EnvironmentOptions.FppkgConfigFile; UpdateFppkgCandidates; UpdateFppkgNote; end; for i := 0 to SetupDlgFrameList.Count - 1 do SetupDlgFrameList[i].Init; for i := 0 to SetupDlgFrameList.Count - 1 do SetupDlgFrameList[i].UpdateState; // select first error Node:=FirstErrorNode; if Node=nil then Node:=TVNodeLazarus; SelectPage(Node); end; procedure TInitialSetupDialog.UpdateFppkgNote; var CurCaption: String; FppkgMsg, Note: string; Quality: TSDFilenameQuality; ConfigFile: string; ImageIndex: Integer; begin if csDestroying in ComponentState then exit; if not FppkgTabSheet.TabVisible then exit; CurCaption:=FppkgComboBox.Text; EnvironmentOptions.FppkgConfigFile:=CurCaption; if fLastParsedFppkgConfigFile=EnvironmentOptions.GetParsedFppkgConfig then exit; fLastParsedFppkgConfigFile:=EnvironmentOptions.GetParsedFppkgConfig; ConfigFile := fLastParsedFppkgConfigFile; Quality := CheckFppkgConfigFile(ConfigFile, Note); if Quality<>sddqCompatible then begin Note := lisError + Note + LineEnding; FppkgWriteConfigButton.Enabled := (Quality=sddqIncomplete); end else begin Quality := CheckFppkgConfiguration(ConfigFile, FppkgMsg); if Quality=sddqCompatible then begin Note := lisOk; FppkgWriteConfigButton.Enabled := False; end else begin Note := lisError + Format(lisIncorrectFppkgConfiguration, [FppkgMsg]) + LineEnding; Note := Note + LineEnding + lisFppkgFixConfiguration; FppkgWriteConfigButton.Enabled := True; end; end; FppkgMemo.Text := lisFile2 + ConfigFile + LineEnding + LineEnding + Note; ImageIndex:=QualityToImgIndex(Quality); TVNodeFppkg.ImageIndex:=ImageIndex; TVNodeFppkg.SelectedIndex:=ImageIndex; IdleConnected:=true; end; procedure TInitialSetupDialog.FppkgComboBoxChange(Sender: TObject); begin UpdateFppkgNote; end; procedure TInitialSetupDialog.UpdateFppkgCandidates; function SearchFppkgFpcPrefixCandidates: TSDFileInfoList; function CheckFile(AFile: string; var List: TSDFileInfoList): boolean; var Item: TSDFileInfo; begin Result:=false; if AFile='' then exit; ForcePathDelims(AFile); // check if already checked if Assigned(List) and List.CaptionExists(AFile) then exit; if FileExistsUTF8(AFile) then begin if List=nil then List:=TSDFileInfoList.create(true); Item:=List.AddNewItem(AFile, AFile); Item.Quality:=sddqCompatible; Result := True; end; end; begin Result:=nil; CheckFile(GetFppkgConfigFile(False, False), Result); CheckFile(GetFppkgConfigFile(False, True), Result); CheckFile(GetFppkgConfigFile(True, False), Result); CheckFile(GetFppkgConfigFile(True, True), Result); end; var Files: TSDFileInfoList; begin Exclude(FFlags,sdfFppkgConfigFileNeedsUpdate); if not FppkgTabSheet.TabVisible then exit; Files:=SearchFppkgFpcPrefixCandidates; FreeAndNil(FCandidates[sddtFppkgFpcPrefix]); FCandidates[sddtFppkgFpcPrefix]:=Files; FillComboboxWithFileInfoList(FppkgComboBox,Files,-1); end; procedure TInitialSetupDialog.FppkgBrowseButtonClick(Sender: TObject); var lExpandedName: string; // Expanded name before Dialog lDirName, lFileName: string; lTitle: string; lChanged: boolean=False; Dlg: TIDEOpenDialog; Filter: String; begin if not FppkgTabSheet.TabVisible then exit; Dlg:=IDEOpenDialogClass.Create(nil); try lTitle:='fppkg.cfg'; Dlg.Title:=SimpleFormat(lisSelectPathTo, [lTitle]); lExpandedName:=EnvironmentOptions.GetParsedValue(eopFppkgConfigFile, FppkgComboBox.Text); lDirName := GetValidDirectory(lExpandedName, {out} lFileName); Dlg.Options:=Dlg.Options+[ofFileMustExist]; if lFileName='' then lFileName:=lTitle; Filter:=dlgFilterAll+'|'+GetAllFilesMask; if ExtractFileExt(lFileName)<>'' then Filter:=dlgFilterExecutable+'|*'+ExtractFileExt(lFileName)+'|'+Filter; Dlg.Filter:=Filter; Dlg.InitialDir:=lDirName; Dlg.FileName:=lFileName; if not Dlg.Execute then exit; lFileName:=CleanAndExpandFilename(Dlg.Filename); lChanged := UpperCase(lExpandedName)<>UpperCase(lFileName); finally Dlg.Free; end; if lChanged then begin // Avoid loosing $(macros) FppkgComboBox.Text:=lFileName; UpdateFppkgNote; end; end; procedure TInitialSetupDialog.FppkgWriteConfigButtonClick(Sender: TObject); var Dialog: TGenerateFppkgConfigurationDialog; begin if not FppkgTabSheet.TabVisible then exit; Dialog := TGenerateFppkgConfigurationDialog.Create(Self); try Dialog.Compiler := fLastParsedCompiler; if fLastParsedFppkgConfigFile='' then Dialog.FppkgCfgFilename := GetFppkgConfigFile(False, False) else Dialog.FppkgCfgFilename := fLastParsedFppkgConfigFile; Dialog.ShowModal; finally Dialog.Free; end; fLastParsedFppkgConfigFile := ' '; UpdateFppkgNote; end; end.