{ *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** Author: Mattias Gaertner Abstract: This unit defines a dialog for the lazarus options. } unit IDEOptionsDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, // LCL LCLType, Controls, Forms, ComCtrls, Buttons, ButtonPanel, ExtCtrls, StdCtrls, Dialogs, Graphics, // LazControls TreeFilterEdit, DividerBevel, // LazUtils LazLoggerBase, // IdeIntf IDEWindowIntf, IDEOptionsIntf, IDEOptEditorIntf, IDECommands, IDEHelpIntf, IdeIntfStrConsts, IDEImagesIntf, ProjectIntf, // IdeConfig EnvironmentOpts, // IDE EditorOptions, EnvGuiOptions, Compiler_ModeMatrix, Project, BuildModesManager, BuildManager, LazarusIDEStrConsts, // Packager PackageDefs; type TIDEOptsDlgAction = ( iodaRead, iodaWrite, iodaRestore ); TIDEOptionsEditorFilter = array of TAbstractIDEOptionsClass; { TIDEOptionsDialog } TIDEOptionsDialog = class(TAbstractOptionsEditorDialog) BuildModeComboBox: TComboBox; BuildModeManageButton: TSpeedButton; BuildModeSelectPanel: TPanel; ButtonPanel: TButtonPanel; CategoryPanel: TPanel; CategoryTree: TTreeView; Splitter: TSplitter; EditorsPanel: TScrollBox; LeftPanel: TPanel; RightPanel: TPanel; BuildModeDividerBevel: TDividerBevel; FilterEdit: TTreeFilterEdit; BuildModesLabel: TLabel; SettingsPanel: TPanel; btnApply: TBitBtn; procedure ApplyButtonClick(Sender: TObject); procedure BuildModeComboBoxSelect(Sender: TObject); procedure BuildModeManageButtonClick(Sender: TObject); procedure CategoryTreeChange(Sender: TObject; Node: TTreeNode); procedure CategoryTreeCollapsed(Sender: TObject; Node: TTreeNode); procedure CategoryTreeCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; {%H-}State: TCustomDrawState; var {%H-}DefaultDraw: Boolean); procedure CategoryTreeExpanded(Sender: TObject; Node: TTreeNode); procedure CategoryTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); function FilterEditFilterItem(ItemData: Pointer; out Done: Boolean): Boolean; procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormShow(Sender: TObject); procedure HelpButtonClick(Sender: TObject); procedure OkButtonClick(Sender: TObject); procedure CancelButtonClick(Sender: TObject); private FTitle: string; FIsProjectOptionsDialog: boolean; FEditorsCreated: Boolean; FEditorToOpen: TAbstractIDEOptionsEditorClass; FNewLastSelected: PIDEOptionsEditorRec; FOnLoadOptionsHook: TOnLoadIDEOptions; FOnSaveOptionsHook: TOnSaveIDEOptions; FOptionsFilter: TIDEOptionsEditorFilter; FPrevEditor: TAbstractIDEOptionsEditor; FSelectNode: TTreeNode; FSettings: TIDEOptionsEditorSettings; function Apply: Boolean; function FindGroupClass(Node: TTreeNode): TAbstractIDEOptionsClass; procedure TraverseSettings(AOptions: TAbstractIDEOptions; anAction: TIDEOptsDlgAction); function CheckValues: boolean; procedure DoOpenEditor(EditorToOpen: TAbstractIDEOptionsEditorClass); procedure LoadIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions); procedure SaveIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions); procedure CreateEditors; function SearchEditorNode(AEditor: TAbstractIDEOptionsEditorClass): TTreeNode; function SearchEditorNode(const IDEOptionsEditorClassName: string): TTreeNode; function PassesFilter(ARec: PIDEOptionsGroupRec): Boolean; procedure SetSettings(const AValue: TIDEOptionsEditorSettings); function AllBuildModes: boolean; procedure UpdateBuildModeButtons; procedure UpdateDialogCaption; procedure SetTitle(ATitle: string); public constructor Create(AOwner: TComponent); override; function ShowModal: Integer; override; function AddButton: TBitBtn; override; procedure AddButtonSeparator; override; function AddControl(AControlClass: TControlClass): TControl; override; procedure OpenEditor(AEditor: TAbstractIDEOptionsEditorClass); override; procedure OpenEditor(GroupIndex, AIndex: integer); override; function FindEditor(AEditor: TAbstractIDEOptionsEditorClass): TAbstractIDEOptionsEditor; override; function FindEditor(const IDEOptionsEditorClassName: string): TAbstractIDEOptionsEditor; override; function FindEditor(GroupIndex, AIndex: integer): TAbstractIDEOptionsEditor; override; function FindEditorClass(GroupIndex, AIndex: integer): TAbstractIDEOptionsEditorClass; override; function ResetFilter: Boolean; override; procedure UpdateBuildModeGUI; override; procedure ReadAll; procedure WriteAll(Restore: boolean); public property Title: string read FTitle write SetTitle; property OptionsFilter: TIDEOptionsEditorFilter read FOptionsFilter write FOptionsFilter; property Settings: TIDEOptionsEditorSettings read FSettings write SetSettings; property OnLoadIDEOptionsHook: TOnLoadIDEOptions read FOnLoadOptionsHook write FOnLoadOptionsHook; property OnSaveIDEOptionsHook: TOnSaveIDEOptions read FOnSaveOptionsHook write FOnSaveOptionsHook; end; implementation {$R *.lfm} procedure SetDropDownCount(AWinControl: TWinControl); // Set global DropDownCount to all TCustomComboBox descendants under AWinControl. var i: integer; begin for i := 0 to AWinControl.ControlCount - 1 do begin if AWinControl.Controls[i] is TCustomComboBox then TCustomComboBox(AWinControl.Controls[i]).DropDownCount := EnvironmentOptions.DropDownCount; // recursive call if AWinControl.Controls[i] is TWinControl then SetDropDownCount(TWinControl(AWinControl.Controls[i])); end; end; { TIDEOptionsDialog } constructor TIDEOptionsDialog.Create(AOwner: TComponent); begin inherited Create(AOwner); FPrevEditor := nil; FEditorsCreated := False; FEditorToOpen := nil; BuildModeSelectPanel.Visible := False; btnApply := AddButton; btnApply.LoadGlyphFromResource(idButtonRetry); btnApply.OnClick := @ApplyButtonClick; ButtonPanel.OKButton.OnClick := @OKButtonClick; ButtonPanel.OKButton.ModalResult := mrNone; ButtonPanel.CancelButton.OnClick := @CancelButtonClick; ButtonPanel.HelpButton.OnClick := @HelpButtonClick; // caption Caption := dlgIDEOptions; FTitle := Caption; BuildModesLabel.Caption := lisBuildModes; ButtonPanel.OKButton.Caption := lisBtnOk; ButtonPanel.CancelButton.Caption := lisCancel; ButtonPanel.HelpButton.Caption:= lisMenuHelp; btnApply.Caption := lisApply; // hint ButtonPanel.ShowHint := true; btnApply.Hint := '[Shift+Enter]'; BuildModeManageButton.Hint := lisEditBuildModes + ' [Ctrl+B]'; BuildModeComboBox.Hint := lisSelectBuildMode + ' [Ctrl+Shift+B]'; FilterEdit.TextHint := lisFindOption + ' [Ctrl+F]'; // images IDEImages.AssignImage(BuildModeManageButton, 'menu_compiler_options'); BuildModeComboBox.DropDownCount := EnvironmentOptions.DropDownCount; IDEDialogLayoutList.ApplyLayout(Self); end; procedure TIDEOptionsDialog.FormShow(Sender: TObject); begin // make sure the Selected Item is Visible, // and try to set the Top Category to TopItem. // 1. make the Top Category the TopItem and visible in the treeview // 2. make sure the Selected Item is Visible in the treeview if CategoryTree.Selected<>nil then begin CategoryTree.TopItem:=CategoryTree.Selected.GetParentNodeOfAbsoluteLevel(0); CategoryTree.Selected.MakeVisible; end; // select first not empty category if (CategoryTree.Selected <> nil) and (CategoryTree.Selected.Data = nil) and // is group category (CategoryTree.Selected.GetFirstVisibleChild <> nil) then CategoryTree.Selected := CategoryTree.Selected.GetFirstVisibleChild; BuildModesManager.OnLoadIDEOptionsHook := @LoadIDEOptions; BuildModesManager.OnSaveIDEOptionsHook := @SaveIDEOptions; UpdateBuildModeGUI; end; procedure TIDEOptionsDialog.HelpButtonClick(Sender: TObject); begin if FPrevEditor<>nil then LazarusHelp.ShowHelpForIDEControl(FPrevEditor) else LazarusHelp.ShowHelpForIDEControl(Self); end; procedure TIDEOptionsDialog.CategoryTreeChange(Sender: TObject; Node: TTreeNode); var GroupClass: TAbstractIDEOptionsClass; AEditor: TAbstractIDEOptionsEditor; begin if Assigned(Node) then begin // The GUI filter can hide nodes. Get a visible node. if not Node.Visible then Node := Node.GetPrevVisible; // Group category node Has Data=nil. Get the first sub-item. while Assigned(Node) and not Assigned(Node.Data) do Node := Node.GetFirstVisibleChild; end; AEditor := nil; GroupClass := nil; if Assigned(Node) and Assigned(Node.Data) then begin Assert(TObject(Node.Data) is TAbstractIDEOptionsEditor, 'TIDEOptionsDialog.CategoryTreeChange: Node.Data is not TAbstractIDEOptionsEditor'); if CategoryTree.Selected = nil then Node.Selected := True; AEditor := TAbstractIDEOptionsEditor(Node.Data); GroupClass := FindGroupClass(Node); end; FIsProjectOptionsDialog := Assigned(GroupClass) and (GroupClass.InheritsFrom(TAbstractIDEProjectOptions) or GroupClass.InheritsFrom(TProjectCompilerOptions)); UpdateDialogCaption; // Show the Build Mode panel for project compiler options BuildModeSelectPanel.Visible := Assigned(GroupClass) and GroupClass.InheritsFrom(TProjectCompilerOptions); // Show the Apply button only for global options (not project or package options). btnApply.Visible := Assigned(GroupClass) and GroupClass.InheritsFrom(TAbstractIDEEnvironmentOptions); // Hide the old and show the new editor frame if Assigned(AEditor) then FNewLastSelected := AEditor.Rec; if (AEditor <> FPrevEditor) then begin if Assigned(FPrevEditor) then FPrevEditor.Visible := False; if Assigned(AEditor) then begin AEditor.Align := alClient; SetDropDownCount(AEditor); AEditor.Visible := True; end; FPrevEditor := AEditor; end; end; procedure TIDEOptionsDialog.BuildModeComboBoxSelect(Sender: TObject); begin if not FIsProjectOptionsDialog then exit; if AllBuildModes then ShowMessage(lisThisWillAllowChangingAllBuildModesAtOnceNotImpleme) else begin SwitchBuildMode(BuildModeComboBox.Text); UpdateDialogCaption; end; end; procedure TIDEOptionsDialog.BuildModeManageButtonClick(Sender: TObject); begin if not FIsProjectOptionsDialog then exit; if ShowBuildModesDlg(Project1.SessionStorage in pssHasSeparateSession) = mrOK then begin UpdateBuildModeCombo(BuildModeComboBox); UpdateDialogCaption; end; end; procedure TIDEOptionsDialog.CategoryTreeCollapsed(Sender: TObject; Node: TTreeNode); begin if Node.Deleting then exit; if Assigned(Node.Data) then TAbstractIDEOptionsEditor(Node.Data).Rec^.Collapsed := True else if Assigned(Node.GetFirstChild) and Assigned(Node.GetFirstChild.Data) then TAbstractIDEOptionsEditor(Node.GetFirstChild.Data).GroupRec^.Collapsed := True; end; procedure TIDEOptionsDialog.CategoryTreeCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); begin // make group categories bold if Node.Data = nil then // is group category Node.TreeView.Canvas.Font.Style := [fsBold] else Node.TreeView.Canvas.Font.Style := []; end; procedure TIDEOptionsDialog.CategoryTreeExpanded(Sender: TObject; Node: TTreeNode); begin if node.Deleting then exit; if Assigned(Node.Data) then TAbstractIDEOptionsEditor(Node.Data).Rec^.Collapsed := False else if Assigned(Node.GetFirstChild) and Assigned(Node.GetFirstChild.Data) then TAbstractIDEOptionsEditor(Node.GetFirstChild.Data).GroupRec^.Collapsed := False; end; procedure TIDEOptionsDialog.CategoryTreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var Command: Word; begin Command := EditorOpts.KeyMap.TranslateKey(Key,Shift,nil); if (Command=ecContextHelp) and (FPrevEditor <> nil) then begin Key:=VK_UNKNOWN; LazarusHelp.ShowHelpForIDEControl(FPrevEditor); end; end; function TIDEOptionsDialog.FilterEditFilterItem(ItemData: Pointer; out Done: Boolean): Boolean; var OptEditor: TAbstractIDEOptionsEditor; begin Result:=False; Done:=False; // Filter will use also the node caption. if ItemData=nil then Exit; OptEditor:=TAbstractIDEOptionsEditor(ItemData); OptEditor.RememberDefaultStyles; Result:=OptEditor.ContainsTextInCaption(FilterEdit.Filter); end; procedure TIDEOptionsDialog.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin if WindowState <> wsMaximized then IDEDialogLayoutList.SaveLayout(self); end; procedure TIDEOptionsDialog.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin // dialog if (Key = VK_ESCAPE) and (Shift = []) then begin CancelButtonClick(Sender); Key := 0; end else if (Key = VK_RETURN) and (Shift = [ssCtrl]) then begin OkButtonClick(Sender); Key := 0; end else if (Key = VK_RETURN) and (Shift = [ssShift]) then begin ApplyButtonClick(Sender); Key := 0; end // filter else if (Key = VK_F) and (Shift = [ssCtrl]) then begin if FilterEdit.CanSetFocus then FilterEdit.SetFocus; Key := 0; end // build modes else if (Key = VK_B) and (Shift = [ssCtrl]) then begin BuildModeManageButtonClick(Sender); Key := 0; end else if (Key = VK_B) and (Shift = [ssCtrl, ssShift]) then begin with BuildModeComboBox do if FIsProjectOptionsDialog and (Items.Count > 0) then begin // next mode (in a circle) ItemIndex := (ItemIndex + 1) mod Items.Count; BuildModeComboBoxSelect(Sender); end; Key := 0; end; end; function TIDEOptionsDialog.Apply: Boolean; begin Result := CheckValues; if not Result then begin DebugLn(['TIDEOptionsDialog.Apply: CheckValues failed!']); Exit; end; IDEEditorGroups.LastSelected := FNewLastSelected; WriteAll(false); // write new values end; procedure TIDEOptionsDialog.ApplyButtonClick(Sender: TObject); // This is called only for global options, ApplyButton is hidden otherwise. begin if not Apply then Exit; // update TaskBarBehavior immediately if EnvironmentGuiOpts.Desktop.SingleTaskBarButton then Application.TaskBarBehavior := tbSingleButton else Application.TaskBarBehavior := tbDefault; // update DropDownCount property immediately SetDropDownCount(EditorsPanel); end; procedure TIDEOptionsDialog.OkButtonClick(Sender: TObject); begin if Apply then ModalResult := mrOk; end; procedure TIDEOptionsDialog.CancelButtonClick(Sender: TObject); begin // cancel WriteAll(true); // restore old values // ToDo: Set build target only for project options. MainBuildBoss.SetBuildTargetProject1; // close ModalResult := mrCancel; end; procedure TIDEOptionsDialog.SetTitle(ATitle: string); begin FTitle := ATitle; UpdateDialogCaption; end; function TIDEOptionsDialog.FindGroupClass(Node: TTreeNode): TAbstractIDEOptionsClass; // Find the group category class where this node belongs to. begin while Assigned(Node) do begin if Assigned(Node.Parent) then Node := Node.Parent else Break; end; // GroupRec is stored in the first child editor if Assigned(Node) then Result := TAbstractIDEOptionsEditor(Node.GetFirstChild.Data).GroupRec^.GroupClass else Result := nil; end; procedure TIDEOptionsDialog.TraverseSettings(AOptions: TAbstractIDEOptions; anAction: TIDEOptsDlgAction); var ClassTypeForCompare: TClass; procedure Traverse(Node: TTreeNode); begin if Node = nil then exit; if Node.Data <> nil then with TAbstractIDEOptionsEditor(Node.Data) do if ((ClassTypeForCompare = nil) and (SupportedOptionsClass = nil)) or ((SupportedOptionsClass <> nil) and ClassTypeForCompare.InheritsFrom(SupportedOptionsClass)) then begin case anAction of iodaRead: ReadSettings(AOptions); iodaWrite: WriteSettings(AOptions); iodaRestore: RestoreSettings(AOptions); end; end; Traverse(Node.GetFirstChild); Traverse(Node.GetNextSibling); end; begin CreateEditors; if AOptions <> nil then ClassTypeForCompare := AOptions.ClassType else ClassTypeForCompare := nil; Traverse(CategoryTree.Items.GetFirstNode); end; procedure TIDEOptionsDialog.ReadAll; type TStage = (sBefore, sRead, sAfter); var i: integer; Rec: PIDEOptionsGroupRec; Instance: TAbstractIDEOptions; InstanceList: TFPList; stag: TStage; begin for stag:=low(TStage) to High(TStage) do begin if stag=sRead then CreateEditors; // Create before the inner loop, as this calls IDEEditorGroups.Resort; InstanceList:=TFPList.Create; for i := 0 to IDEEditorGroups.Count - 1 do begin Rec := IDEEditorGroups[i]; if not PassesFilter(Rec) then Continue; if Assigned(Rec^.Items) and Assigned(Rec^.GroupClass) then begin Instance := Rec^.GroupClass.GetInstance; if (InstanceList.IndexOf(Instance)<0) and Assigned(Instance) then begin InstanceList.Add(Instance); case stag of sBefore: Instance.DoBeforeRead; sRead: TraverseSettings(Instance,iodaRead); sAfter: Instance.DoAfterRead; end; end; end; end; if stag=sRead then TraverseSettings(nil,iodaRead); // load settings that does not belong to any group InstanceList.Free; end; end; procedure TIDEOptionsDialog.WriteAll(Restore: boolean); type TStage = (sBefore, sWrite, sAfter); var i: integer; Rec: PIDEOptionsGroupRec; Instance: TAbstractIDEOptions; stag: TStage; begin for stag:=low(TStage) to High(TStage) do begin if stag=sWrite then CreateEditors; // Create before the inner loop, as this calls IDEEditorGroups.Resort; for i := 0 to IDEEditorGroups.Count - 1 do begin Rec := IDEEditorGroups[i]; if not PassesFilter(Rec) then Continue; if Assigned(Rec^.Items) and Assigned(Rec^.GroupClass) then begin Instance := Rec^.GroupClass.GetInstance; if Assigned(Instance) then begin case stag of sBefore: Instance.DoBeforeWrite(Restore); sWrite: if Restore then TraverseSettings(Instance,iodaRestore) else TraverseSettings(Instance,iodaWrite); sAfter: Instance.DoAfterWrite(Restore); end; end; end; end; // save settings that do not belong to any group if stag=sWrite then if Restore then TraverseSettings(nil,iodaRestore) else TraverseSettings(nil,iodaWrite); end; end; function TIDEOptionsDialog.CheckValues: boolean; function Traverse(Node: TTreeNode): Boolean; begin if Node <> nil then begin if Node.Data <> nil then Result := TAbstractIDEOptionsEditor(Node.Data).Check else Result := True; Result := Result and Traverse(Node.GetFirstChild) and Traverse(Node.GetNextSibling); end else Result := True; end; begin Result := Traverse(CategoryTree.Items.GetFirstNode); end; procedure TIDEOptionsDialog.LoadIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions); begin if Assigned(OnLoadIDEOptionsHook) then OnLoadIDEOptionsHook(Self, AOptions); TraverseSettings(AOptions,iodaRead); if AOptions is TProjectCompilerOptions then UpdateBuildModeButtons; end; procedure TIDEOptionsDialog.SaveIDEOptions(Sender: TObject; AOptions: TAbstractIDEOptions); begin TraverseSettings(AOptions,iodaWrite); if Assigned(OnSaveIDEOptionsHook) then OnSaveIDEOptionsHook(Self, AOptions); end; procedure TIDEOptionsDialog.CreateEditors; function SearchNode(Node: TTreeNode; Index: Integer): TTreeNode; begin Result := nil; if Node = nil then Exit; if (Node.Data <> nil) and (TAbstractIDEOptionsEditor(Node.Data).Tag = Index) then Result := Node; if Result <> nil then Exit; Result := SearchNode(Node.GetFirstChild, Index); if Result <> nil then Exit; Result := SearchNode(Node.GetNextSibling, Index); end; var Instance: TAbstractIDEOptionsEditor; GroupNode, ItemNode, ItemParent: TTreeNode; i, j: integer; Rec: PIDEOptionsGroupRec; ACaption: string; begin if FEditorsCreated then Exit; FEditorsCreated := True; IDEEditorGroups.Resort; FSelectNode := nil; for i := 0 to IDEEditorGroups.Count - 1 do begin Rec := IDEEditorGroups[i]; //DebugLn(['TIDEOptionsDialog.CreateEditors ',Rec^.GroupClass.ClassName]); if PassesFilter(Rec) and (Rec^.Items <> nil) then begin if Rec^.GroupClass<>nil then ACaption := Rec^.GroupClass.GetGroupCaption else ACaption := format('Group<%d>',[i]); GroupNode := CategoryTree.Items.AddChild(nil, ACaption); for j := 0 to Rec^.Items.Count - 1 do begin Instance := Rec^.Items[j]^.EditorClass.Create(Self); Instance.OnLoadIDEOptions := @LoadIDEOptions; Instance.OnSaveIDEOptions := @SaveIDEOptions; Instance.Setup(Self); Instance.Tag := Rec^.Items[j]^.Index; Instance.Visible := False; Instance.Parent := EditorsPanel; Instance.Rec := Rec^.Items[j]; ItemParent := GroupNode; if Rec^.Items[j]^.Parent <> NoParent then begin ItemParent := SearchNode(GroupNode.GetFirstChild, Rec^.Items[j]^.Parent); if ItemParent = nil then ItemParent := GroupNode; end; ItemNode := CategoryTree.Items.AddChild(ItemParent, Instance.GetTitle); ItemNode.Data := Instance; if ItemParent.Data <> nil then begin Instance := TAbstractIDEOptionsEditor(ItemParent.Data); ItemParent.Expanded := not Instance.Rec^.Collapsed; end; if IDEEditorGroups.LastSelected = Rec^.Items[j] then FSelectNode := ItemNode; end; if (GroupNode.GetFirstChild <> nil) and (GroupNode.GetFirstChild.Data <> nil) then TAbstractIDEOptionsEditor(GroupNode.GetFirstChild.Data).GroupRec := Rec; GroupNode.Expanded := not Rec^.Collapsed; end; end; if FSelectNode <> nil then FSelectNode.Selected := True; end; function TIDEOptionsDialog.SearchEditorNode(AEditor: TAbstractIDEOptionsEditorClass): TTreeNode; function Traverse(ANode: TTreeNode): TTreeNode; begin Result := nil; if ANode <> nil then begin if (ANode.Data <> nil) and (TObject(ANode.Data).ClassType = AEditor) then Result := ANode; if Result = nil then Result := Traverse(ANode.GetFirstChild); if Result = nil then Result := Traverse(ANode.GetNextSibling); end; end; begin Result := Traverse(CategoryTree.Items.GetFirstNode); end; function TIDEOptionsDialog.SearchEditorNode( const IDEOptionsEditorClassName: string): TTreeNode; function Traverse(ANode: TTreeNode): TTreeNode; begin Result := nil; if ANode <> nil then begin if (ANode.Data <> nil) and (CompareText(TObject(ANode.Data).ClassName,IDEOptionsEditorClassName)=0) then Result := ANode; if Result = nil then Result := Traverse(ANode.GetFirstChild); if Result = nil then Result := Traverse(ANode.GetNextSibling); end; end; begin Result := Traverse(CategoryTree.Items.GetFirstNode); end; function TIDEOptionsDialog.PassesFilter(ARec: PIDEOptionsGroupRec): Boolean; var i: Integer; begin if (ARec^.GroupClass = nil) then Exit(Length(OptionsFilter) = 0); for i := 0 to Length(OptionsFilter) - 1 do if ARec^.GroupClass.InheritsFrom(OptionsFilter[i]) then Exit(True); Result := False; end; procedure TIDEOptionsDialog.SetSettings(const AValue: TIDEOptionsEditorSettings); begin if FSettings <> AValue then begin FSettings := AValue; if ioesReadOnly in Settings then ButtonPanel.ShowButtons := ButtonPanel.ShowButtons - [pbOK, pbCancel] + [pbClose] else ButtonPanel.ShowButtons := ButtonPanel.ShowButtons + [pbOK, pbCancel] - [pbClose]; end; end; function TIDEOptionsDialog.AllBuildModes: boolean; begin Result:=BuildModeComboBox.Text = lisAllBuildModes; end; procedure TIDEOptionsDialog.UpdateBuildModeButtons; var ModeMatrix: TCompOptModeMatrixFrame; begin ModeMatrix:=TCompOptModeMatrixFrame(FindEditor(TCompOptModeMatrixFrame)); if Assigned(ModeMatrix) then ModeMatrix.UpdateModes; end; procedure TIDEOptionsDialog.UpdateDialogCaption; begin // Show current build mode in Caption for Project options dialog if FIsProjectOptionsDialog then Caption := Format('%s [%s]', [FTitle, BuildModeComboBox.Text]) else Caption := FTitle; end; procedure TIDEOptionsDialog.DoOpenEditor(EditorToOpen: TAbstractIDEOptionsEditorClass); var Node: TTreeNode; begin if EditorToOpen = nil then begin if FSelectNode <> nil then Node := FSelectNode else Node := CategoryTree.Items.GetFirstNode end else Node := SearchEditorNode(EditorToOpen); if Node <> nil then CategoryTree.Selected := Node; FSelectNode := nil; end; function TIDEOptionsDialog.ShowModal: Integer; begin DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TIDEOptionsDialog.ShowModal'){$ENDIF}; try CreateEditors; DoOpenEditor(FEditorToOpen); finally EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TIDEOptionsDialog.ShowModal'){$ENDIF}; end; Result := inherited ShowModal; end; function TIDEOptionsDialog.AddButton: TBitBtn; begin Result := TBitBtn.Create(Self); Result.Align := alCustom; Result.Default := false; Result.Constraints.MinWidth := 75; Result.AutoSize := true; Result.Parent := ButtonPanel; end; procedure TIDEOptionsDialog.AddButtonSeparator; var pnl: TPanel; begin pnl := TPanel.Create(Self); pnl.Align := alCustom; pnl.BevelOuter := bvNone; pnl.Width := 6; pnl.Parent := ButtonPanel; end; function TIDEOptionsDialog.AddControl(AControlClass: TControlClass): TControl; begin Result := AControlClass.Create(Self); Result.Parent := SettingsPanel; Result.BorderSpacing.Top := 6; Result.BorderSpacing.Bottom := 6; Result.Align := alBottom; end; procedure TIDEOptionsDialog.OpenEditor(AEditor: TAbstractIDEOptionsEditorClass); begin if IsVisible then DoOpenEditor(AEditor) else FEditorToOpen := AEditor; end; procedure TIDEOptionsDialog.OpenEditor(GroupIndex, AIndex: integer); begin if IsVisible then DoOpenEditor(FindEditorClass(GroupIndex,AIndex)) else FEditorToOpen := FindEditorClass(GroupIndex,AIndex); end; function TIDEOptionsDialog.FindEditor(AEditor: TAbstractIDEOptionsEditorClass): TAbstractIDEOptionsEditor; var Node: TTreeNode; begin Node := SearchEditorNode(AEditor); if Node <> nil then Result := TAbstractIDEOptionsEditor(Node.Data) else Result := nil; end; function TIDEOptionsDialog.FindEditor(const IDEOptionsEditorClassName: string ): TAbstractIDEOptionsEditor; var Node: TTreeNode; begin Node := SearchEditorNode(IDEOptionsEditorClassName); if Node <> nil then Result := TAbstractIDEOptionsEditor(Node.Data) else Result := nil; end; function TIDEOptionsDialog.FindEditor(GroupIndex, AIndex: integer): TAbstractIDEOptionsEditor; var EditorClass: TAbstractIDEOptionsEditorClass; begin EditorClass := FindEditorClass(GroupIndex, AIndex); if EditorClass <> nil then Result := FindEditor(EditorClass) else Result := nil; end; function TIDEOptionsDialog.FindEditorClass(GroupIndex, AIndex: integer): TAbstractIDEOptionsEditorClass; var Grp: PIDEOptionsGroupRec; i: Integer; begin Result:=nil; Grp:=IDEEditorGroups.GetByIndex(GroupIndex); if Assigned(Grp) and Assigned(Grp^.Items) then for i:=0 to Grp^.Items.Count-1 do if Grp^.Items[i]^.Index=AIndex then exit(Grp^.Items[i]^.EditorClass); end; function TIDEOptionsDialog.ResetFilter: Boolean; begin Result := FilterEdit.Filter <> ''; FilterEdit.ResetFilter; end; procedure TIDEOptionsDialog.UpdateBuildModeGUI; begin UpdateBuildModeCombo(BuildModeComboBox); UpdateBuildModeButtons; end; end.