lazarus/ide/ideoptionsdlg.pas

946 lines
29 KiB
ObjectPascal

{
***************************************************************************
* *
* 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 <http://www.gnu.org/copyleft/gpl.html>. 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.