{ Double Commander ------------------------------------------------------------------------- Options frame page Copyright (C) 2006-2020 Alexander Koblov (alexx2000@mail.ru) This program 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 program 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. You should have received a copy of the GNU General Public License along with this program. If not, see . } unit fOptionsFrame; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, fgl; type TOptionsEditorInitFlag = (oeifLoad); TOptionsEditorInitFlags = set of TOptionsEditorInitFlag; TOptionsEditorSaveFlag = (oesfNeedsRestart); TOptionsEditorSaveFlags = set of TOptionsEditorSaveFlag; TOptionsEditor = class; TOptionsEditorClass = class of TOptionsEditor; TOptionsEditorClassList = class; { IOptionsDialog } {$interfaces corba} IOptionsDialog = interface ['{E62AAF5E-74ED-49AB-93F2-DBE210BF6723}'] procedure LoadSettings; function GetEditor(EditorClass: TOptionsEditorClass): TOptionsEditor; end; {$interfaces default} { TOptionsEditor } // Regarding warning to user when attempting to exit configuration window or "option editor" without having saved a modified setting: // 1o) Immediately after having load the options in "LoadSettings", we will compute a signature, // which is a CRC32 of the related settings and memorize it. // 2o) When will attempt to close options, we'll recalculate again this signature, if it is different, // we know user has change something and will prompt user to validate if he wants to save, discard or cancel quit. // 3o) For many option editors, signature may be computed simply by validating actual controls of the window like // checkboxes state, edit box, etc. // 4o) For others, we need to run specific computation like signature of list like hot directories list, favorites tabs list, etc. // 5o) For some computing the signature with controls should not be done. // 6o) Here is a list of function and procedure around that: // 7o) "IsSignatureComputedFromAllWindowComponents": Function that may be overloaded by specific option editor to indicate // if we may compute signature of controls of the editor or not. // By default, it is the case. // 8o) "ExtraOptionsSignature": Function that may overloaded by specifica option editor when signature must include extra element not present in controls of the editor like a list of structures, etc. // By default, nothing more is required. // 9o) "ComputeCompleteOptionsSignature": Will first compute signature based on controls >IF< "IsSignatureComputedFromAllWindowComponents" is not invalidated by specific option editor // Then will make progress that signature >IF< "ExtraOptionsSignature" has been overload by specific option editor. TOptionsEditor = class(TFrame) private FOptionsDialog: IOptionsDialog; FLastLoadedOptionSignature: dword; protected procedure Init; virtual; procedure Done; virtual; procedure Load; virtual; function Save: TOptionsEditorSaveFlags; virtual; property OptionsDialog: IOptionsDialog read FOptionsDialog; public property LastLoadedOptionSignature:dword read FLastLoadedOptionSignature write FLastLoadedOptionSignature; // Let it public so Options Forms will be able to know what was initial signature. destructor Destroy; override; class function GetIconIndex: Integer; virtual; abstract; class function GetTitle: String; virtual; abstract; class function IsEmpty: Boolean; virtual; function IsSignatureComputedFromAllWindowComponents: Boolean; virtual; function ComputeCompleteOptionsSignature: dword; function ExtraOptionsSignature(CurrentSignature:dword):dword; virtual; function CanWeClose(var SaveFlags:TOptionsEditorSaveFlags; bForceClose:boolean=false):boolean; virtual; procedure LoadSettings; function SaveSettings: TOptionsEditorSaveFlags; procedure Init(AParent: TWinControl; AOptionsDialog: IOptionsDialog; Flags: TOptionsEditorInitFlags); end; { TOptionsEditorRec } TOptionsEditorRec = class private FChildren: TOptionsEditorClassList; FEditorClass: TOptionsEditorClass; function GetChildren: TOptionsEditorClassList; public constructor Create; destructor Destroy; override; function Add(Editor: TOptionsEditorClass): TOptionsEditorRec; function HasChildren: Boolean; property Children: TOptionsEditorClassList read GetChildren; property EditorClass: TOptionsEditorClass read FEditorClass write FEditorClass; end; { TBaseOptionsEditorClassList } TBaseOptionsEditorClassList = specialize TFPGObjectList; { TOptionsEditorClassList } TOptionsEditorClassList = class(TBaseOptionsEditorClassList) public function Add(Editor: TOptionsEditorClass): TOptionsEditorRec; overload; end; var OptionsEditorClassList: TOptionsEditorClassList = nil; implementation uses uLng, uComponentsSignature, uShowMsg, fOptions, fOptionsArchivers, fOptionsAutoRefresh, fOptionsBehavior, fOptionsBriefView, fOptionsColumnsView, fOptionsConfiguration, fOptionsCustomColumns, fOptionsDragDrop, fOptionsDrivesListButton, fOptionsTreeViewMenu, fOptionsTreeViewMenuColor, fOptionsFileOperations, fOptionsFileSearch, fOptionsMultiRename, fOptionsFilePanelsColors, fOptionsFileTypesColors, fOptionsFilesViews, fOptionsFilesViewsComplement, fOptionsFonts, fOptionsGroups, fOptionsHotkeys, {$IFDEF DARWIN} fOptionsiCloud, {$ENDIF} fOptionsIcons, fOptionsIgnoreList, fOptionsKeyboard, fOptionsLanguage, fOptionsLayout, fOptionsLog, fOptionsMisc, fOptionsMouse, fOptionsPluginsGroup, fOptionsPluginsDSX, fOptionsPluginsWCX, fOptionsPluginsWDX, fOptionsPluginsWFX, fOptionsPluginsWLX, fOptionsQuickSearchFilter, fOptionsTabs, fOptionsFavoriteTabs, fOptionsTabsExtra, fOptionsTerminal, fOptionsToolbar, fOptionsToolbarExtra, fOptionsToolbarMiddle, fOptionsTools, fOptionsToolsEditor, fOptionsToolsDiffer, fOptionsEditorColors, fOptionsToolTips, fOptionsFileAssoc, fOptionsFileAssocExtra, fOptionsDirectoryHotlist, fOptionsDirectoryHotlistExtra, fOptionsColors ; { TOptionsEditorRec } function TOptionsEditorRec.GetChildren: TOptionsEditorClassList; begin if not Assigned(FChildren) then FChildren := TOptionsEditorClassList.Create; Result := FChildren; end; constructor TOptionsEditorRec.Create; begin FChildren := nil; end; destructor TOptionsEditorRec.Destroy; begin inherited Destroy; FreeAndNil(FChildren); end; function TOptionsEditorRec.Add(Editor: TOptionsEditorClass): TOptionsEditorRec; begin Result := Children.Add(Editor); end; function TOptionsEditorRec.HasChildren: Boolean; begin Result := Assigned(FChildren) and (FChildren.Count > 0); end; { TOptionsEditorClassList } function TOptionsEditorClassList.Add(Editor: TOptionsEditorClass): TOptionsEditorRec; begin Result := TOptionsEditorRec.Create; Add(Result); Result.EditorClass:= Editor; end; { TOptionsEditor } procedure TOptionsEditor.Init; begin // Empty. end; { TOptionsEditor.ExtraOptionsSignature } function TOptionsEditor.ExtraOptionsSignature(CurrentSignature:dword):dword; begin result := CurrentSignature; end; { TOptionsEditor.ComputeCompleteOptionsSignature } function TOptionsEditor.ComputeCompleteOptionsSignature:dword; begin result := $000000; if IsSignatureComputedFromAllWindowComponents then result := ComputeSignatureBasedOnComponent(Self, result); result := ExtraOptionsSignature(result); end; { TOptionsEditor.CanWeClose } function TOptionsEditor.CanWeClose(var SaveFlags:TOptionsEditorSaveFlags; bForceClose:boolean=false):boolean; var Answer: TMyMsgResult; begin SaveFlags:=[]; if bForceClose then result:=True else result := (FLastLoadedOptionSignature = ComputeCompleteOptionsSignature); if (not result) OR bForceClose then begin if bForceClose then begin Answer:=mmrYes; end else begin ShowOptions(Self.ClassName); Answer := MsgBox(Format(rsOptionsEditorOptionsChanged, [GetTitle]), [msmbYes, msmbNo, msmbCancel], msmbCancel, msmbCancel); end; case Answer of mmrYes: begin SaveFlags := SaveSettings; result := True; end; mmrNo: result := True; else result := False; end; end; end; procedure TOptionsEditor.Done; begin // Empty. end; destructor TOptionsEditor.Destroy; begin Done; inherited Destroy; end; class function TOptionsEditor.IsEmpty: Boolean; begin Result := False; end; { TOptionsEditor.IsSignatureComputedFromAllWindowComponents } function TOptionsEditor.IsSignatureComputedFromAllWindowComponents: Boolean; begin Result := True; end; procedure TOptionsEditor.LoadSettings; begin DisableAutoSizing; try Load; FLastLoadedOptionSignature := ComputeCompleteOptionsSignature; finally EnableAutoSizing; end; end; function TOptionsEditor.SaveSettings: TOptionsEditorSaveFlags; begin Result := Save; FLastLoadedOptionSignature := ComputeCompleteOptionsSignature; end; procedure TOptionsEditor.Load; begin // Empty. end; function TOptionsEditor.Save: TOptionsEditorSaveFlags; begin Result := []; end; procedure TOptionsEditor.Init(AParent: TWinControl; AOptionsDialog: IOptionsDialog; Flags: TOptionsEditorInitFlags); begin DisableAutoSizing; try Parent := AParent; FOptionsDialog := AOptionsDialog; Init; if oeifLoad in Flags then LoadSettings; finally EnableAutoSizing; end; end; procedure MakeEditorsClassList; var Main: TOptionsEditorClassList absolute OptionsEditorClassList; Colors, ColumnsView, FilesViews, Keyboard, Layout, Mouse, Tools, Editor, FileAssoc, ToolbarConfig, FileOperation, FolderTabs, Plugins, DirectoryHotlistConfig: TOptionsEditorRec; begin Main.Add(TfrmOptionsLanguage); Main.Add(TfrmOptionsBehavior); Tools := Main.Add(TOptionsToolsGroup); Tools.Add(TfrmOptionsViewer); Editor:= Tools.Add(TfrmOptionsEditor); Editor.Add(TfrmOptionsEditorColors); Tools.Add(TfrmOptionsDiffer); Tools.Add(TfrmOptionsTerminal); Main.Add(TfrmOptionsFonts); Colors := Main.Add(TfrmOptionsColors); Colors.Add(TfrmOptionsFilePanelsColors); Colors.Add(TfrmOptionsFileTypesColors); Keyboard := Main.Add(TfrmOptionsKeyboard); Keyboard.Add(TfrmOptionsHotkeys); Mouse := Main.Add(TfrmOptionsMouse); Mouse.Add(TfrmOptionsDragDrop); FilesViews := Main.Add(TfrmOptionsFilesViews); FilesViews.Add(TfrmOptionsFilesViewsComplement); FilesViews.Add(TfrmOptionsBriefView); ColumnsView := FilesViews.Add(TfrmOptionsColumnsView); ColumnsView.Add(TfrmOptionsCustomColumns); Plugins := Main.Add(TfrmOptionsPluginsGroup); Plugins.Add(TfrmOptionsPluginsDSX); Plugins.Add(TfrmOptionsPluginsWCX); Plugins.Add(TfrmOptionsPluginsWDX); Plugins.Add(TfrmOptionsPluginsWFX); Plugins.Add(TfrmOptionsPluginsWLX); Layout := Main.Add(TfrmOptionsLayout); Layout.Add(TfrmOptionsDrivesListButton); Layout.Add(TfrmOptionsTreeViewMenu); Layout.Add(TfrmOptionsTreeViewMenuColor); ToolbarConfig := Main.Add(TfrmOptionsToolbar); ToolbarConfig.Add(TfrmOptionsToolbarMiddle); ToolbarConfig.Add(TfrmOptionsToolbarExtra); FileOperation := Main.Add(TfrmOptionsFileOperations); FileOperation.Add(TfrmOptionsFileSearch); FileOperation.Add(TfrmOptionsMultiRename); FolderTabs := Main.Add(TfrmOptionsTabs); FolderTabs.Add(TfrmOptionsFavoriteTabs); FolderTabs.Add(TfrmOptionsTabsExtra); Main.Add(TfrmOptionsLog); Main.Add(TfrmOptionsConfiguration); Main.Add(TfrmOptionsQuickSearchFilter); Main.Add(TfrmOptionsMisc); Main.Add(TfrmOptionsAutoRefresh); {$IFDEF DARWIN} Main.Add(TfrmOptionsiCloud); {$ENDIF} Main.Add(TfrmOptionsIcons); Main.Add(TfrmOptionsIgnoreList); Main.Add(TfrmOptionsArchivers); Main.Add(TfrmOptionsToolTips); FileAssoc := Main.Add(TfrmOptionsFileAssoc); FileAssoc.Add(TfrmOptionsFileAssocExtra); DirectoryHotlistConfig := Main.Add(TfrmOptionsDirectoryHotlist); DirectoryHotlistConfig.Add(TfrmOptionsDirectoryHotlistExtra); end; initialization OptionsEditorClassList:= TOptionsEditorClassList.Create; MakeEditorsClassList; finalization if Assigned(OptionsEditorClassList) then FreeAndNil(OptionsEditorClassList); end.