1 {
2  ***************************************************************************
3  *                                                                         *
4  *   This source is free software; you can redistribute it and/or modify   *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This code is distributed in the hope that it will be useful, but      *
10  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
12  *   General Public License for more details.                              *
13  *                                                                         *
14  *   A copy of the GNU General Public License is available on the World    *
15  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
16  *   obtain it by writing to the Free Software Foundation,                 *
17  *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
18  *                                                                         *
19  ***************************************************************************
20 
21   Author: Mattias Gaertner
22 
23   Abstract:
24     This unit defines a dialog for the lazarus options.
25 }
26 unit IDEOptionsDlg;
27 
28 {$mode objfpc}{$H+}
29 
30 interface
31 
32 uses
33   Classes, SysUtils,
34   // LCL
35   LCLProc, LCLType, Controls, Forms, ComCtrls, Buttons, ButtonPanel,
36   ExtCtrls, StdCtrls, Dialogs,
37   // LazControls
38   TreeFilterEdit,
39   LazControlDsgn, // move this to lazarus.lpr
40   // IdeIntf
41   IDEWindowIntf, IDEOptionsIntf, IDEOptEditorIntf, IDECommands, IDEHelpIntf,
42   ProjectIntf, IDEImagesIntf,
43   // IDE
44   EnvironmentOpts, EditorOptions, BuildModesManager, Compiler_ModeMatrix,
45   Project, LazarusIDEStrConsts,
46   // Packager
47   PackageDefs, PackageSystem;
48 
49 type
50   TIDEOptsDlgAction = (
51     iodaRead,
52     iodaWrite,
53     iodaRestore
54     );
55 
56   TIDEOptionsEditorFilter = array of TAbstractIDEOptionsClass;
57 
58   { TIDEOptionsDialog }
59 
60   TIDEOptionsDialog = class(TAbstractOptionsEditorDialog)
61     BuildModeComboBox: TComboBox;
62     BuildModeManageButton: TButton;
63     BuildModeSelectPanel: TPanel;
64     ButtonPanel: TButtonPanel;
65     CategoryPanel: TPanel;
66     CategoryTree: TTreeView;
67     CatTVSplitter: TSplitter;
68     EditorsPanel: TScrollBox;
69     FilterEdit: TTreeFilterEdit;
70     BuildModesLabel: TLabel;
71     SettingsPanel: TPanel;
72     procedure BuildModeComboBoxSelect(Sender: TObject);
73     procedure BuildModeManageButtonClick(Sender: TObject);
74     procedure CategoryTreeChange(Sender: TObject; Node: TTreeNode);
75     procedure CategoryTreeCollapsed(Sender: TObject; Node: TTreeNode);
76     procedure CategoryTreeExpanded(Sender: TObject; Node: TTreeNode);
77     procedure CategoryTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
FilterEditFilterItemnull78     function FilterEditFilterItem(ItemData: Pointer; out Done: Boolean): Boolean;
79     procedure FormShow(Sender: TObject);
80     procedure HelpButtonClick(Sender: TObject);
81     procedure OkButtonClick(Sender: TObject);
82     procedure CancelButtonClick(Sender: TObject);
83   private
84     FEditorsCreated: Boolean;
85     FEditorToOpen: TAbstractIDEOptionsEditorClass;
86     FNewLastSelected: PIDEOptionsEditorRec;
87     FOnLoadOptionsHook: TOnLoadIDEOptions;
88     FOnSaveOptionsHook: TOnSaveIDEOptions;
89     FOptionsFilter: TIDEOptionsEditorFilter;
90     FPrevEditor: TAbstractIDEOptionsEditor;
91     FSelectNode: TTreeNode;
92     FSettings: TIDEOptionsEditorSettings;
FindGroupClassnull93     function FindGroupClass(Node: TTreeNode): TAbstractIDEOptionsClass;
94     procedure TraverseSettings(AOptions: TAbstractIDEOptions; anAction: TIDEOptsDlgAction);
CheckValuesnull95     function CheckValues: boolean;
96     procedure DoOpenEditor(EditorToOpen: TAbstractIDEOptionsEditorClass);
97     procedure LoadIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions);
98     procedure SaveIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions);
99     procedure CreateEditors;
SearchEditorNodenull100     function SearchEditorNode(AEditor: TAbstractIDEOptionsEditorClass): TTreeNode;
SearchEditorNodenull101     function SearchEditorNode(const IDEOptionsEditorClassName: string): TTreeNode;
PassesFilternull102     function PassesFilter(ARec: PIDEOptionsGroupRec): Boolean;
103     procedure SetSettings(const AValue: TIDEOptionsEditorSettings);
AllBuildModesnull104     function AllBuildModes: boolean;
105     procedure UpdateBuildModeButtons;
106     procedure SetBuildModeVisibility(AVisibility: Boolean);
107   public
108     constructor Create(AOwner: TComponent); override;
ShowModalnull109     function ShowModal: Integer; override;
AddButtonnull110     function AddButton: TBitBtn; override;
111     procedure AddButtonSeparator; override;
AddControlnull112     function AddControl(AControlClass: TControlClass): TControl; override;
113     procedure OpenEditor(AEditor: TAbstractIDEOptionsEditorClass); override;
114     procedure OpenEditor(GroupIndex, AIndex: integer); override;
FindEditornull115     function FindEditor(AEditor: TAbstractIDEOptionsEditorClass): TAbstractIDEOptionsEditor; override;
FindEditornull116     function FindEditor(const IDEOptionsEditorClassName: string): TAbstractIDEOptionsEditor; override;
FindEditornull117     function FindEditor(GroupIndex, AIndex: integer): TAbstractIDEOptionsEditor; override;
FindEditorClassnull118     function FindEditorClass(GroupIndex, AIndex: integer): TAbstractIDEOptionsEditorClass; override;
ResetFilternull119     function ResetFilter: Boolean; override;
120     procedure UpdateBuildModeGUI; override;
121     procedure ReadAll;
122     procedure WriteAll(Restore: boolean);
123   public
124     property OptionsFilter: TIDEOptionsEditorFilter read FOptionsFilter write FOptionsFilter;
125     property Settings: TIDEOptionsEditorSettings read FSettings write SetSettings;
126     property OnLoadIDEOptionsHook: TOnLoadIDEOptions read FOnLoadOptionsHook write FOnLoadOptionsHook;
127     property OnSaveIDEOptionsHook: TOnSaveIDEOptions read FOnSaveOptionsHook write FOnSaveOptionsHook;
128   end;
129 
130 implementation
131 
132 {$R *.lfm}
133 
134 { TIDEOptionsDialog }
135 
136 constructor TIDEOptionsDialog.Create(AOwner: TComponent);
137 begin
138   inherited Create(AOwner);
139   FPrevEditor := nil;
140   FEditorsCreated := False;
141   FEditorToOpen := nil;
142   SetBuildModeVisibility(False);
143   Caption := dlgIDEOptions;
144   BuildModesLabel.Caption := lisBuildModes;
145   ButtonPanel.OKButton.Caption := lisMenuOk;
146   ButtonPanel.OKButton.OnClick := @OKButtonClick;
147   ButtonPanel.OKButton.ModalResult := mrNone;
148   ButtonPanel.CancelButton.Caption := lisCancel;
149   ButtonPanel.CancelButton.OnClick := @CancelButtonClick;
150   ButtonPanel.HelpButton.Caption:= lisMenuHelp;
151   ButtonPanel.HelpButton.OnClick := @HelpButtonClick;
152   IDEDialogLayoutList.ApplyLayout(Self);
153   BuildModeComboBox.DropDownCount := EnvironmentOptions.DropDownCount;
154 end;
155 
156 procedure TIDEOptionsDialog.FormShow(Sender: TObject);
157 begin
158   // make the category visible in the treeview
159   if (CategoryTree.Selected<>nil) and (CategoryTree.Selected.Parent<>nil) then
160     CategoryTree.TopItem:=CategoryTree.Selected.Parent;
161   BuildModesManager.OnLoadIDEOptionsHook := @LoadIDEOptions;
162   BuildModesManager.OnSaveIDEOptionsHook := @SaveIDEOptions;
163   UpdateBuildModeGUI;
164 end;
165 
166 procedure TIDEOptionsDialog.HelpButtonClick(Sender: TObject);
167 begin
168   if FPrevEditor<>nil then
169     LazarusHelp.ShowHelpForIDEControl(FPrevEditor)
170   else
171     LazarusHelp.ShowHelpForIDEControl(Self);
172 end;
173 
174 procedure TIDEOptionsDialog.CategoryTreeChange(Sender: TObject; Node: TTreeNode);
175 var
176   GroupClass: TAbstractIDEOptionsClass;
177   AEditor: TAbstractIDEOptionsEditor;
178 begin
179   if Assigned(Node) then begin
180     // The GUI filter can hide nodes. Get a visible node.
181     if not Node.Visible then
182       Node := Node.GetPrevVisible;
183     // Group category node Has Data=nil. Get the first sub-item.
184     while Assigned(Node) and not Assigned(Node.Data) do
185       Node := Node.GetFirstVisibleChild;
186   end;
187   AEditor := nil;
188   GroupClass := nil;
189   if Assigned(Node) and Assigned(Node.Data) then begin
190     Assert(TObject(Node.Data) is TAbstractIDEOptionsEditor,
191       'TIDEOptionsDialog.CategoryTreeChange: Node.Data is not TAbstractIDEOptionsEditor');
192     if CategoryTree.Selected = nil then
193       Node.Selected := True;
194     AEditor := TAbstractIDEOptionsEditor(Node.Data);
195     GroupClass := FindGroupClass(Node);
196   end;
197   // Show the Build Mode panel for project compiler options
198   SetBuildModeVisibility((GroupClass <> nil) and (GroupClass.InheritsFrom(TProjectCompilerOptions)));
199   // Hide the old and show the new editor frame
200   if Assigned(AEditor) then
201     FNewLastSelected := AEditor.Rec;
202   if (AEditor <> FPrevEditor) then begin
203     if Assigned(FPrevEditor) then
204       FPrevEditor.Visible := False;
205     if Assigned(AEditor) then begin
206       AEditor.Align := alClient;
207       AEditor.BorderSpacing.Around := 6;
208       AEditor.Visible := True;
209     end;
210     FPrevEditor := AEditor;
211   end;
212 end;
213 
214 procedure TIDEOptionsDialog.BuildModeComboBoxSelect(Sender: TObject);
215 begin
216   if AllBuildModes then
217     ShowMessage(lisThisWillAllowChangingAllBuildModesAtOnceNotImpleme)
218   else begin
219     Assert(BuildModeSelectPanel.Visible, 'BuildModeComboBoxSelect: BuildModeSelectPanel not Visible');
220     SwitchBuildMode(BuildModeComboBox.Text);
221   end;
222 end;
223 
224 procedure TIDEOptionsDialog.BuildModeManageButtonClick(Sender: TObject);
225 begin
226   if ShowBuildModesDlg(Project1.SessionStorage in pssHasSeparateSession) <> mrOK then
227     exit;
228   UpdateBuildModeCombo(BuildModeComboBox);
229 end;
230 
231 procedure TIDEOptionsDialog.CategoryTreeCollapsed(Sender: TObject; Node: TTreeNode);
232 begin
233   if node.Deleting then exit;
234   if (Node.Data <> nil) then
235     TAbstractIDEOptionsEditor(Node.Data).Rec^.Collapsed := True
236   else
237   if (Node.GetFirstChild <> nil) and (Node.GetFirstChild.Data <> nil) then
238     TAbstractIDEOptionsEditor(Node.GetFirstChild.Data).GroupRec^.Collapsed := True;
239 end;
240 
241 procedure TIDEOptionsDialog.CategoryTreeExpanded(Sender: TObject; Node: TTreeNode);
242 begin
243   if node.Deleting then exit;
244   if (Node.Data <> nil) then
245     TAbstractIDEOptionsEditor(Node.Data).Rec^.Collapsed := False
246   else
247   if (Node.GetFirstChild <> nil) and (Node.GetFirstChild.Data <> nil) then
248     TAbstractIDEOptionsEditor(Node.GetFirstChild.Data).GroupRec^.Collapsed := False;
249 end;
250 
251 procedure TIDEOptionsDialog.CategoryTreeKeyDown(Sender: TObject; var Key: Word;
252   Shift: TShiftState);
253 var
254   Command: Word;
255 begin
256   Command := EditorOpts.KeyMap.TranslateKey(Key,Shift,nil);
257   if (Command=ecContextHelp) and (FPrevEditor <> nil) then begin
258     Key:=VK_UNKNOWN;
259     LazarusHelp.ShowHelpForIDEControl(FPrevEditor);
260   end;
261 end;
262 
FilterEditFilterItemnull263 function TIDEOptionsDialog.FilterEditFilterItem(ItemData: Pointer; out Done: Boolean): Boolean;
264 var
265   OptEditor: TAbstractIDEOptionsEditor;
266 begin
267   Result:=False;
268   Done:=False;                        // Filter will use also the node caption.
269   if ItemData=nil then Exit;
270   OptEditor:=TAbstractIDEOptionsEditor(ItemData);
271   OptEditor.RememberDefaultStyles;
272   Result:=OptEditor.ContainsTextInCaption(FilterEdit.Filter);
273 end;
274 
275 procedure TIDEOptionsDialog.OkButtonClick(Sender: TObject);
276 begin
277   IDEEditorGroups.LastSelected := FNewLastSelected;
278   if not CheckValues then
279     Exit;
280   IDEDialogLayoutList.SaveLayout(Self);
281   ModalResult := mrOk;
282 end;
283 
284 procedure TIDEOptionsDialog.CancelButtonClick(Sender: TObject);
285 begin
286   IDEDialogLayoutList.SaveLayout(Self);
287   ModalResult := mrCancel;
288 end;
289 
FindGroupClassnull290 function TIDEOptionsDialog.FindGroupClass(Node: TTreeNode): TAbstractIDEOptionsClass;
291 // Find the group category class where this node belongs to.
292 begin
293   while Assigned(Node) do begin
294     if Assigned(Node.Parent) then
295       Node := Node.Parent
296     else
297       Break;
298   end;
299   // GroupRec is stored in the first child editor
300   Result := nil;
301   if Assigned(Node) then
302     Result := TAbstractIDEOptionsEditor(Node.GetFirstChild.Data).GroupRec^.GroupClass;
303 end;
304 
305 procedure TIDEOptionsDialog.TraverseSettings(AOptions: TAbstractIDEOptions;
306   anAction: TIDEOptsDlgAction);
307 var
308   ClassTypeForCompare: TClass;
309 
310   procedure Traverse(Node: TTreeNode);
311   begin
312     if Node <> nil then
313     begin
314       if Node.Data <> nil then
315         with TAbstractIDEOptionsEditor(Node.Data) do
316           if ((ClassTypeForCompare = nil) and (SupportedOptionsClass = nil))
317           or ((SupportedOptionsClass <> nil)
318           and ClassTypeForCompare.InheritsFrom(SupportedOptionsClass)) then
319           begin
320             case anAction of
321             iodaRead: ReadSettings(AOptions);
322             iodaWrite: WriteSettings(AOptions);
323             iodaRestore: RestoreSettings(AOptions);
324             end;
325           end;
326       Traverse(Node.GetFirstChild);
327       Traverse(Node.GetNextSibling);
328     end;
329   end;
330 
331 begin
332   CreateEditors;
333   if AOptions <> nil then
334     ClassTypeForCompare := AOptions.ClassType
335   else
336     ClassTypeForCompare := nil;
337 
338   Traverse(CategoryTree.Items.GetFirstNode);
339 end;
340 
341 procedure TIDEOptionsDialog.ReadAll;
342 type
343   TStage = (sBefore, sRead, sAfter);
344 var
345   i: integer;
346   Rec: PIDEOptionsGroupRec;
347   Instance: TAbstractIDEOptions;
348   InstanceList: TFPList;
349   stag: TStage;
350 begin
351   for stag:=low(TStage) to High(TStage) do
352   begin
353     InstanceList:=TFPList.Create;
354     for i := 0 to IDEEditorGroups.Count - 1 do
355     begin
356       Rec := IDEEditorGroups[i];
357       if not PassesFilter(Rec) then
358         Continue;
359       if Assigned(Rec^.Items) and Assigned(Rec^.GroupClass) then
360       begin
361         Instance := Rec^.GroupClass.GetInstance;
362         if (InstanceList.IndexOf(Instance)<0) and Assigned(Instance) then
363         begin
364           InstanceList.Add(Instance);
365           case stag of
366           sBefore:
367             Instance.DoBeforeRead;
368           sRead:
369             TraverseSettings(Instance,iodaRead);
370           sAfter:
371             Instance.DoAfterRead;
372           end;
373         end;
374       end;
375     end;
376     if stag=sRead then
377       TraverseSettings(nil,iodaRead); // load settings that does not belong to any group
378     InstanceList.Free;
379   end;
380 end;
381 
382 procedure TIDEOptionsDialog.WriteAll(Restore: boolean);
383 type
384   TStage = (sBefore, sWrite, sAfter);
385 var
386   i: integer;
387   Rec: PIDEOptionsGroupRec;
388   Instance: TAbstractIDEOptions;
389   stag: TStage;
390 begin
391   for stag:=low(TStage) to High(TStage) do
392   begin
393     for i := 0 to IDEEditorGroups.Count - 1 do
394     begin
395       Rec := IDEEditorGroups[i];
396       if not PassesFilter(Rec) then
397         Continue;
398       if Assigned(Rec^.Items) and Assigned(Rec^.GroupClass) then
399       begin
400         Instance := Rec^.GroupClass.GetInstance;
401         if Assigned(Instance) then
402         begin
403           case stag of
404           sBefore:
405             Instance.DoBeforeWrite(Restore);
406           sWrite:
407             if Restore then
408               TraverseSettings(Instance,iodaRestore)
409             else
410               TraverseSettings(Instance,iodaWrite);
411           sAfter:
412             Instance.DoAfterWrite(Restore);
413           end;
414         end;
415       end;
416     end;
417 
418     // save settings that do not belong to any group
419     if stag=sWrite then
420       if Restore then
421         TraverseSettings(nil,iodaRestore)
422       else
423         TraverseSettings(nil,iodaWrite);
424   end;
425 end;
426 
CheckValuesnull427 function TIDEOptionsDialog.CheckValues: boolean;
428 
Traversenull429   function Traverse(Node: TTreeNode): Boolean;
430   begin
431     if Node <> nil then
432     begin
433       if Node.Data <> nil then
434         Result := TAbstractIDEOptionsEditor(Node.Data).Check
435       else
436         Result := True;
437 
438       Result := Result and
439                 Traverse(Node.GetFirstChild) and
440                 Traverse(Node.GetNextSibling);
441     end
442     else
443       Result := True;
444   end;
445 
446 begin
447   Result := Traverse(CategoryTree.Items.GetFirstNode);
448 end;
449 
450 procedure TIDEOptionsDialog.LoadIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions);
451 begin
452   if Assigned(OnLoadIDEOptionsHook) then
453     OnLoadIDEOptionsHook(Self, AOptions);
454   TraverseSettings(AOptions,iodaRead);
455   if AOptions is TProjectCompilerOptions then
456     UpdateBuildModeButtons;
457 end;
458 
459 procedure TIDEOptionsDialog.SaveIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions);
460 begin
461   TraverseSettings(AOptions,iodaWrite);
462   if Assigned(OnSaveIDEOptionsHook) then
463     OnSaveIDEOptionsHook(Self, AOptions);
464 end;
465 
466 procedure TIDEOptionsDialog.CreateEditors;
467 
SearchNodenull468   function SearchNode(Node: TTreeNode; Index: Integer): TTreeNode;
469   begin
470     Result := nil;
471     if Node =  nil then
472       Exit;
473     if (Node.Data <> nil) and (TAbstractIDEOptionsEditor(Node.Data).Tag = Index) then
474       Result := Node;
475     if Result <> nil then
476       Exit;
477     Result := SearchNode(Node.GetFirstChild, Index);
478     if Result <> nil then
479       Exit;
480     Result := SearchNode(Node.GetNextSibling, Index);
481   end;
482 
483 var
484   Instance: TAbstractIDEOptionsEditor;
485   GroupNode, ItemNode, ItemParent: TTreeNode;
486   i, j: integer;
487   Rec: PIDEOptionsGroupRec;
488   ACaption: string;
489 begin
490   if FEditorsCreated then
491     Exit;
492   FEditorsCreated := True;
493   IDEEditorGroups.Resort;
494   FSelectNode := nil;
495 
496   for i := 0 to IDEEditorGroups.Count - 1 do
497   begin
498     Rec := IDEEditorGroups[i];
499     //DebugLn(['TIDEOptionsDialog.CreateEditors ',Rec^.GroupClass.ClassName]);
500     if PassesFilter(Rec) and (Rec^.Items <> nil) then
501     begin
502       if Rec^.GroupClass<>nil then
503         ACaption := Rec^.GroupClass.GetGroupCaption
504       else
505         ACaption := format('Group<%d>',[i]);
506       GroupNode := CategoryTree.Items.AddChild(nil, ACaption);
507       for j := 0 to Rec^.Items.Count - 1 do
508       begin
509         Instance := Rec^.Items[j]^.EditorClass.Create(Self);
510         Instance.OnLoadIDEOptions := @LoadIDEOptions;
511         Instance.OnSaveIDEOptions := @SaveIDEOptions;
512         Instance.Setup(Self);
513         Instance.Tag := Rec^.Items[j]^.Index;
514         Instance.Visible := False;
515         Instance.Parent := EditorsPanel;
516         Instance.Rec := Rec^.Items[j];
517 
518         ItemParent := GroupNode;
519         if Rec^.Items[j]^.Parent <> NoParent then begin
520           ItemParent := SearchNode(GroupNode.GetFirstChild, Rec^.Items[j]^.Parent);
521           if ItemParent = nil then
522             ItemParent := GroupNode;
523         end;
524 
525         ItemNode := CategoryTree.Items.AddChild(ItemParent, Instance.GetTitle);
526         ItemNode.Data := Instance;
527 
528         if ItemParent.Data <> nil then begin
529           Instance := TAbstractIDEOptionsEditor(ItemParent.Data);
530           ItemParent.Expanded := not Instance.Rec^.Collapsed;
531         end;
532         if IDEEditorGroups.LastSelected = Rec^.Items[j] then
533           FSelectNode := ItemNode;
534       end;
535       if (GroupNode.GetFirstChild <> nil) and (GroupNode.GetFirstChild.Data <> nil) then
536         TAbstractIDEOptionsEditor(GroupNode.GetFirstChild.Data).GroupRec := Rec;
537       GroupNode.Expanded := not Rec^.Collapsed;
538     end;
539   end;
540   if FSelectNode <> nil then
541     FSelectNode.Selected := True;
542 end;
543 
SearchEditorNodenull544 function TIDEOptionsDialog.SearchEditorNode(AEditor: TAbstractIDEOptionsEditorClass): TTreeNode;
545 
Traversenull546   function Traverse(ANode: TTreeNode): TTreeNode;
547   begin
548     Result := nil;
549     if ANode <> nil then
550     begin
551       if (ANode.Data <> nil) and (TObject(ANode.Data).ClassType = AEditor) then
552         Result := ANode;
553       if Result = nil then
554         Result := Traverse(ANode.GetFirstChild);
555       if Result = nil then
556         Result := Traverse(ANode.GetNextSibling);
557     end;
558   end;
559 
560 begin
561   Result := Traverse(CategoryTree.Items.GetFirstNode);
562 end;
563 
SearchEditorNodenull564 function TIDEOptionsDialog.SearchEditorNode(
565   const IDEOptionsEditorClassName: string): TTreeNode;
566 
Traversenull567   function Traverse(ANode: TTreeNode): TTreeNode;
568   begin
569     Result := nil;
570     if ANode <> nil then
571     begin
572       if (ANode.Data <> nil)
573       and (CompareText(TObject(ANode.Data).ClassName,IDEOptionsEditorClassName)=0) then
574         Result := ANode;
575       if Result = nil then
576         Result := Traverse(ANode.GetFirstChild);
577       if Result = nil then
578         Result := Traverse(ANode.GetNextSibling);
579     end;
580   end;
581 
582 begin
583   Result := Traverse(CategoryTree.Items.GetFirstNode);
584 end;
585 
TIDEOptionsDialog.PassesFilternull586 function TIDEOptionsDialog.PassesFilter(ARec: PIDEOptionsGroupRec): Boolean;
587 var
588   i: Integer;
589 begin
590   if (ARec^.GroupClass = nil) then
591     Exit(Length(OptionsFilter) = 0);
592 
593   for i := 0 to Length(OptionsFilter) - 1 do
594     if ARec^.GroupClass.InheritsFrom(OptionsFilter[i]) then
595       Exit(True);
596 
597   Result := False;
598 end;
599 
600 procedure TIDEOptionsDialog.SetSettings(const AValue: TIDEOptionsEditorSettings);
601 begin
602   if FSettings <> AValue then
603   begin
604     FSettings := AValue;
605     if ioesReadOnly in Settings then
606       ButtonPanel.ShowButtons := ButtonPanel.ShowButtons - [pbOK, pbCancel] + [pbClose]
607     else
608       ButtonPanel.ShowButtons := ButtonPanel.ShowButtons + [pbOK, pbCancel] - [pbClose];
609   end;
610 end;
611 
TIDEOptionsDialog.AllBuildModesnull612 function TIDEOptionsDialog.AllBuildModes: boolean;
613 begin
614   Result:=BuildModeComboBox.Text = lisAllBuildModes;
615 end;
616 
617 procedure TIDEOptionsDialog.UpdateBuildModeButtons;
618 var
619   ModeMatrix: TCompOptModeMatrixFrame;
620 begin
621   ModeMatrix:=TCompOptModeMatrixFrame(FindEditor(TCompOptModeMatrixFrame));
622   if Assigned(ModeMatrix) then
623     ModeMatrix.UpdateModes;
624 end;
625 
626 procedure TIDEOptionsDialog.SetBuildModeVisibility(AVisibility: Boolean);
627 begin
628   BuildModeSelectPanel.Visible := AVisibility;
629   if AVisibility then
630   begin
631     EditorsPanel.AnchorSide[akTop].Control := BuildModeSelectPanel;
632     EditorsPanel.AnchorSide[akTop].Side := asrBottom;
633   end
634   else
635   begin
636     EditorsPanel.AnchorSide[akTop].Control := Self;
637     EditorsPanel.AnchorSide[akTop].Side := asrTop;
638   end;
639 end;
640 
641 procedure TIDEOptionsDialog.DoOpenEditor(EditorToOpen: TAbstractIDEOptionsEditorClass);
642 var
643   Node: TTreeNode;
644 begin
645   if EditorToOpen = nil then
646   begin
647     if FSelectNode <> nil then
648       Node := FSelectNode
649     else
650       Node := CategoryTree.Items.GetFirstNode
651   end
652   else
653     Node := SearchEditorNode(EditorToOpen);
654   if Node <> nil then
655     CategoryTree.Selected := Node;
656   FSelectNode := nil;
657 end;
658 
TIDEOptionsDialog.ShowModalnull659 function TIDEOptionsDialog.ShowModal: Integer;
660 begin
661   DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TIDEOptionsDialog.ShowModal'){$ENDIF};
662   try
663     CreateEditors;
664     DoOpenEditor(FEditorToOpen);
665   finally
666     EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TIDEOptionsDialog.ShowModal'){$ENDIF};
667   end;
668   Result := inherited ShowModal;
669 end;
670 
TIDEOptionsDialog.AddButtonnull671 function TIDEOptionsDialog.AddButton: TBitBtn;
672 begin
673   Result := TBitBtn.Create(Self);
674   Result.Align := alCustom;
675   Result.Default := false;
676   Result.Constraints.MinWidth := 25;
677   Result.AutoSize := true;
678   Result.Parent := ButtonPanel;
679 end;
680 
681 procedure TIDEOptionsDialog.AddButtonSeparator;
682 var
683   pnl: TPanel;
684 begin
685   pnl := TPanel.Create(Self);
686   pnl.Align := alCustom;
687   pnl.BevelOuter := bvNone;
688   pnl.Width := 6;
689   pnl.Parent := ButtonPanel;
690 end;
691 
AddControlnull692 function TIDEOptionsDialog.AddControl(AControlClass: TControlClass): TControl;
693 begin
694   Result := AControlClass.Create(Self);
695   Result.Parent := SettingsPanel;
696   Result.Align := alBottom;
697   Result.BorderSpacing.Around := 6;
698 end;
699 
700 procedure TIDEOptionsDialog.OpenEditor(AEditor: TAbstractIDEOptionsEditorClass);
701 begin
702   if IsVisible then
703     DoOpenEditor(AEditor)
704   else
705     FEditorToOpen := AEditor;
706 end;
707 
708 procedure TIDEOptionsDialog.OpenEditor(GroupIndex, AIndex: integer);
709 begin
710   if IsVisible then
711     DoOpenEditor(FindEditorClass(GroupIndex,AIndex))
712   else
713     FEditorToOpen := FindEditorClass(GroupIndex,AIndex);
714 end;
715 
FindEditornull716 function TIDEOptionsDialog.FindEditor(AEditor: TAbstractIDEOptionsEditorClass): TAbstractIDEOptionsEditor;
717 var
718   Node: TTreeNode;
719 begin
720   Node := SearchEditorNode(AEditor);
721   if Node <> nil then
722     Result := TAbstractIDEOptionsEditor(Node.Data)
723   else
724     Result := nil;
725 end;
726 
FindEditornull727 function TIDEOptionsDialog.FindEditor(const IDEOptionsEditorClassName: string
728   ): TAbstractIDEOptionsEditor;
729 var
730   Node: TTreeNode;
731 begin
732   Node := SearchEditorNode(IDEOptionsEditorClassName);
733   if Node <> nil then
734     Result := TAbstractIDEOptionsEditor(Node.Data)
735   else
736     Result := nil;
737 end;
738 
FindEditornull739 function TIDEOptionsDialog.FindEditor(GroupIndex, AIndex: integer): TAbstractIDEOptionsEditor;
740 var
741   EditorClass: TAbstractIDEOptionsEditorClass;
742 begin
743   EditorClass := FindEditorClass(GroupIndex, AIndex);
744   if EditorClass <> nil then
745     Result := FindEditor(EditorClass)
746   else
747     Result := nil;
748 end;
749 
FindEditorClassnull750 function TIDEOptionsDialog.FindEditorClass(GroupIndex, AIndex: integer): TAbstractIDEOptionsEditorClass;
751 var
752   Grp: PIDEOptionsGroupRec;
753   i: Integer;
754 begin
755   Result:=nil;
756   Grp:=IDEEditorGroups.GetByIndex(GroupIndex);
757   if (Grp=nil) or (Grp^.Items=nil) then exit;
758   for i:=0 to Grp^.Items.Count-1 do
759   begin
760     if Grp^.Items[i]^.Index=AIndex then
761     begin
762       Result:=Grp^.Items[i]^.EditorClass;
763       exit;
764     end;
765   end;
766 end;
767 
TIDEOptionsDialog.ResetFilternull768 function TIDEOptionsDialog.ResetFilter: Boolean;
769 begin
770   Result := FilterEdit.Filter <> '';
771   FilterEdit.ResetFilter;
772 end;
773 
774 procedure TIDEOptionsDialog.UpdateBuildModeGUI;
775 begin
776   UpdateBuildModeCombo(BuildModeComboBox);
777   UpdateBuildModeButtons;
778 end;
779 
780 end.
781 
782