PageRenderTime 46ms CodeModel.GetById 34ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 1ms

/ide/initialsetupdlgs.pas

http://github.com/graemeg/lazarus
Pascal | 1333 lines | 1099 code | 125 blank | 109 comment | 144 complexity | a4a8e2c55d6bee42d9c3583263315442 MD5 | raw file
   1{
   2 /***************************************************************************
   3                            initialsetupdlgs.pas
   4                            --------------------
   5       Contains the dialogs to help users setup basic settings.
   6
   7
   8 ***************************************************************************/
   9
  10 ***************************************************************************
  11 *                                                                         *
  12 *   This source is free software; you can redistribute it and/or modify   *
  13 *   it under the terms of the GNU General Public License as published by  *
  14 *   the Free Software Foundation; either version 2 of the License, or     *
  15 *   (at your option) any later version.                                   *
  16 *                                                                         *
  17 *   This code is distributed in the hope that it will be useful, but      *
  18 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
  19 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
  20 *   General Public License for more details.                              *
  21 *                                                                         *
  22 *   A copy of the GNU General Public License is available on the World    *
  23 *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
  24 *   obtain it by writing to the Free Software Foundation,                 *
  25 *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
  26 *                                                                         *
  27 ***************************************************************************
  28
  29  Author: Mattias Gaertner
  30  
  31  Abstract:
  32    Contains the dialogs to help users setup basic settings.
  33}
  34unit InitialSetupDlgs;
  35
  36{$mode objfpc}{$H+}
  37
  38{off $DEFINE VerboseFPCSrcScanThead}
  39
  40interface
  41
  42uses
  43  // RTL + FCL + LCL
  44  Classes, SysUtils,
  45  Forms, Controls, Buttons, Dialogs, Graphics, ComCtrls, ExtCtrls, StdCtrls, LCLProc,
  46  // CodeTools
  47  FileProcs, CodeToolManager, DefineTemplates,
  48  // LazUtils
  49  FileUtil, LazUTF8, LazUTF8Classes, LazFileUtils, LazFileCache, LazLogger,
  50  // Other
  51  MacroDefIntf, GDBMIDebugger, DbgIntfDebuggerBase,
  52  TransferMacros, LazarusIDEStrConsts, LazConf, EnvironmentOpts,
  53  AboutFrm, IDETranslations, BaseBuildManager, InitialSetupProc;
  54  
  55type
  56  TInitialSetupDialog = class;
  57
  58  { TSearchFpcSourceThread }
  59
  60  TSearchFpcSourceThread = class(TThread)
  61  private
  62    fSetupDialog: TInitialSetupDialog;
  63    fFPCVer: string;
  64    fFoundFPCSrc: TSDFileInfo;
  65    {$IFDEF VerboseFPCSrcScanThead}
  66    fPath: string;
  67    fFileInfo: TSearchRec;
  68    procedure Debug;
  69    {$ENDIF}
  70    function CheckFPCSrcDir(Dir: string): TSDFileInfo;
  71    procedure DoSearch(const APath: String);
  72    procedure UpdateFPCSrcDir;
  73    procedure Finishing;
  74  protected
  75    procedure Execute; override;
  76  public
  77    constructor Create(aSetupDialog: TInitialSetupDialog);
  78    destructor Destroy; override;
  79  end;
  80
  81  { TInitialSetupDialog }
  82
  83  TInitialSetupDialog = class(TForm)
  84    BtnPanel: TPanel;
  85    CompilerBrowseButton: TButton;
  86    CompilerComboBox: TComboBox;
  87    CompilerLabel: TLabel;
  88    CompilerMemo: TMemo;
  89    CompilerTabSheet: TTabSheet;
  90    DebuggerBrowseButton: TButton;
  91    DebuggerComboBox: TComboBox;
  92    DebuggerLabel: TLabel;
  93    DebuggerMemo: TMemo;
  94    DebuggerTabSheet: TTabSheet;
  95    FPCSourcesTabSheet: TTabSheet;
  96    FPCSrcDirBrowseButton: TButton;
  97    FPCSrcDirComboBox: TComboBox;
  98    FPCSrcDirLabel: TLabel;
  99    FPCSrcDirMemo: TMemo;
 100    ImageList1: TImageList;
 101    LazarusTabSheet: TTabSheet;
 102    LazDirBrowseButton: TButton;
 103    LazDirComboBox: TComboBox;
 104    LazDirLabel: TLabel;
 105    LazDirMemo: TMemo;
 106    MakeExeBrowseButton: TButton;
 107    MakeExeComboBox: TComboBox;
 108    MakeExeLabel: TLabel;
 109    MakeExeMemo: TMemo;
 110    MakeExeTabSheet: TTabSheet;
 111    PropertiesPageControl: TPageControl;
 112    PropertiesTreeView: TTreeView;
 113    ScanLabel: TLabel;
 114    ScanProgressBar: TProgressBar;
 115    Splitter1: TSplitter;
 116    StartIDEBitBtn: TBitBtn;
 117    StopScanButton: TBitBtn;
 118    WelcomePaintBox: TPaintBox;
 119    procedure CompilerBrowseButtonClick(Sender: TObject);
 120    procedure CompilerComboBoxChange(Sender: TObject);
 121    procedure DebuggerBrowseButtonClick(Sender: TObject);
 122    procedure DebuggerComboBoxChange(Sender: TObject);
 123    procedure FormCreate(Sender: TObject);
 124    procedure FormDestroy(Sender: TObject);
 125    procedure FPCSrcDirBrowseButtonClick(Sender: TObject);
 126    procedure FPCSrcDirComboBoxChange(Sender: TObject);
 127    procedure LazDirBrowseButtonClick(Sender: TObject);
 128    procedure LazDirComboBoxChange(Sender: TObject);
 129    procedure MakeExeBrowseButtonClick(Sender: TObject);
 130    procedure MakeExeComboBoxChange(Sender: TObject);
 131    procedure OnAppActivate(Sender: TObject);
 132    procedure PropertiesPageControlChange(Sender: TObject);
 133    procedure PropertiesTreeViewSelectionChanged(Sender: TObject);
 134    procedure StartIDEBitBtnClick(Sender: TObject);
 135    procedure StopScanButtonClick(Sender: TObject);
 136    procedure WelcomePaintBoxPaint(Sender: TObject);
 137    procedure OnIdle(Sender: TObject; var {%H-}Done: Boolean);
 138  private
 139    FFlags: TSDFlags;
 140    FLastParsedLazDir: string;
 141    fLastParsedCompiler: string;
 142    fLastParsedFPCSrcDir: string;
 143    fLastParsedMakeExe: string;
 144    fLastParsedDebugger: string;
 145    FIdleConnected: boolean;
 146    ImgIDError: LongInt;
 147    ImgIDWarning: LongInt;
 148    FHeadGraphic: TPortableNetworkGraphic;
 149    FInitialDebuggerFileName: String;
 150    FSelectingPage: boolean;
 151    FCandidates: array[TSDFilenameType] of TSDFileInfoList; // list of TSDFileInfo
 152    fSearchFpcSourceThread: TSearchFpcSourceThread;
 153    procedure UpdateCaptions;
 154    procedure SelectPage(const NodeText: string);
 155    function SelectDirectory(aTitle: string): string;
 156    procedure StartFPCSrcThread;
 157    procedure UpdateLazarusDirCandidates;
 158    procedure UpdateCompilerFilenameCandidates;
 159    procedure UpdateFPCSrcDirCandidates;
 160    procedure UpdateFPCSrcDirCandidate(aFPCSrcDirInfo: TSDFileInfo);
 161    procedure UpdateMakeExeCandidates;
 162    procedure UpdateDebuggerCandidates;
 163    procedure FillComboboxWithFileInfoList(ABox: TComboBox; List: TSDFileInfoList;
 164       ItemIndex: integer = 0);
 165    procedure SetIdleConnected(const AValue: boolean);
 166    procedure UpdateLazDirNote;
 167    procedure UpdateCompilerNote;
 168    procedure UpdateFPCSrcDirNote;
 169    procedure UpdateMakeExeNote;
 170    procedure UpdateDebuggerNote;
 171    function FirstErrorNode: TTreeNode;
 172    function GetFPCVer: string;
 173    function GetFirstCandidate(Candidates: TSDFileInfoList;
 174      MinQuality: TSDFilenameQuality = sddqCompatible): TSDFileInfo;
 175    function QualityToImgIndex(Quality: TSDFilenameQuality): integer;
 176    procedure ShowHideScanControls(aShow: Boolean);
 177    procedure ThreadTerminated(Sender: TObject); // called in main thread by fSearchFpcSourceThread.OnTerminate
 178    procedure TranslateResourceStrings;
 179  public
 180    TVNodeLazarus: TTreeNode;
 181    TVNodeCompiler: TTreeNode;
 182    TVNodeFPCSources: TTreeNode;
 183    TVNodeMakeExe: TTreeNode;
 184    TVNodeDebugger: TTreeNode;
 185    procedure Init; //Check for config errors, find and show alternatives
 186    property IdleConnected: boolean read FIdleConnected write SetIdleConnected;
 187  end;
 188
 189
 190function ShowInitialSetupDialog: TModalResult;
 191
 192// Debugger
 193// Checks a given file to see if it is a valid debugger (only gdb supported for now)
 194function CheckDebuggerQuality(AFilename: string; out Note: string): TSDFilenameQuality;
 195// Search debugger candidates and add them to list, including quality level
 196function SearchDebuggerCandidates(StopIfFits: boolean): TSDFileInfoList;
 197
 198implementation
 199
 200const
 201  DefaultDebuggerClass: TDebuggerClass = TGDBMIDebugger;
 202
 203type
 204
 205  { TSetupMacros }
 206
 207  TSetupMacros = class(TTransferMacroList)
 208  protected
 209    procedure DoSubstitution({%H-}TheMacro: TTransferMacro; const MacroName: string;
 210      var s: string; const {%H-}Data: PtrInt; var Handled, {%H-}Abort: boolean;
 211      {%H-}Depth: integer); override;
 212  public
 213    FPCVer: string;
 214    LazarusDir: string;
 215  end;
 216
 217function CheckDebuggerQuality(AFilename: string; out Note: string): TSDFilenameQuality;
 218begin
 219  Result:=sddqInvalid;
 220  AFilename:=TrimFilename(AFilename);
 221  if not FileExistsCached(AFilename) then
 222  begin
 223    Note:=lisFileNotFound4;
 224    exit;
 225  end;
 226  if DirPathExistsCached(AFilename) then
 227  begin
 228    Note:=lisFileIsDirectory;
 229    exit;
 230  end;
 231  if not FileIsExecutableCached(AFilename) then
 232  begin
 233    Note:=lisFileIsNotAnExecutable;
 234    exit;
 235  end;
 236
 237  { We could call gdb and parse the output looking for something like
 238  GNU gdb, but that may be going too far. }
 239  Note:=lisOk;
 240  Result:=sddqCompatible;
 241end;
 242
 243function SearchDebuggerCandidates(StopIfFits: boolean): TSDFileInfoList;
 244
 245  function CheckFile(AFilename: string; var List: TSDFileInfoList): boolean;
 246  var
 247    Item: TSDFileInfo;
 248    RealFilename: String;
 249  begin
 250    Result:=false;
 251    if AFilename='' then exit;
 252    ForcePathDelims(AFilename);
 253    // check if already checked
 254    if Assigned(List) and List.CaptionExists(AFilename) then exit;
 255    EnvironmentOptions.DebuggerFilename:=AFilename;
 256    RealFilename:=EnvironmentOptions.GetParsedDebuggerFilename;
 257    debugln(['SearchDebuggerCandidates Value=',AFilename,' File=',RealFilename]);
 258    if RealFilename='' then exit;
 259    // check if exists
 260    if not FileExistsCached(RealFilename) then exit;
 261    // add to list and check quality
 262    if List=nil then
 263      List:=TSDFileInfoList.create(true);
 264    Item:=List.AddNewItem(RealFilename, AFilename);
 265    Item.Quality:=CheckDebuggerQuality(RealFilename, Item.Note);
 266    Result:=(Item.Quality=sddqCompatible) and StopIfFits;
 267  end;
 268
 269const
 270  DebuggerFileName='gdb'; //For Windows, .exe will be appended
 271var
 272  OldDebuggerFilename: String;
 273  s, AFilename: String;
 274  Files: TStringList;
 275  i: Integer;
 276begin
 277  Result:=nil;
 278
 279  OldDebuggerFilename:=EnvironmentOptions.DebuggerFilename;
 280  try
 281    // check current setting
 282    if CheckFile(EnvironmentOptions.DebuggerFilename,Result) then exit;
 283
 284    // check the primary options
 285    AFilename:=GetValueFromPrimaryConfig(EnvOptsConfFileName,
 286                                    'EnvironmentOptions/DebuggerFilename/Value');
 287    if CheckFile(AFilename,Result) then exit;
 288
 289    // check the secondary options
 290    AFilename:=GetValueFromSecondaryConfig(EnvOptsConfFileName,
 291                                    'EnvironmentOptions/DebuggerFilename/Value');
 292    if CheckFile(AFilename,Result) then exit;
 293
 294    // Check locations proposed by debugger class
 295    s := DefaultDebuggerClass.ExePaths;
 296    while s <> '' do begin
 297      AFilename := GetPart([], [';'], s);
 298      if CheckFile(AFilename, Result) then exit;
 299      if s <> '' then delete(s, 1, 1);
 300    end;
 301
 302
 303    // Windows-only locations:
 304    if (GetDefaultSrcOSForTargetOS(GetCompiledTargetOS)='win') then begin
 305      // check for debugger in fpc.exe directory - could be a lucky shot
 306      if CheckFile(SetDirSeparators('$Path($(CompPath))/'+DebuggerFileName+GetExecutableExt),Result)
 307        then exit;
 308    end;
 309
 310    // check history
 311    Files:=EnvironmentOptions.DebuggerFileHistory;
 312    if Files<>nil then
 313      for i:=0 to Files.Count-1 do
 314        if CheckFile(Files[i],Result) then exit;
 315
 316    // check PATH
 317    AFilename:=DebuggerFileName+GetExecutableExt;
 318    if CheckFile(AFilename,Result) then exit;
 319
 320    // There are no common directories apart from the PATH
 321    // where gdb would be installed. Otherwise we could do something similar as
 322    // in SearchMakeExeCandidates.
 323  finally
 324    EnvironmentOptions.DebuggerFilename:=OldDebuggerFilename;
 325  end;
 326end;
 327
 328function ShowInitialSetupDialog: TModalResult;
 329var
 330  InitialSetupDialog: TInitialSetupDialog;
 331begin
 332  InitialSetupDialog:=TInitialSetupDialog.Create(nil);
 333  try
 334    Application.TaskBarBehavior:=tbMultiButton;
 335    InitialSetupDialog.Init;
 336    Result:=InitialSetupDialog.ShowModal;
 337  finally
 338    InitialSetupDialog.Free;
 339    Application.TaskBarBehavior:=tbDefault;
 340  end;
 341end;
 342
 343{ TSearchFpcSourceThread }
 344
 345constructor TSearchFpcSourceThread.Create(aSetupDialog: TInitialSetupDialog);
 346begin
 347  inherited Create(True);
 348  FreeOnTerminate:=True;
 349  fSetupDialog:=aSetupDialog;
 350end;
 351
 352destructor TSearchFpcSourceThread.Destroy;
 353begin
 354  inherited Destroy;
 355end;
 356
 357procedure TSearchFpcSourceThread.Execute;
 358var
 359  RootDir: String;
 360begin
 361  // ToDo: RootDir must be changed for Windows and maybe other systems.
 362  //       GetUserDir returns the user profile dir on Windows.
 363  RootDir:=GetUserDir;
 364  // Scan directories under root directory.
 365  DoSearch(AppendPathDelim(RootDir));
 366  if Assigned(fFoundFPCSrc) then
 367    Synchronize(@UpdateFPCSrcDir); // Update GUI in main thread.
 368  Synchronize(@Finishing);
 369end;
 370
 371function TSearchFpcSourceThread.CheckFPCSrcDir(Dir: string): TSDFileInfo;
 372var
 373  RealDir: String;
 374begin
 375  Result:=Nil;
 376  RealDir:=TrimFilename(Dir);
 377  if RealDir='' then exit;
 378  if not DirPathExistsCached(RealDir) then exit;   // check if exists
 379  Result:=TSDFileInfo.Create;
 380  Result.Filename:=RealDir;
 381  Result.Caption:=Dir;                             // check quality
 382  Result.Quality:=CheckFPCSrcDirQuality(RealDir, Result.Note, fFPCVer, False);
 383  if Result.Quality<>sddqCompatible then           // return only exact matches
 384    FreeAndNil(Result);
 385end;
 386
 387procedure TSearchFpcSourceThread.DoSearch(const APath: String);
 388var
 389  PathInfo: TSearchRec;
 390  FPCSrc: TSDFileInfo;
 391begin
 392  if FindFirstUTF8(APath+AllDirectoryEntriesMask, faDirectory, PathInfo) = 0 then
 393  try
 394    repeat
 395      if Terminated then Break;
 396      if (PathInfo.Name='') or (PathInfo.Name[1]='.')
 397      or ((PathInfo.Attr and faDirectory) = 0) then Continue;
 398      {$IFDEF VerboseFPCSrcScanThead}
 399      fPath := APath;
 400      fFileInfo := PathInfo;
 401      Synchronize(@Debug);
 402      {$ENDIF}
 403      DoSearch(AppendPathDelim(APath+PathInfo.Name));  // Recursive call
 404      FPCSrc:=CheckFPCSrcDir(APath+PathInfo.Name);
 405      if Assigned(FPCSrc) then begin
 406        fFoundFPCSrc:=FPCSrc;                 // An exact match was found.
 407        Terminate;
 408      end;
 409    until (FindNextUTF8(PathInfo) <> 0);
 410  finally
 411    FindCloseUTF8(PathInfo);
 412  end;
 413end;
 414
 415{$IFDEF VerboseFPCSrcScanThead}
 416procedure TSearchFpcSourceThread.Debug;
 417begin
 418  DebugLn(['* TSearchFpcSourceThread.Debug: Path=', fPath, ', Name=', fFileInfo.Name]);
 419end;
 420{$ENDIF}
 421
 422procedure TSearchFpcSourceThread.UpdateFPCSrcDir;
 423begin
 424  DebugLn(['TSearchFpcSourceThread.UpdateFPCSrcDir']);
 425  fSetupDialog.UpdateFPCSrcDirCandidate(fFoundFPCSrc);
 426  fSetupDialog.UpdateFPCSrcDirNote;
 427end;
 428
 429procedure TSearchFpcSourceThread.Finishing;
 430begin
 431  DebugLn(['TSearchFpcSourceThread.Finishing']);
 432  fSetupDialog.ShowHideScanControls(False); // Hide scan controls
 433end;
 434
 435{ TSetupMacros }
 436
 437procedure TSetupMacros.DoSubstitution(TheMacro: TTransferMacro;
 438  const MacroName: string; var s: string; const Data: PtrInt; var Handled,
 439  Abort: boolean; Depth: integer);
 440begin
 441  Handled:=true;
 442  if CompareText(MacroName,'ENV')=0 then
 443    s:=GetEnvironmentVariableUTF8(MacroName)
 444  else if CompareText(MacroName,'PrimaryConfigPath')=0 then
 445    s:=GetPrimaryConfigPath
 446  else if CompareText(MacroName,'SecondaryConfigPath')=0 then
 447    s:=GetSecondaryConfigPath
 448  else if CompareText(MacroName,'FPCVer')=0 then begin
 449    if FPCVer<>'' then
 450      s:=FPCVer
 451    else
 452      s:={$I %FPCVERSION%};
 453  end else if CompareText(MacroName,'LazarusDir')=0 then begin
 454    if LazarusDir<>'' then
 455      s:=LazarusDir
 456    else
 457      s:='<LazarusDirNotSet>';
 458  end else if (CompareText(MacroName,'TargetOS')=0) then
 459    s:=GetCompiledTargetOS
 460  else if (CompareText(MacroName,'TargetCPU')=0) then
 461    s:=GetCompiledTargetCPU
 462  else if (CompareText(MacroName,'SrcOS')=0) then
 463    s:=GetDefaultSrcOSForTargetOS(GetCompiledTargetOS)
 464  else
 465    Handled:=false;
 466  //debugln(['TSetupMacros.DoSubstitution MacroName=',MacroName,' Value="',s,'"']);
 467end;
 468
 469{$R *.lfm}
 470
 471{ TInitialSetupDialog }
 472
 473procedure TInitialSetupDialog.FormCreate(Sender: TObject);
 474begin
 475  LazarusTabSheet.Caption:='Lazarus';
 476  CompilerTabSheet.Caption:=lisCompiler;
 477  FPCSourcesTabSheet.Caption:=lisFPCSources;
 478  MakeExeTabSheet.Caption:='Make';
 479  DebuggerTabSheet.Caption:=lisDebugger;
 480
 481  FHeadGraphic:=TPortableNetworkGraphic.Create;
 482  FHeadGraphic.LoadFromResourceName(HInstance, 'ide_icon48x48');
 483
 484  TVNodeLazarus:=PropertiesTreeView.Items.Add(nil,LazarusTabSheet.Caption);
 485  TVNodeCompiler:=PropertiesTreeView.Items.Add(nil,CompilerTabSheet.Caption);
 486  TVNodeFPCSources:=PropertiesTreeView.Items.Add(nil,FPCSourcesTabSheet.Caption);
 487  TVNodeMakeExe:=PropertiesTreeView.Items.Add(nil,MakeExeTabSheet.Caption);
 488  TVNodeDebugger:=PropertiesTreeView.Items.Add(nil,DebuggerTabSheet.Caption);
 489  ImgIDError := Imagelist1.AddResourceName(HInstance, 'state_error');
 490  ImgIDWarning := Imagelist1.AddResourceName(HInstance, 'state_warning');
 491
 492  StopScanButton.LoadGlyphFromResourceName(HInstance, 'menu_stop');
 493
 494  UpdateCaptions;
 495
 496  Application.AddOnActivateHandler(@OnAppActivate);
 497end;
 498
 499procedure TInitialSetupDialog.CompilerComboBoxChange(Sender: TObject);
 500begin
 501  UpdateCompilerNote;
 502  UpdateFPCSrcDirNote;
 503end;
 504
 505procedure TInitialSetupDialog.DebuggerBrowseButtonClick(Sender: TObject);
 506var
 507  Filename: String;
 508  Dlg: TOpenDialog;
 509  Filter: String;
 510begin
 511  Dlg:=TOpenDialog.Create(nil);
 512  try
 513    Filename:='gdb'+GetExecutableExt;
 514    Dlg.Title:=SimpleFormat(lisSelectPathTo, [Filename]);
 515    Dlg.Options:=Dlg.Options+[ofFileMustExist];
 516    Filter:=dlgFilterAll+'|'+GetAllFilesMask;
 517    if ExtractFileExt(Filename)<>'' then
 518      Filter:=dlgFilterExecutable+'|*'+ExtractFileExt(Filename)+'|'+Filter;
 519    Dlg.Filter:=Filter;
 520    if not Dlg.Execute then exit;
 521    Filename:=Dlg.FileName;
 522  finally
 523    Dlg.Free;
 524  end;
 525  DebuggerComboBox.Text:=Filename;
 526  UpdateDebuggerNote;
 527end;
 528
 529procedure TInitialSetupDialog.DebuggerComboBoxChange(Sender: TObject);
 530begin
 531  UpdateDebuggerNote;
 532end;
 533
 534procedure TInitialSetupDialog.CompilerBrowseButtonClick(Sender: TObject);
 535var
 536  Filename: String;
 537  Dlg: TOpenDialog;
 538  Filter: String;
 539begin
 540  Dlg:=TOpenDialog.Create(nil);
 541  try
 542    Filename:='fpc'+GetExecutableExt;
 543    Dlg.Title:=SimpleFormat(lisSelectPathTo, [Filename]);
 544    Dlg.Options:=Dlg.Options+[ofFileMustExist];
 545    Filter:=dlgFilterAll+'|'+GetAllFilesMask;
 546    if ExtractFileExt(Filename)<>'' then
 547      Filter:=dlgFilterExecutable+'|*'+ExtractFileExt(Filename)+'|'+Filter;
 548    Dlg.Filter:=Filter;
 549    if not Dlg.Execute then exit;
 550    Filename:=Dlg.FileName;
 551  finally
 552    Dlg.Free;
 553  end;
 554  CompilerComboBox.Text:=Filename;
 555  UpdateCompilerNote;
 556end;
 557
 558procedure TInitialSetupDialog.FormDestroy(Sender: TObject);
 559var
 560  d: TSDFilenameType;
 561begin
 562  IdleConnected:=false;
 563  if Assigned(fSearchFpcSourceThread) then begin
 564    fSearchFpcSourceThread.Terminate;
 565    fSearchFpcSourceThread.WaitFor;
 566  end;
 567  for d:=low(FCandidates) to high(FCandidates) do
 568    FreeAndNil(FCandidates[d]);
 569  FreeAndNil(FHeadGraphic);
 570end;
 571
 572procedure TInitialSetupDialog.FPCSrcDirBrowseButtonClick(Sender: TObject);
 573var
 574  Dir: String;
 575begin
 576  Dir:=SelectDirectory(lisSelectFPCSourceDirectory);
 577  if Dir='' then exit;
 578  FPCSrcDirComboBox.Text:=Dir;
 579  UpdateFPCSrcDirNote;
 580end;
 581
 582procedure TInitialSetupDialog.FPCSrcDirComboBoxChange(Sender: TObject);
 583begin
 584  UpdateFPCSrcDirNote;
 585end;
 586
 587procedure TInitialSetupDialog.LazDirBrowseButtonClick(Sender: TObject);
 588var
 589  Dir: String;
 590begin
 591  Dir:=SelectDirectory(lisSelectLazarusSourceDirectory);
 592  if Dir='' then exit;
 593  LazDirComboBox.Text:=Dir;
 594  UpdateLazDirNote;
 595end;
 596
 597procedure TInitialSetupDialog.LazDirComboBoxChange(Sender: TObject);
 598begin
 599  UpdateLazDirNote;
 600end;
 601
 602procedure TInitialSetupDialog.MakeExeBrowseButtonClick(Sender: TObject);
 603var
 604  Filename: String;
 605  Dlg: TOpenDialog;
 606  Filter: String;
 607begin
 608  Dlg:=TOpenDialog.Create(nil);
 609  try
 610    Filename:='make'+GetExecutableExt;
 611    Dlg.Title:=SimpleFormat(lisSelectPathTo, [Filename]);
 612    Dlg.Options:=Dlg.Options+[ofFileMustExist];
 613    Filter:=dlgFilterAll+'|'+GetAllFilesMask;
 614    if ExtractFileExt(Filename)<>'' then
 615      Filter:=dlgFilterExecutable+'|*'+ExtractFileExt(Filename)+'|'+Filter;
 616    Dlg.Filter:=Filter;
 617    if not Dlg.Execute then exit;
 618    Filename:=Dlg.FileName;
 619  finally
 620    Dlg.Free;
 621  end;
 622  MakeExeComboBox.Text:=Filename;
 623  UpdateMakeExeNote;
 624end;
 625
 626procedure TInitialSetupDialog.MakeExeComboBoxChange(Sender: TObject);
 627begin
 628  UpdateMakeExeNote;
 629end;
 630
 631procedure TInitialSetupDialog.OnAppActivate(Sender: TObject);
 632begin
 633  // switched back from another application
 634  InvalidateFileStateCache;
 635end;
 636
 637procedure TInitialSetupDialog.PropertiesPageControlChange(Sender: TObject);
 638var
 639  s: String;
 640  i: Integer;
 641begin
 642  if PropertiesPageControl.ActivePage=nil then exit;
 643  s:=PropertiesPageControl.ActivePage.Caption;
 644  for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do
 645    if PropertiesTreeView.Items.TopLvlItems[i].Text=s then
 646      PropertiesTreeView.Selected:=PropertiesTreeView.Items.TopLvlItems[i];
 647end;
 648
 649procedure TInitialSetupDialog.PropertiesTreeViewSelectionChanged(Sender: TObject);
 650begin
 651  if PropertiesTreeView.Selected=nil then
 652    SelectPage(TVNodeLazarus.Text)
 653  else
 654    SelectPage(PropertiesTreeView.Selected.Text);
 655end;
 656
 657procedure TInitialSetupDialog.StartIDEBitBtnClick(Sender: TObject);
 658var
 659  Node: TTreeNode;
 660  s: String;
 661  MsgResult: TModalResult;
 662begin
 663  Node:=FirstErrorNode;
 664  s:='';
 665  if Node=TVNodeLazarus then
 666    s:=lisWithoutAProperLazarusDirectoryYouWillGetALotOfWarn
 667  else if Node=TVNodeCompiler then
 668    s:=lisWithoutAProperCompilerTheCodeBrowsingAndCompilingW
 669  else if Node=TVNodeFPCSources then
 670    s:=lisWithoutTheProperFPCSourcesCodeBrowsingAndCompletio
 671  else if Node=TVNodeMakeExe then
 672    s:=lisWithoutAProperMakeExecutableTheCompilingOfTheIDEIs
 673  else if Node=TVNodeDebugger then
 674    s:=lisWithoutAProperDebuggerDebuggingWillBeDisappointing;
 675  if s<>'' then begin
 676    MsgResult:=MessageDlg(lisCCOWarningCaption, s, mtWarning, [mbIgnore,
 677      mbCancel], 0);
 678    if MsgResult<>mrIgnore then exit;
 679  end;
 680
 681  s:=LazDirComboBox.Text;
 682  if s<>'' then
 683    EnvironmentOptions.LazarusDirectory:=s;
 684  s:=CompilerComboBox.Text;
 685  if s<>'' then
 686    EnvironmentOptions.CompilerFilename:=s;
 687  s:=FPCSrcDirComboBox.Text;
 688  if s<>'' then
 689    EnvironmentOptions.FPCSourceDirectory:=s;
 690  s:=MakeExeComboBox.Text;
 691  if s<>'' then
 692    EnvironmentOptions.MakeFilename:=s;
 693  s:=DebuggerComboBox.Text;
 694  if s<>'' then begin
 695    EnvironmentOptions.DebuggerFilename:=s;
 696    if s <> FInitialDebuggerFileName then
 697      EnvironmentOptions.DebuggerConfig.DebuggerClass := 'TGDBMIDebugger';
 698  end;
 699
 700  ModalResult:=mrOk;
 701end;
 702
 703procedure TInitialSetupDialog.StopScanButtonClick(Sender: TObject);
 704begin
 705  if fSearchFpcSourceThread<>nil then
 706    fSearchFpcSourceThread.Terminate;
 707end;
 708
 709procedure TInitialSetupDialog.WelcomePaintBoxPaint(Sender: TObject);
 710begin
 711  with WelcomePaintBox.Canvas do begin
 712    GradientFill(WelcomePaintBox.ClientRect,$854b32,$c88e60,gdHorizontal);
 713    Draw(0,WelcomePaintBox.ClientHeight-FHeadGraphic.Height,FHeadGraphic);
 714    Font.Color:=clWhite;
 715    Font.Height:=30;
 716    Brush.Style:=bsClear;
 717    TextOut(FHeadGraphic.Width+15, 5, lisConfigureLazarusIDE);
 718  end;
 719end;
 720
 721procedure TInitialSetupDialog.OnIdle(Sender: TObject; var Done: Boolean);
 722begin
 723  if sdfCompilerFilenameNeedsUpdate in FFlags then begin
 724    UpdateCompilerFilenameCandidates;
 725    UpdateCompilerNote;
 726  end else if sdfFPCSrcDirNeedsUpdate in FFlags then begin
 727    UpdateFPCSrcDirCandidates;
 728    UpdateFPCSrcDirNote;
 729  end else if sdfMakeExeFilenameNeedsUpdate in FFlags then begin
 730    UpdateMakeExeCandidates;
 731    UpdateMakeExeNote;
 732  end else if sdfDebuggerFilenameNeedsUpdate in FFlags then begin
 733    UpdateDebuggerCandidates;
 734    UpdateDebuggerNote;
 735  end else
 736    IdleConnected:=false;
 737end;
 738
 739procedure TInitialSetupDialog.UpdateCaptions;
 740var
 741  s: String;
 742begin
 743  Caption:=SimpleFormat(lisWelcomeToLazarusIDE, [GetLazarusVersionString]);
 744
 745  StartIDEBitBtn.Caption:=lisStartIDE;
 746
 747  LazarusTabSheet.Caption:='Lazarus';
 748  CompilerTabSheet.Caption:=lisCompiler;
 749  FPCSourcesTabSheet.Caption:=lisFPCSources;
 750  MakeExeTabSheet.Caption:='Make';
 751  DebuggerTabSheet.Caption:=lisDebugger;
 752
 753  TVNodeLazarus.Text:=LazarusTabSheet.Caption;
 754  TVNodeCompiler.Text:=CompilerTabSheet.Caption;
 755  TVNodeFPCSources.Text:=FPCSourcesTabSheet.Caption;
 756  TVNodeMakeExe.Text:=MakeExeTabSheet.Caption;
 757  TVNodeDebugger.Text:=DebuggerTabSheet.Caption;
 758
 759  LazDirBrowseButton.Caption:=lisPathEditBrowse;
 760  LazDirLabel.Caption:=SimpleFormat(
 761    lisTheLazarusDirectoryContainsTheSourcesOfTheIDEAndTh, [PathDelim]);
 762
 763  CompilerBrowseButton.Caption:=lisPathEditBrowse;
 764  CompilerLabel.Caption:=SimpleFormat(lisTheFreePascalCompilerExecutableTypicallyHasTheName,
 765    [DefineTemplates.GetDefaultCompilerFilename,
 766     DefineTemplates.GetDefaultCompilerFilename(GetCompiledTargetCPU)]);
 767
 768  FPCSrcDirBrowseButton.Caption:=lisPathEditBrowse;
 769  FPCSrcDirLabel.Caption:=SimpleFormat(lisTheSourcesOfTheFreePascalPackagesAreRequiredForBro,
 770    [SetDirSeparators('rtl/linux/system.pp')]);
 771  ScanLabel.Caption := lisScanning;
 772  StopScanButton.Caption:=lisStop;
 773
 774  MakeExeBrowseButton.Caption:=lisPathEditBrowse;
 775  MakeExeLabel.Caption:=SimpleFormat(
 776    lisTheMakeExecutableTypicallyHasTheName, ['make'+GetExecutableExt('')]);
 777
 778  DebuggerBrowseButton.Caption:=lisPathEditBrowse;
 779  s:=SimpleFormat(lisTheDebuggerExecutableTypicallyHasTheNamePleaseGive, [
 780    'gdb'+GetExecutableExt]);
 781  {$IFDEF Windows}
 782  s+=' '+lisAUsefulSettingOnWindowsSystemsIsLazarusDirMingwBin;
 783  {$ENDIF}
 784  DebuggerLabel.Caption:=s;
 785end;
 786
 787procedure TInitialSetupDialog.SelectPage(const NodeText: string);
 788var
 789  i: Integer;
 790  Node: TTreeNode;
 791begin
 792  if FSelectingPage then exit;
 793  FSelectingPage:=true;
 794  try
 795    for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do begin
 796      Node:=PropertiesTreeView.Items.TopLvlItems[i];
 797      if Node.Text=NodeText then begin
 798        PropertiesTreeView.Selected:=Node;
 799        PropertiesPageControl.ActivePageIndex:=i;
 800        break;
 801      end;
 802    end;
 803  finally
 804    FSelectingPage:=false;
 805  end;
 806end;
 807
 808function TInitialSetupDialog.SelectDirectory(aTitle: string): string;
 809var
 810  DirDlg: TSelectDirectoryDialog;
 811begin
 812  Result:='';
 813  DirDlg:=TSelectDirectoryDialog.Create(nil);
 814  try
 815    DirDlg.Title:=aTitle;
 816    DirDlg.Options:=DirDlg.Options+[ofPathMustExist,ofFileMustExist];
 817    if not DirDlg.Execute then exit;
 818    Result:=DirDlg.FileName;
 819  finally
 820    DirDlg.Free;
 821  end;
 822end;
 823
 824procedure TInitialSetupDialog.StartFPCSrcThread;
 825begin
 826  fSearchFpcSourceThread:=TSearchFpcSourceThread.Create(Self);
 827  fSearchFpcSourceThread.OnTerminate:=@ThreadTerminated;
 828  fSearchFpcSourceThread.fFPCVer:=GetFPCVer;
 829  ShowHideScanControls(True); // Show scan controls while thread is running
 830  fSearchFpcSourceThread.Start;
 831end;
 832
 833procedure TInitialSetupDialog.UpdateLazarusDirCandidates;
 834var
 835  Dirs: TSDFileInfoList;
 836begin
 837  Dirs:=SearchLazarusDirectoryCandidates(false);
 838  FreeAndNil(FCandidates[sddtLazarusSrcDir]);
 839  FCandidates[sddtLazarusSrcDir]:=Dirs;
 840  FillComboboxWithFileInfoList(LazDirComboBox,Dirs);
 841end;
 842
 843procedure TInitialSetupDialog.UpdateCompilerFilenameCandidates;
 844var
 845  Files: TSDFileInfoList;
 846begin
 847  Exclude(FFlags,sdfCompilerFilenameNeedsUpdate);
 848  Files:=SearchCompilerCandidates(false,CodeToolBoss.FPCDefinesCache.TestFilename);
 849  FreeAndNil(FCandidates[sddtCompilerFilename]);
 850  FCandidates[sddtCompilerFilename]:=Files;
 851  FillComboboxWithFileInfoList(CompilerComboBox,Files);
 852end;
 853
 854procedure TInitialSetupDialog.UpdateFPCSrcDirCandidates;
 855var
 856  Dirs: TSDFileInfoList;
 857begin
 858  Exclude(FFlags,sdfFPCSrcDirNeedsUpdate);
 859  Dirs:=SearchFPCSrcDirCandidates(false,GetFPCVer);
 860  FreeAndNil(FCandidates[sddtFPCSrcDir]);
 861  FCandidates[sddtFPCSrcDir]:=Dirs;
 862  FillComboboxWithFileInfoList(FPCSrcDirComboBox,Dirs);
 863end;
 864
 865procedure TInitialSetupDialog.UpdateFPCSrcDirCandidate(aFPCSrcDirInfo: TSDFileInfo);
 866var
 867  Dirs: TSDFileInfoList;
 868begin
 869  Exclude(FFlags,sdfFPCSrcDirNeedsUpdate);
 870  FreeAndNil(FCandidates[sddtFPCSrcDir]);
 871  Dirs:=TSDFileInfoList.Create;
 872  Dirs.Add(aFPCSrcDirInfo);
 873  FCandidates[sddtFPCSrcDir]:=Dirs;
 874  FillComboboxWithFileInfoList(FPCSrcDirComboBox,Dirs);
 875end;
 876
 877procedure TInitialSetupDialog.UpdateMakeExeCandidates;
 878var
 879  Files: TSDFileInfoList;
 880begin
 881  Exclude(FFlags,sdfMakeExeFilenameNeedsUpdate);
 882  Files:=SearchMakeExeCandidates(false);
 883  FreeAndNil(FCandidates[sddtMakeExeFileName]);
 884  FCandidates[sddtMakeExeFileName]:=Files;
 885  FillComboboxWithFileInfoList(MakeExeComboBox,Files);
 886end;
 887
 888procedure TInitialSetupDialog.UpdateDebuggerCandidates;
 889var
 890  Files: TSDFileInfoList;
 891begin
 892  Exclude(FFlags,sdfDebuggerFilenameNeedsUpdate);
 893  Files:=SearchDebuggerCandidates(false);
 894  FreeAndNil(FCandidates[sddtDebuggerFilename]);
 895  FCandidates[sddtDebuggerFilename]:=Files;
 896  FillComboboxWithFileInfoList(DebuggerComboBox,Files);
 897end;
 898
 899procedure TInitialSetupDialog.FillComboboxWithFileInfoList(ABox: TComboBox;
 900  List: TSDFileInfoList; ItemIndex: integer);
 901var
 902  sl: TStringList;
 903  i: Integer;
 904begin
 905  sl:=TStringList.Create;
 906  try
 907    if List<>nil then
 908      for i:=0 to List.Count-1 do
 909        sl.Add(TSDFileInfo(List[i]).Caption);
 910    ABox.Items.Assign(sl);
 911    if (ItemIndex>=0) and (ItemIndex<sl.Count) then
 912      ABox.Text:=sl[ItemIndex]
 913    else if ABox.Text=ABox.Name then
 914      ABox.Text:='';
 915  finally
 916    sl.Free;
 917  end;
 918end;
 919
 920procedure TInitialSetupDialog.SetIdleConnected(const AValue: boolean);
 921begin
 922  if FIdleConnected=AValue then exit;
 923  FIdleConnected:=AValue;
 924  if IdleConnected then
 925    Application.AddOnIdleHandler(@OnIdle)
 926  else
 927    Application.RemoveOnIdleHandler(@OnIdle);
 928end;
 929
 930procedure TInitialSetupDialog.UpdateLazDirNote;
 931var
 932  CurCaption: String;
 933  Note: string;
 934  Quality: TSDFilenameQuality;
 935  s: String;
 936  ImageIndex: Integer;
 937begin
 938  if csDestroying in ComponentState then exit;
 939  CurCaption:=LazDirComboBox.Text;
 940  CurCaption:=ChompPathDelim(CurCaption);
 941  EnvironmentOptions.LazarusDirectory:=CurCaption;
 942  if FLastParsedLazDir=EnvironmentOptions.GetParsedLazarusDirectory then exit;
 943  FLastParsedLazDir:=EnvironmentOptions.GetParsedLazarusDirectory;
 944  //debugln(['TInitialSetupDialog.UpdateLazDirNote ',FLastParsedLazDir]);
 945  Quality:=CheckLazarusDirectoryQuality(FLastParsedLazDir,Note);
 946  case Quality of
 947  sddqInvalid: s:=lisError;
 948  sddqCompatible: s:='';
 949  else s:=lisWarning;
 950  end;
 951  if EnvironmentOptions.LazarusDirectory<>EnvironmentOptions.GetParsedLazarusDirectory
 952  then
 953    s:=lisDirectory+EnvironmentOptions.GetParsedLazarusDirectory+LineEnding+
 954      LineEnding+s;
 955  LazDirMemo.Text:=s+Note;
 956
 957  ImageIndex:=QualityToImgIndex(Quality);
 958  TVNodeLazarus.ImageIndex:=ImageIndex;
 959  TVNodeLazarus.SelectedIndex:=ImageIndex;
 960
 961  FFlags:=FFlags+[sdfCompilerFilenameNeedsUpdate,sdfFPCSrcDirNeedsUpdate,
 962                  sdfMakeExeFilenameNeedsUpdate,sdfDebuggerFilenameNeedsUpdate];
 963  IdleConnected:=true;
 964end;
 965
 966procedure TInitialSetupDialog.UpdateCompilerNote;
 967var
 968  CurCaption: String;
 969  Note: string;
 970  Quality: TSDFilenameQuality;
 971  s: String;
 972  ImageIndex: Integer;
 973  CfgCache: TFPCTargetConfigCache;
 974begin
 975  if csDestroying in ComponentState then exit;
 976  CurCaption:=CompilerComboBox.Text;
 977  EnvironmentOptions.CompilerFilename:=CurCaption;
 978  if fLastParsedCompiler=EnvironmentOptions.GetParsedCompilerFilename then exit;
 979  fLastParsedCompiler:=EnvironmentOptions.GetParsedCompilerFilename;
 980  //debugln(['TInitialSetupDialog.UpdateCompilerNote ',fLastParsedCompiler]);
 981
 982  Quality:=CheckCompilerQuality(fLastParsedCompiler,Note,
 983                                CodeToolBoss.FPCDefinesCache.TestFilename);
 984  if Quality<>sddqInvalid then begin
 985    CodeToolBoss.FPCDefinesCache.ConfigCaches.Find(
 986      fLastParsedCompiler,'','','',true);
 987    // check compiler again
 988    CfgCache:=CodeToolBoss.FPCDefinesCache.ConfigCaches.Find(
 989                                               fLastParsedCompiler,'','','',true);
 990    CfgCache.Update(CodeToolBoss.FPCDefinesCache.TestFilename);
 991    BuildBoss.SetBuildTargetIDE;
 992  end;
 993
 994  case Quality of
 995  sddqInvalid: s:=lisError;
 996  sddqCompatible: s:='';
 997  else s:=lisWarning;
 998  end;
 999  if EnvironmentOptions.CompilerFilename<>EnvironmentOptions.GetParsedCompilerFilename
