PageRenderTime 40ms CodeModel.GetById 22ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/jcl/install/VclGui/JediGUIInstall.pas

https://github.com/the-Arioch/jcl
Pascal | 787 lines | 656 code | 84 blank | 47 comment | 51 complexity | d16f2f34c46ca08c578322fad7551422 MD5 | raw file
Possible License(s): BSD-3-Clause
  1{**************************************************************************************************}
  2{                                                                                                  }
  3{ Project JEDI Code Library (JCL) extension                                                        }
  4{                                                                                                  }
  5{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
  6{ you may not use this file except in compliance with the License. You may obtain a copy of the    }
  7{ License at http://www.mozilla.org/MPL/                                                           }
  8{                                                                                                  }
  9{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF   }
 10{ ANY KIND, either express or implied. See the License for the specific language governing rights  }
 11{ and limitations under the License.                                                               }
 12{                                                                                                  }
 13{ The Original Code is JediInstallerMain.pas.                                                      }
 14{                                                                                                  }
 15{ The Initial Developer of the Original Code is Petr Vones. Portions created by Petr Vones are     }
 16{ Copyright (C) of Petr Vones. All Rights Reserved.                                                }
 17{                                                                                                  }
 18{ Contributors:                                                                                    }
 19{   Andreas Hausladen (ahuser)                                                                     }
 20{   Robert Rossmair (rrossmair) - crossplatform & BCB support, refactoring                         }
 21{   Florent Ouchet (outchy) - New installer core                                                   }
 22{                                                                                                  }
 23{**************************************************************************************************}
 24{                                                                                                  }
 25{ Last modified: $Date::                                                                         $ }
 26{ Revision:      $Rev::                                                                          $ }
 27{ Author:        $Author::                                                                       $ }
 28{                                                                                                  }
 29{**************************************************************************************************}
 30
 31unit JediGUIInstall;
 32
 33{$I jcl.inc}
 34{$I crossplatform.inc}
 35
 36interface
 37
 38uses
 39  SysUtils, Classes,
 40  Graphics, Forms, Controls, StdCtrls, ComCtrls, ExtCtrls, FrmCompile,
 41  JclIDEUtils, JediInstall;
 42
 43type
 44  TSetIconEvent = procedure(Sender: TObject; const FileName: string) of object;
 45
 46  TInstallFrame = class(TFrame, IJediInstallPage, IJediPage)
 47    ComponentsTreePanel: TPanel;
 48    LabelSelectComponents: TLabel;
 49    TreeView: TTreeView;
 50    Splitter: TSplitter;
 51    InfoPanel: TPanel;
 52    LabelInstallationLog: TLabel;
 53    InfoDisplay: TRichEdit;
 54    OptionsGroupBox: TGroupBox;
 55    ProgressBar: TProgressBar;
 56    procedure SplitterCanResize(Sender: TObject; var NewSize: Integer;
 57      var Accept: Boolean);
 58    procedure TreeViewMouseDown(Sender: TObject; Button: TMouseButton;
 59      Shift: TShiftState; X, Y: Integer);
 60    procedure TreeViewKeyPress(Sender: TObject; var Key: Char);
 61    procedure TreeViewCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
 62      State: TCustomDrawState; var DefaultDraw: Boolean);
 63  private
 64    FNodeData: TList;
 65    FDirectories: TList;
 66    FCheckedCount: Integer;
 67    FInstallCount: Integer;
 68    FInstalling: Boolean;
 69    FOnSetIcon: TSetIconEvent;
 70    FFormCompile: TFormCompile;
 71    FInstallGUI: IJediInstallGUI;
 72    function GetFormCompile: TFormCompile;
 73    function GetNodeChecked(Node: TTreeNode): Boolean;
 74    function IsAutoChecked(Node: TTreeNode): Boolean;
 75    function IsRadioButton(Node: TTreeNode): Boolean;
 76    function IsStandAloneParent(Node: TTreeNode): Boolean;
 77    function IsExpandable(Node: TTreeNode): Boolean;
 78    procedure UpdateNode(N: TTreeNode; C: Boolean);
 79    procedure SetNodeChecked(Node: TTreeNode; const Value: Boolean);
 80    procedure ToggleNodeChecked(Node: TTreeNode);
 81    procedure DirectoryEditChange(Sender: TObject);
 82    procedure DirectorySelectBtnClick(Sender: TObject);
 83    function GetNode(Id: Integer): TTreeNode;
 84    procedure UpdateImageIndex(N: TTreeNode);
 85  public
 86    constructor Create(AOwner: TComponent; AInstallGUI: IJediInstallGUI); reintroduce;
 87    destructor Destroy; override;
 88    // IJediPage
 89    function GetCaption: string;
 90    procedure SetCaption(const Value: string);
 91    function GetHintAtPos(ScreenX, ScreenY: Integer): string;
 92    procedure Show;
 93    // IJediInstallPage
 94    procedure AddInstallOption(Id: Integer; Options: TJediInstallGUIOptions;
 95      const Caption: string = ''; const Hint: string = ''; Parent: Integer = -1);
 96    procedure InitDisplay;
 97    function GetOptionChecked(Id: Integer): Boolean;
 98    procedure SetOptionChecked(Id: Integer; Value: Boolean);
 99    function GetDirectoryCount: Integer;
100    function GetDirectory(Index: Integer): string;
101    procedure SetDirectory(Index: Integer; const Value: string);
102    function AddDirectory(const Caption: string): Integer;
103    function GetProgress: Integer;
104    procedure SetProgress(Value: Integer);
105    procedure BeginInstall;
106    procedure MarkOptionBegin(Id: Integer);
107    procedure MarkOptionEnd(Id: Integer; Failed: Boolean);
108    procedure EndInstall;
109    procedure CompilationStart(const ProjectName: string);
110    procedure AddLogLine(const Line: string);
111    procedure AddHint(const Line: string);
112    procedure AddWarning(const Line: string);
113    procedure AddError(const Line: string);
114    procedure AddFatal(const Line: string);
115    procedure AddText(const Line: string);
116    procedure CompilationProgress(const FileName: string; LineNumber: Integer);
117    procedure SetIcon(const FileName: string);
118    property OnSetIcon: TSetIconEvent read FOnSetIcon write FOnSetIcon;
119  end;
120
121implementation
122
123{$R *.dfm}
124
125uses
126  {$IFDEF HAS_UNIT_TYPES}
127  Types, // inlining of Point
128  {$ENDIF HAS_UNIT_TYPES}
129  Windows, Messages,
130  FileCtrl,
131  JclStrings,
132  JediInstallResources;
133
134const
135  // Icon indexes
136  IcoUnchecked      = 0;
137  IcoChecked        = 1;
138  IcoRadioUnchecked = 2;
139  IcoRadioChecked   = 3;
140  IcoNotInstalled   = 4;
141  IcoFailed         = 5;
142  IcoInstalled      = 6;
143
144  IconIndexes: array [Boolean {RadioButton}, Boolean {Checked}] of Integer =
145   ( (IcoUnchecked, IcoChecked), (IcoRadioUnchecked, IcoRadioChecked) );
146
147type
148  TNodeRec = record
149    Id: Integer;
150    Options: TJediInstallGUIOptions;
151    Hint: string;
152  end;
153
154  PNodeRec = ^TNodeRec;
155
156  TDirectoryRec = record
157    Edit: TEdit;
158    Button: TButton;
159  end;
160
161  PDirectoryRec = ^TDirectoryRec;
162
163constructor TInstallFrame.Create(AOwner: TComponent; AInstallGUI: IJediInstallGUI);
164begin
165  inherited Create(AOwner);
166
167  FNodeData := TList.Create;
168  FDirectories := TList.Create;
169  FInstallGUI := AInstallGUI;
170end;
171
172destructor TInstallFrame.Destroy;
173var
174  Index: Integer;
175begin
176  for Index := FNodeData.Count - 1 downto 0 do
177    Dispose(FNodeData.Items[Index]);
178  FNodeData.Free;
179  for Index := FDirectories.Count - 1 downto 0 do
180    Dispose(FDirectories.Items[Index]);
181  FDirectories.Free;
182
183  inherited Destroy;
184end;
185
186procedure TInstallFrame.DirectoryEditChange(Sender: TObject);
187var
188  AEdit: TEdit;
189begin
190  AEdit := Sender as TEdit;
191  if {$IFDEF RTL220_UP}SysUtils.{$ENDIF RTL220_UP}DirectoryExists(AEdit.Text) then
192    AEdit.Font.Color := clWindowText
193  else
194    AEdit.Font.Color := clRed;
195end;
196
197function TInstallFrame.GetNodeChecked(Node: TTreeNode): Boolean;
198begin
199  Result := goChecked in PNodeRec(Node.Data)^.Options;
200end;
201
202function TInstallFrame.IsAutoChecked(Node: TTreeNode): Boolean;
203begin
204  Result := not (goNoAutoCheck in PNodeRec(Node.Data)^.Options);
205end;
206
207function TInstallFrame.IsRadioButton(Node: TTreeNode): Boolean;
208begin
209  Result := goRadioButton in PNodeRec(Node.Data)^.Options;
210end;
211
212function TInstallFrame.IsStandAloneParent(Node: TTreeNode): Boolean;
213begin
214  Result := goStandaloneParent in PNodeRec(Node.Data)^.Options;
215end;
216
217function TInstallFrame.IsExpandable(Node: TTreeNode): Boolean;
218begin
219  Result := goExpandable in PNodeRec(Node.Data)^.Options;
220end;
221
222procedure TInstallFrame.SetIcon(const FileName: string);
223begin
224  if Assigned(FOnSetIcon) then
225    FOnSetIcon(Self, FileName);
226end;
227
228procedure TInstallFrame.UpdateNode(N: TTreeNode; C: Boolean);
229var
230  ANodeRec: PNodeRec;
231begin
232  ANodeRec := N.Data;
233  if C then
234    Include(ANodeRec^.Options, goChecked)
235  else
236    Exclude(ANodeRec^.Options, goChecked);
237  UpdateImageIndex(N);
238end;
239
240procedure TInstallFrame.SetNodeChecked(Node: TTreeNode; const Value: Boolean);
241
242  procedure UpdateTreeDown(N: TTreeNode; C: Boolean);
243  begin
244    N := N.getFirstChild;
245    while Assigned(N) do
246    begin
247      if not C or IsAutoChecked(N) then
248      begin
249        if not IsRadioButton(N) then
250          UpdateNode(N, C);
251        UpdateTreeDown(N, C);
252      end;
253      N := N.getNextSibling;
254    end;
255  end;
256
257  procedure UpdateTreeUp(N: TTreeNode; C: Boolean);
258  var
259    ParentNode: TTreeNode;
260    ParentChecked: Boolean;
261  begin
262    if C then
263      while Assigned(N) do
264      begin
265        UpdateNode(N, True);
266        N := N.Parent;
267      end
268    else
269    begin
270      ParentNode := N.Parent;
271      while Assigned(ParentNode) do
272      begin
273        N := ParentNode.getFirstChild;
274        ParentChecked := IsStandAloneParent(ParentNode);
275        while Assigned(N) do
276          if GetNodeChecked(N) and not IsRadioButton(N) then
277          begin
278            ParentChecked := True;
279            Break;
280          end
281          else
282            N := N.getNextSibling;
283        UpdateNode(ParentNode, ParentChecked);
284        ParentNode := ParentNode.Parent;
285      end;
286    end;
287  end;
288
289  procedure UpdateRadioButton(N: TTreeNode; C: Boolean);
290  var
291    Node: TTreeNode;
292  begin
293    if Value and not GetNodeChecked(N) then
294    begin
295      Node := N.Parent;
296      if Node <> nil then
297      begin
298        Node := Node.getFirstChild;
299        while Node <> nil do
300        begin
301          if IsRadioButton(Node) then
302            UpdateNode(Node, Node = N);
303          Node := Node.getNextSibling;
304        end;
305      end;
306    end;
307  end;
308
309begin
310  if IsRadioButton(Node) then
311    UpdateRadioButton(Node, Value)
312  else
313  begin
314    UpdateTreeDown(Node, Value);
315    UpdateNode(Node, Value);
316    UpdateTreeUp(Node, Value);
317  end;
318  TreeView.Invalidate;
319end;
320
321procedure TInstallFrame.ToggleNodeChecked(Node: TTreeNode);
322begin
323  if Assigned(Node) then
324    SetNodeChecked(Node, not GetNodeChecked(Node));
325end;
326
327function TInstallFrame.GetNode(Id: Integer): TTreeNode;
328begin
329  Result := TreeView.Items.GetFirstNode;
330  while Assigned(Result) do
331  begin
332    if PNodeRec(Result.Data)^.Id = Id then
333      Break;
334    Result := Result.GetNext;
335  end;
336end;
337
338procedure TInstallFrame.UpdateImageIndex(N: TTreeNode);
339var
340  ImgIndex: Integer;
341begin
342  ImgIndex := IconIndexes[IsRadioButton(N), GetNodeChecked(N)];
343  N.ImageIndex := ImgIndex;
344  N.SelectedIndex := ImgIndex;
345end;
346
347procedure TInstallFrame.DirectorySelectBtnClick(Sender: TObject);
348var
349  Index: Integer;
350  Button: TButton;
351  Edit: TEdit;
352  {$IFDEF USE_WIDESTRING}
353  Directory: WideString;
354  {$UNDEF USE_WIDESTRING}
355  {$ELSE}
356  Directory: string;
357  {$ENDIF}
358  DirectoryRec: PDirectoryRec;
359begin
360  Button := Sender as TButton;
361  Edit := nil;
362  for Index := 0 to FDirectories.Count - 1 do
363  begin
364    DirectoryRec := FDirectories.Items[Index];
365    if DirectoryRec^.Button = Button then
366    begin
367      Edit := DirectoryRec^.Edit;
368      Break;
369    end;
370  end;
371  if Assigned(Edit) and SelectDirectory(RsSelectPath, '', Directory) then
372    Edit.Text := Directory;
373end;
374
375procedure TInstallFrame.SplitterCanResize(Sender: TObject;
376  var NewSize: Integer; var Accept: Boolean);
377begin
378  Accept := NewSize > 150;
379end;
380
381procedure TInstallFrame.TreeViewCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; 
382  State: TCustomDrawState; var DefaultDraw: Boolean);
383begin
384  case TTreeNode(Node).Level of
385    0: begin
386         Sender.Canvas.Font.Style := [fsBold, fsUnderline];
387       end;
388    1: begin
389         Sender.Canvas.Font.Style := [fsBold];
390       end;
391  end;
392end;
393
394procedure TInstallFrame.TreeViewKeyPress(Sender: TObject; var Key: Char);
395begin
396  with TTreeView(Sender) do
397    case Key of
398      #32:
399        if not FInstalling then
400        begin
401          ToggleNodeChecked(Selected);
402          Key := #0;
403        end;
404      '+':
405        Selected.Expanded := True;
406      '-':
407        Selected.Expanded := False;
408    end;
409end;
410
411function TreeNodeIconHit(TreeView: TTreeView; X, Y: Integer): Boolean;
412begin
413  Result := htOnIcon in TreeView.GetHitTestInfoAt(X, Y);
414end;
415
416procedure TInstallFrame.TreeViewMouseDown(Sender: TObject;
417  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
418var
419  Node: TTreeNode;
420begin
421  if not FInstalling then
422    with TTreeView(Sender) do
423  begin
424    Node := GetNodeAt(X, Y);
425    if (Button = mbLeft) and TreeNodeIconHit(TreeView, X, Y) then
426      ToggleNodeChecked(Node);
427  end;
428end;
429
430function TInstallFrame.GetFormCompile: TFormCompile;
431begin
432  if not Assigned(FFormCompile) then
433  begin
434    FFormCompile := TFormCompile.Create(Self, FInstallGUI);
435    SetWindowLong(FFormCompile.Handle, GWL_HWNDPARENT, Handle);
436    FFormCompile.Init(Caption, True);
437    FFormCompile.Show;
438    Application.ProcessMessages;
439  end;
440  Result := FFormCompile;
441end;
442
443// IJediPage
444function TInstallFrame.GetCaption: string;
445begin
446  Result := (Parent as TTabSheet).Caption;
447end;
448
449procedure TInstallFrame.SetCaption(const Value: string);
450begin
451  (Parent as TTabSheet).Caption := Value;
452  AddInstallOption(JediTargetOption, [goExpandable], Value, LoadResString(@RsHintTarget), -1);
453end;
454
455function TInstallFrame.GetHintAtPos(ScreenX, ScreenY: Integer): string;
456var
457  TreeViewCoord: TPoint;
458  ANode: TTreeNode;
459begin
460  TreeViewCoord := TreeView.ScreenToClient(Point(ScreenX, ScreenY));
461  if (TreeViewCoord.X >= 0) and (TreeViewCoord.Y >= 0) and
462    (TreeViewCoord.X < TreeView.Width) and (TreeViewCoord.Y < TreeView.Height) then
463  begin
464    ANode := TreeView.GetNodeAt(TreeViewCoord.X, TreeViewCoord.Y);
465    if Assigned(ANode) then
466      Result := PNodeRec(ANode.Data)^.Hint;
467  end;
468end;
469
470procedure TInstallFrame.Show;
471var
472  ATabSheet: TTabSheet;
473begin
474  ATabSheet := Parent as TTabSheet;
475  (ATabSheet.Parent as TPageControl).ActivePage := ATabSheet;
476end;
477
478// IJediInstallPage
479procedure TInstallFrame.AddInstallOption(Id: Integer; Options: TJediInstallGUIOptions;
480  const Caption: string = ''; const Hint: string = ''; Parent: Integer = -1);
481var
482  NodeRec: PNodeRec;
483  ParentNode, ThisNode: TTreeNode;
484begin
485  if Id = -1 then
486    raise Exception.CreateResFmt(@RsInvalidOption, [Id]);
487
488  if Parent <> -1 then
489    ParentNode := GetNode(Parent)
490  else
491    ParentNode := nil;
492  ThisNode := GetNode(Id);
493  if Assigned(ThisNode) then
494    ThisNode.Text := Caption
495  else
496  begin
497    New(NodeRec);
498    NodeRec^.Id := Id;
499    NodeRec^.Hint := Hint;
500    NodeRec^.Options := Options;
501    ThisNode := TreeView.Items.AddChildObject(ParentNode, Caption, NodeRec);
502    FNodeData.Add(NodeRec);
503  end;
504
505  UpdateImageIndex(ThisNode);
506end;
507
508procedure TInstallFrame.InitDisplay;
509var
510  ANode: TTreeNode;
511begin
512  LabelSelectComponents.Caption := LoadResString(@RsGUISelectComponents);
513  LabelInstallationLog.Caption := LoadResString(@RsGUIInstallationLog);
514  OptionsGroupBox.Caption := LoadResString(@RsGUIAdvancedOptions);
515
516  ANode := TreeView.Items.GetFirstNode;
517  while Assigned(ANode) do
518  begin
519    if (ANode.Count > 0) and IsExpandable(ANode) then
520      ANode.Expand(False);
521    ANode := ANode.GetNext;
522  end;
523  ANode := TreeView.Items.GetFirstNode;
524  if Assigned(ANode) then
525    TreeView.TopItem := ANode;
526end;
527
528function TInstallFrame.GetOptionChecked(Id: Integer): Boolean;
529var
530  ANode: TTreeNode;
531begin
532  ANode := GetNode(Id);
533  Result := Assigned(ANode) and GetNodeChecked(ANode);
534end;
535
536procedure TInstallFrame.SetOptionChecked(Id: Integer; Value: Boolean);
537var
538  ANode: TTreeNode;
539begin
540  ANode := GetNode(Id);
541  while Assigned(ANode) do
542  begin
543    UpdateNode(ANode, Value);
544    // if an option is checked, ensure that all parent options are checked too
545    if IsRadioButton(ANode) or not Value then
546      Break;
547    ANode := ANode.Parent;
548  end;
549end;
550
551function TInstallFrame.GetDirectoryCount: Integer;
552begin
553  Result := FDirectories.Count;
554end;
555
556function TInstallFrame.GetDirectory(Index: Integer): string;
557begin
558  Result := PDirectoryRec(FDirectories.Items[Index])^.Edit.Text;
559end;
560
561procedure TInstallFrame.SetDirectory(Index: Integer; const Value: string);
562begin
563  PDirectoryRec(FDirectories.Items[Index])^.Edit.Text := Value;
564end;
565
566function TInstallFrame.AddDirectory(const Caption: string): Integer;
567var
568  ADirectoryRec: PDirectoryRec;
569  ALabel: TLabel;
570  ControlTop, ButtonWidth, LabelRight: Integer;
571begin
572  if FDirectories.Count > 0 then
573  begin
574    ADirectoryRec := FDirectories.Items[FDirectories.Count - 1];
575    ControlTop := ADirectoryRec^.Edit.Top + ADirectoryRec^.Edit.Height + 10;
576  end
577  else
578    ControlTop := 16;
579
580  New(ADirectoryRec);
581  ALabel := TLabel.Create(Self);
582  ALabel.Parent := OptionsGroupBox;
583  ALabel.Caption := Caption;
584  ALabel.AutoSize := True;
585  ADirectoryRec^.Edit := TEdit.Create(Self);
586  ADirectoryRec^.Edit.Parent := OptionsGroupBox;
587  ADirectoryRec^.Edit.Anchors := [akLeft, akTop, akRight];
588  ADirectoryRec^.Button := TButton.Create(Self);
589  ADirectoryRec^.Button.Parent := OptionsGroupBox;
590  ADirectoryRec^.Button.Caption := '...';
591  ADirectoryRec^.Button.Anchors := [akTop, akRight];
592
593  ButtonWidth := 2 * ALabel.Height;
594  LabelRight := (ALabel.Width div 16) * 16 + 32 + ALabel.Left; // make edits aligned when label widths are nearly equals
595
596  ADirectoryRec^.Edit.SetBounds(LabelRight, ControlTop,
597    OptionsGroupBox.ClientWidth - LabelRight - ButtonWidth - 16,
598    ADirectoryRec^.Edit.Height);
599  ADirectoryRec^.Button.SetBounds(OptionsGroupBox.ClientWidth - ButtonWidth - 8,
600    ControlTop, ButtonWidth, ADirectoryRec^.Edit.Height);
601  ALabel.SetBounds(8, ControlTop + (ADirectoryRec^.Edit.Height - ALabel.Height) div 2,
602    ALabel.Width, ALabel.Height);
603
604  ADirectoryRec^.Edit.OnChange := DirectoryEditChange;
605  ADirectoryRec^.Button.OnClick := DirectorySelectBtnClick;
606
607  OptionsGroupBox.ClientHeight := ADirectoryRec^.Edit.Top + ADirectoryRec^.Edit.Height + 10;
608  OptionsGroupBox.Top := TreeView.Height + TreeView.Top - OptionsGroupBox.Height;
609  InfoDisplay.Height := OptionsGroupBox.Top - InfoDisplay.Top - 8;
610
611  Result := FDirectories.Add(ADirectoryRec);
612end;
613
614function TInstallFrame.GetProgress: Integer;
615begin
616  Result := ProgressBar.Position;
617end;
618
619procedure TInstallFrame.SetProgress(Value: Integer);
620begin
621  ProgressBar.Position := Value;
622end;
623
624procedure TInstallFrame.BeginInstall;
625var
626  ANode: TTreeNode;
627begin
628  ProgressBar.Visible := True;
629
630  InfoDisplay.Lines.Clear;
631
632  FCheckedCount := 0;
633  FInstallCount := 0;
634  ANode := TreeView.Items.GetFirstNode;
635  while Assigned(ANode) do
636  begin
637    if GetNodeChecked(ANode) then
638      Inc(FCheckedCount);
639    ANode := ANode.GetNext;
640  end;
641
642  FInstalling := True;
643end;
644
645procedure TInstallFrame.MarkOptionBegin(Id: Integer);
646var
647  ANode: TTreeNode;
648begin
649  ANode := GetNode(Id);
650  while Assigned(ANode) do
651  begin
652    ANode.ImageIndex := IcoNotInstalled;
653    ANode.SelectedIndex := IcoNotInstalled;
654    ANode := ANode.Parent;
655  end;
656end;
657
658procedure TInstallFrame.MarkOptionEnd(Id: Integer; Failed: Boolean);
659var
660  ANode, BNode: TTreeNode;
661  Index: Integer;
662  ChangeIcon: Boolean;
663begin
664  if Assigned(FFormCompile) then
665  begin
666    if FFormCompile.Errors > 0 then // do not make the dialog modal when no error occured
667      FFormCompile.Done(' ')
668    else
669      FFormCompile.Done;
670    FreeAndNil(FFormCompile);
671  end;
672  ANode := GetNode(Id);
673  while Assigned(ANode) and GetNodeChecked(ANode) do
674  begin
675    ChangeIcon := (ANode.Count = 0) or Failed;
676    if not ChangeIcon then
677    begin
678      ChangeIcon := True;
679      for Index := 0 to ANode.Count - 1 do
680      begin
681        BNode := ANode.Item[Index];
682        case BNode.ImageIndex of
683          IcoNotInstalled:
684            begin
685              ChangeIcon := False;
686              Break;
687            end;
688          IcoFailed:
689            begin
690              Failed := True;
691              Break;
692            end;
693          IcoInstalled: ;
694        else
695          ChangeIcon := ChangeIcon and not GetNodeChecked(BNode);
696        end;
697      end;
698    end;
699    if ChangeIcon then
700    begin
701      if Failed then
702      begin
703        ANode.ImageIndex := IcoFailed;
704        ANode.SelectedIndex := IcoFailed;
705      end
706      else
707      begin
708        ANode.ImageIndex := IcoInstalled;
709        ANode.SelectedIndex := IcoInstalled;
710      end;
711    end
712    else
713      Break;
714    ANode := ANode.Parent;
715  end;
716  Inc(FInstallCount);
717  if FCheckedCount > 0 then
718    SetProgress(100 * FInstallCount div FCheckedCount);
719end;
720
721procedure TInstallFrame.EndInstall;
722var
723  ANode: TTreeNode;
724begin
725  FInstalling := False;
726
727  MarkOptionEnd(-1, True);
728  ANode := TreeView.Items.GetFirstNode;
729  while Assigned(ANode) do
730  begin
731    UpdateImageIndex(ANode);
732    ANode := ANode.GetNext;
733  end;
734  ProgressBar.Visible := False;
735end;
736
737procedure TInstallFrame.CompilationStart(const ProjectName: string);
738begin
739  GetFormCompile.Init(ProjectName, True);
740end;
741
742procedure TInstallFrame.AddLogLine(const Line: string);
743begin
744  InfoDisplay.Lines.Append(Line);
745  InfoDisplay.Perform(EM_SCROLLCARET, 0, 0);
746end;
747
748procedure TInstallFrame.AddHint(const Line: string);
749begin
750  GetFormCompile.AddHint(Line);
751  AddLogLine(Line);
752end;
753
754procedure TInstallFrame.AddWarning(const Line: string);
755begin
756  GetFormCompile.AddWarning(Line);
757  AddLogLine(Line);
758end;
759
760procedure TInstallFrame.AddError(const Line: string);
761begin
762  GetFormCompile.AddError(Line);
763  AddLogLine(Line);
764end;
765
766procedure TInstallFrame.AddFatal(const Line: string);
767begin
768  GetFormCompile.AddFatal(Line);
769  AddLogLine(Line);
770end;
771
772procedure TInstallFrame.AddText(const Line: string);
773begin
774  //{$IFDEF VCL}
775  //GetFormCompile.AddText(Line);
776  //{$ENDIF VCL}
777  AddLogLine(Line);
778end;
779
780procedure TInstallFrame.CompilationProgress(const FileName: string; LineNumber: Integer);
781begin
782  GetFormCompile.CompilationProgress(FileName, LineNumber);
783end;
784
785end.
786
787