1000  then
1001    s:=lisFile2+EnvironmentOptions.GetParsedCompilerFilename+LineEnding+
1002      LineEnding+s;
1003  CompilerMemo.Text:=s+Note;
1004
1005  ImageIndex:=QualityToImgIndex(Quality);
1006  TVNodeCompiler.ImageIndex:=ImageIndex;
1007  TVNodeCompiler.SelectedIndex:=ImageIndex;
1008
1009  FFlags:=FFlags+[sdfFPCSrcDirNeedsUpdate,
1010                  sdfMakeExeFilenameNeedsUpdate,sdfDebuggerFilenameNeedsUpdate];
1011  IdleConnected:=true;
1012end;
1013
1014procedure TInitialSetupDialog.UpdateFPCSrcDirNote;
1015var
1016  CurCaption: String;
1017  Note: string;
1018  Quality: TSDFilenameQuality;
1019  s: String;
1020  ImageIndex: Integer;
1021begin
1022  if csDestroying in ComponentState then exit;
1023  CurCaption:=FPCSrcDirComboBox.Text;
1024  CurCaption:=ChompPathDelim(CurCaption);
1025  EnvironmentOptions.FPCSourceDirectory:=CurCaption;
1026  if fLastParsedFPCSrcDir=EnvironmentOptions.GetParsedFPCSourceDirectory then exit;
1027  fLastParsedFPCSrcDir:=EnvironmentOptions.GetParsedFPCSourceDirectory;
1028  //debugln(['TInitialSetupDialog.UpdateFPCSrcDirNote ',fLastParsedFPCSrcDir]);
1029  Quality:=CheckFPCSrcDirQuality(fLastParsedFPCSrcDir,Note,GetFPCVer);
1030  case Quality of
1031  sddqInvalid: s:=lisError;
1032  sddqCompatible: s:='';
1033  else s:=lisWarning;
1034  end;
1035  if EnvironmentOptions.FPCSourceDirectory<>EnvironmentOptions.GetParsedFPCSourceDirectory
1036  then
1037    s:=lisDirectory+EnvironmentOptions.GetParsedFPCSourceDirectory+LineEnding+
1038      LineEnding+s;
1039  s+=Note;
1040  if Quality<>sddqCompatible then
1041    s+=#13+lisYouCanDownloadFPCAndTheFPCSourcesFromHttpSourcefor;
1042  FPCSrcDirMemo.Text:=s;
1043
1044  ImageIndex:=QualityToImgIndex(Quality);
1045  TVNodeFPCSources.ImageIndex:=ImageIndex;
1046  TVNodeFPCSources.SelectedIndex:=ImageIndex;
1047end;
1048
1049procedure TInitialSetupDialog.UpdateMakeExeNote;
1050var
1051  CurCaption: String;
1052  Note: string;
1053  Quality: TSDFilenameQuality;
1054  s: String;
1055  ImageIndex: Integer;
1056begin
1057  if csDestroying in ComponentState then exit;
1058  CurCaption:=MakeExeComboBox.Text;
1059  EnvironmentOptions.MakeFilename:=CurCaption;
1060  if fLastParsedMakeExe=EnvironmentOptions.GetParsedMakeFilename then exit;
1061  fLastParsedMakeExe:=EnvironmentOptions.GetParsedMakeFilename;
1062  //debugln(['TInitialSetupDialog.UpdateMakeExeNote ',fLastParsedMakeExe]);
1063  Quality:=CheckMakeExeQuality(fLastParsedMakeExe,Note);
1064
1065  case Quality of
1066  sddqInvalid: s:=lisError;
1067  sddqCompatible: s:='';
1068  else s:=lisWarning;
1069  end;
1070  if EnvironmentOptions.MakeFilename<>EnvironmentOptions.GetParsedMakeFilename
1071  then
1072    s:=lisFile2+EnvironmentOptions.GetParsedMakeFilename+LineEnding+
1073      LineEnding+s;
1074  MakeExeMemo.Text:=s+Note;
1075
1076  ImageIndex:=QualityToImgIndex(Quality);
1077  TVNodeMakeExe.ImageIndex:=ImageIndex;
1078  TVNodeMakeExe.SelectedIndex:=ImageIndex;
1079
1080  IdleConnected:=true;
1081end;
1082
1083procedure TInitialSetupDialog.UpdateDebuggerNote;
1084var
1085  CurCaption: String;
1086  Note: string;
1087  Quality: TSDFilenameQuality;
1088  s: String;
1089  ImageIndex: Integer;
1090begin
1091  if csDestroying in ComponentState then exit;
1092  CurCaption:=DebuggerComboBox.Text;
1093  EnvironmentOptions.DebuggerFilename:=CurCaption;
1094  if fLastParsedDebugger=EnvironmentOptions.GetParsedDebuggerFilename then exit;
1095  fLastParsedDebugger:=EnvironmentOptions.GetParsedDebuggerFilename;
1096  //debugln(['TInitialSetupDialog.UpdateDebuggerNote ',fLastParsedDebugger]);
1097  Quality:=CheckDebuggerQuality(fLastParsedDebugger,Note);
1098
1099  case Quality of
1100  sddqInvalid: s:=lisError;
1101  sddqCompatible: s:='';
1102  else s:=lisWarning;
1103  end;
1104  if EnvironmentOptions.DebuggerFilename<>EnvironmentOptions.GetParsedDebuggerFilename
1105  then
1106    s:=lisFile2+EnvironmentOptions.GetParsedDebuggerFilename+LineEnding+
1107      LineEnding+s;
1108  DebuggerMemo.Text:=s+Note;
1109
1110  ImageIndex:=QualityToImgIndex(Quality);
1111  TVNodeDebugger.ImageIndex:=ImageIndex;
1112  TVNodeDebugger.SelectedIndex:=ImageIndex;
1113
1114  IdleConnected:=true;
1115end;
1116
1117function TInitialSetupDialog.FirstErrorNode: TTreeNode;
1118var
1119  i: Integer;
1120begin
1121  for i:=0 to PropertiesTreeView.Items.TopLvlCount-1 do
1122  begin
1123    Result:=PropertiesTreeView.Items.TopLvlItems[i];
1124    if Result.ImageIndex=ImgIDError then exit;
1125  end;
1126  Result:=nil;
1127end;
1128
1129function TInitialSetupDialog.GetFPCVer: string;
1130begin
1131  Result:='$(FPCVer)';
1132  GlobalMacroList.SubstituteStr(Result);
1133end;
1134
1135function TInitialSetupDialog.GetFirstCandidate(Candidates: TSDFileInfoList;
1136  MinQuality: TSDFilenameQuality): TSDFileInfo;
1137var
1138  i: Integer;
1139begin
1140  if Candidates<>nil then
1141    for i:=0 to Candidates.Count-1 do begin
1142      Result:=TSDFileInfo(Candidates[i]);
1143      if Result.Quality>=MinQuality then
1144        exit;
1145    end;
1146  Result:=nil;
1147end;
1148
1149function TInitialSetupDialog.QualityToImgIndex(Quality: TSDFilenameQuality): integer;
1150begin
1151  if Quality=sddqCompatible then
1152    Result:=-1
1153  else if Quality=sddqWrongMinorVersion then
1154    Result:=ImgIDWarning
1155  else if Quality=sddqIncomplete then
1156    Result:=ImgIDWarning
1157  else
1158    Result:=ImgIDError;
1159end;
1160
1161procedure TInitialSetupDialog.ShowHideScanControls(aShow: Boolean);
1162begin
1163  // Show ProgressBar and Stop button durin scanning
1164  ScanLabel.Visible:=aShow;
1165  ScanProgressBar.Visible:=aShow;
1166  StopScanButton.Visible:=aShow;
1167  // At the same time disable other GUI controls so a user can not mess with it
1168  StartIDEBitBtn.Enabled:=not aShow;
1169  FPCSrcDirBrowseButton.Enabled:=not aShow;
1170  FPCSrcDirComboBox.Enabled:=not aShow;
1171//  FPCSrcDirMemo.Enabled:=not aShow;
1172end;
1173
1174procedure TInitialSetupDialog.ThreadTerminated(Sender: TObject);
1175begin
1176  debugln(['TInitialSetupDialog.ThreadTerminated ']);
1177  fSearchFpcSourceThread:=nil; // Thread will free itself. Make the variable nil, too.
1178  ShowHideScanControls(false);
1179end;
1180
1181procedure TInitialSetupDialog.TranslateResourceStrings;
1182begin
1183  IDETranslations.TranslateResourceStrings(
1184                           EnvironmentOptions.GetParsedLazarusDirectory,
1185                           EnvironmentOptions.LanguageID);
1186  UpdateCaptions;
1187end;
1188
1189procedure TInitialSetupDialog.Init;
1190var
1191  Node: TTreeNode;
1192  Candidate: TSDFileInfo;
1193  IsFirstStart: Boolean;
1194  PrimaryFilename: String;
1195  SecondaryFilename: String;
1196  PrimaryEnvs: TStringListUTF8;
1197  SecondaryEnvs: TStringListUTF8;
1198begin
1199  IsFirstStart:=not FileExistsCached(EnvironmentOptions.Filename);
1200  if not IsFirstStart then begin
1201    PrimaryFilename:=EnvironmentOptions.Filename;
1202    SecondaryFilename:=AppendPathDelim(GetSecondaryConfigPath)+ExtractFilename(PrimaryFilename);
1203    if FileExistsUTF8(PrimaryFilename)
1204    and FileExistsUTF8(SecondaryFilename) then begin
1205      // compare content of primary and secondary config
1206      PrimaryEnvs:=TStringListUTF8.Create;
1207      SecondaryEnvs:=TStringListUTF8.Create;
1208      try
1209        PrimaryEnvs.LoadFromFile(PrimaryFilename);
1210      except
1211        on E: Exception do
1212          debugln(['TInitialSetupDialog.Init unable to read "'+PrimaryFilename+'": '+E.Message]);
1213      end;
1214      try
1215        SecondaryEnvs.LoadFromFile(SecondaryFilename);
1216      except
1217        on E: Exception do
1218          debugln(['TInitialSetupDialog.Init unable to read "'+SecondaryFilename+'": '+E.Message]);
1219      end;
1220      IsFirstStart:=PrimaryEnvs.Text=SecondaryEnvs.Text;
1221      PrimaryEnvs.Free;
1222      SecondaryEnvs.Free;
1223    end;
1224  end;
1225  //debugln(['TInitialSetupDialog.Init IsFirstStart=',IsFirstStart,' ',EnvironmentOptions.Filename]);
1226
1227  // Lazarus directory
1228  UpdateLazarusDirCandidates;
1229  if IsFirstStart
1230  or (not FileExistsCached(EnvironmentOptions.GetParsedLazarusDirectory))
1231  then begin
1232    // first start => choose first best candidate
1233    Candidate:=GetFirstCandidate(FCandidates[sddtLazarusSrcDir]);
1234    if Candidate<>nil then
1235    begin
1236      EnvironmentOptions.LazarusDirectory:=Candidate.Caption;
1237      if Candidate.Quality=sddqCompatible then
1238        TranslateResourceStrings;
1239    end;
1240  end;
1241  LazDirComboBox.Text:=EnvironmentOptions.LazarusDirectory;
1242  FLastParsedLazDir:='. .';
1243  UpdateLazDirNote;
1244
1245  // compiler filename
1246  UpdateCompilerFilenameCandidates;
1247  if IsFirstStart
1248  or (EnvironmentOptions.CompilerFilename='')
1249  or (not FileExistsCached(EnvironmentOptions.GetParsedCompilerFilename))
1250  then begin
1251    // first start => choose first best candidate
1252    Candidate:=GetFirstCandidate(FCandidates[sddtCompilerFilename]);
1253    if Candidate<>nil then
1254      EnvironmentOptions.CompilerFilename:=Candidate.Caption;
1255  end;
1256  CompilerComboBox.Text:=EnvironmentOptions.CompilerFilename;
1257  fLastParsedCompiler:='. .';
1258  UpdateCompilerNote;
1259
1260  // FPC source directory
1261  UpdateFPCSrcDirCandidates;
1262  {$IFDEF DebugSearchFPCSrcThread}
1263  IsFirstStart:=true;
1264  {$ENDIF}
1265  if IsFirstStart or (EnvironmentOptions.FPCSourceDirectory='')
1266  or (not FileExistsCached(EnvironmentOptions.GetParsedFPCSourceDirectory))
1267  then begin
1268    // first start => choose first best candidate
1269    {$IFDEF DebugSearchFPCSrcThread}
1270    Candidate:=nil;
1271    {$ELSE}
1272    Candidate:=GetFirstCandidate(FCandidates[sddtFPCSrcDir]);
1273    {$ENDIF}
1274    if Candidate<>nil then begin
1275      EnvironmentOptions.FPCSourceDirectory:=Candidate.Caption;
1276    end
1277    else begin
1278      // No candidates found => start a thread to scan the file system.
1279      {$IFNDEF LCLCarbon}
1280      // carbon interface does not support Synchronize outside Application.Run
1281      StartFPCSrcThread;
1282      SelectPage(TVNodeFPCSources.Text);
1283      {$ENDIF}
1284    end;
1285  end;
1286  ShowHideScanControls(fSearchFpcSourceThread<>nil);
1287  FPCSrcDirComboBox.Text:=EnvironmentOptions.FPCSourceDirectory;
1288  fLastParsedFPCSrcDir:='. .';
1289  UpdateFPCSrcDirNote;
1290
1291  // Make executable
1292  UpdateMakeExeCandidates;
1293  if IsFirstStart
1294  or (EnvironmentOptions.MakeFilename='')
1295  or (not FileExistsCached(EnvironmentOptions.GetParsedMakeFilename)) then
1296  begin
1297    // first start => choose first best candidate
1298    Candidate:=GetFirstCandidate(FCandidates[sddtMakeExeFilename]);
1299    if Candidate<>nil then
1300      EnvironmentOptions.MakeFilename:=Candidate.Caption
1301    else begin // second chance => better an incomplete instead of none (especially for windows)
1302      Candidate:=GetFirstCandidate(FCandidates[sddtMakeExeFilename], sddqIncomplete);
1303      if Candidate<>nil then
1304        EnvironmentOptions.MakeFilename:=Candidate.Caption;
1305    end;
1306  end;
1307  MakeExeComboBox.Text:=EnvironmentOptions.MakeFilename;
1308  fLastParsedMakeExe:='. .';
1309  UpdateMakeExeNote;
1310
1311  // Debugger
1312  FInitialDebuggerFileName := EnvironmentOptions.DebuggerFilename;
1313  UpdateDebuggerCandidates;
1314  if IsFirstStart or (not FileExistsCached(EnvironmentOptions.GetParsedDebuggerFilename))
1315  then begin
1316    // first start => choose first best candidate
1317    Candidate:=GetFirstCandidate(FCandidates[sddtDebuggerFilename]);
1318    if Candidate<>nil then
1319      EnvironmentOptions.DebuggerFilename:=Candidate.Caption;
1320  end;
1321  DebuggerComboBox.Text:=EnvironmentOptions.DebuggerFilename;
1322  fLastParsedDebugger:='. .';
1323  UpdateDebuggerNote;
1324
1325  // select first error
1326  Node:=FirstErrorNode;
1327  if Node=nil then
1328    Node:=TVNodeLazarus;
1329  PropertiesTreeView.Selected:=Node;
1330end;
1331
1332end.
1333