mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
ADD: Add a new item in the main menu called "Favorites" for the Favorite Tabs (validated with AK). UPD: Favorite Tabs stored in a separate single config file called "favoritetabs.xml" in the %DC_CONFIG_PATH% directory and not trace in the "doublecmd.xml" (except maybe the ID of the last active Favorite Tabs). UPD: "favoritetabs.xml" now holds both the tree structure of Favorite Tabs menu AND the actual bare data for what the tabs are. ADD: New configuration form called "Folder tabs extra" for little more specific behaviors when we save/load Favorite Tabs. ADD: New settings to enable or not options related with Favorite Tabs when they are loaded. So there is like a "simple" mode and a kind of extra" mode. FIX: Favorite Tabs now saves directory history (before was not working). In the "simple" mode, it will be according to the general "Save dir history" setting. In the extra mode it could be set independently from a setup to another. ADD: In the Favorite Tabs configuration, we may import legacy existing .tab files to have their contents in the Favorite Tabs. (We may export back to .tab file also). UPD: Refactor the "LoadThisToThis" function that was in "umaincommands.pas" to now be "LoadTheseTabsWithThisConfig" in "fmain". It can now be called directly by functions in "ufavoritetabs.pas" since they load directly tabs from there. ADD: Add six 16x16 icons for commands related with favorite tabs. UPD: Change the 32x32 icons for the cm_configfoldertabs internal command as well of the 16x16 image in the options page related with that so it looks like the other blue tab related command (validated with AK). ADD: Add the internal parametrable command "cm_copyalltabstoopposite" to copy tabs from a side to the opposite one. Parameter value of "side=" indicates which tab to use as source and it could be "left", "right", "active", "inactive" or even "both". RMV: Remove two unused image that were related with Favorite Tabs (newadditionfavtabs.png & submenufavtabs.png). RMV: Remove the "Group" related menus, actions and variables. (validated with meteu and AK).
412 lines
12 KiB
ObjectPascal
412 lines
12 KiB
ObjectPascal
{
|
|
Double Commander
|
|
-------------------------------------------------------------------------
|
|
Implementing of Options dialog
|
|
|
|
Copyright (C) 2006-2016 Koblov Alexander (Alexx2000@mail.ru)
|
|
|
|
contributors:
|
|
|
|
Radek Cervinka <radek.cervinka@centrum.cz>
|
|
|
|
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, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
}
|
|
|
|
unit fOptions;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, Controls, Forms, Dialogs, ExtCtrls, ComCtrls, Buttons,
|
|
StdCtrls, fgl, uGlobs, fOptionsFrame, uDCUtils;
|
|
|
|
type
|
|
|
|
{ TOptionsEditorView }
|
|
|
|
TOptionsEditorView = class
|
|
EditorClass: TOptionsEditorClass;
|
|
Instance: TOptionsEditor;
|
|
TreeNode: TTreeNode;
|
|
LegacyOrderIndex: integer;
|
|
end;
|
|
|
|
TOptionsEditorViews = specialize TFPGObjectList<TOptionsEditorView>;
|
|
|
|
{ TfrmOptions }
|
|
|
|
TfrmOptions = class(TForm, IOptionsDialog)
|
|
lblEmptyEditor: TLabel;
|
|
OptionsEditorsImageList: TImageList;
|
|
Panel1: TPanel;
|
|
Panel3: TPanel;
|
|
pnlCaption: TPanel;
|
|
btnOK: TBitBtn;
|
|
btnApply: TBitBtn;
|
|
btnCancel: TBitBtn;
|
|
sboxOptionsEditor: TScrollBox;
|
|
tvTreeView: TTreeView;
|
|
splOptionsSplitter: TSplitter;
|
|
procedure btnCancelClick(Sender: TObject);
|
|
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure btnOKClick(Sender: TObject);
|
|
procedure btnApplyClick(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure tvTreeViewChange(Sender: TObject; Node: TTreeNode);
|
|
private
|
|
FOptionsEditorList: TOptionsEditorViews;
|
|
FOldEditor: TOptionsEditorView;
|
|
function CreateEditor(EditorClass: TOptionsEditorClass): TOptionsEditor;
|
|
procedure CreateOptionsEditorList;
|
|
function GetEditor(EditorClass: TOptionsEditorClass): TOptionsEditor;
|
|
procedure LoadSettings;
|
|
procedure SelectEditor(EditorClassName: String);
|
|
function CompareTwoNodeOfConfigurationOptionTree(Node1, Node2: TTreeNode): integer;
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
constructor Create(TheOwner: TComponent; EditorClass: TOptionsEditorClass); overload;
|
|
constructor Create(TheOwner: TComponent; EditorClassName: String); overload;
|
|
procedure LoadConfig;
|
|
procedure SaveConfig;
|
|
end;
|
|
|
|
function ShowOptions(EditorClass: TOptionsEditorClass = nil): IOptionsDialog;
|
|
function ShowOptions(EditorClassName: String): IOptionsDialog;
|
|
procedure SortConfigurationOptionsOnLeftTree; //If the var "frmOptions" would be in the interface section, we could have called directly "frmOptions.tvTreeView.CustomSort(@frmOptions.CompareTwoNodeOfConfigurationOptionTree);"
|
|
//But it's not the case... Let's create this routine and respect the wish of original authors to have it there. Maybe there is a raison why so let's play safe.
|
|
function GetOptionsForm: TfrmOptions;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
uses
|
|
LCLProc, LCLVersion, uLng, fMain;
|
|
|
|
var
|
|
LastOpenedEditor: TOptionsEditorClass = nil;
|
|
frmOptions: TfrmOptions = nil;
|
|
|
|
{ GetOptionsForm }
|
|
// To get a point on the frmOptions.
|
|
// Could have been simple to place "frmOptions" in the "interface" section but not sure why original author hide it under. Let's play safe.
|
|
function GetOptionsForm: TfrmOptions;
|
|
begin
|
|
result := frmOptions;
|
|
end;
|
|
|
|
function ShowOptions(EditorClass: TOptionsEditorClass): IOptionsDialog;
|
|
begin
|
|
Result := ShowOptions(EditorClass.ClassName);
|
|
end;
|
|
|
|
function ShowOptions(EditorClassName: String): IOptionsDialog;
|
|
begin
|
|
if Assigned(frmOptions) then
|
|
begin
|
|
if frmOptions.WindowState = wsMinimized then
|
|
frmOptions.WindowState:= wsNormal
|
|
else
|
|
frmOptions.BringToFront;
|
|
|
|
frmOptions.SelectEditor(EditorClassName);
|
|
end
|
|
else
|
|
begin
|
|
if EditorClassName = '' then
|
|
frmOptions := TfrmOptions.Create(Application)
|
|
else
|
|
frmOptions := TfrmOptions.Create(Application, EditorClassName);
|
|
|
|
frmOptions.Show;
|
|
end;
|
|
Result := frmOptions;
|
|
end;
|
|
|
|
procedure SortConfigurationOptionsOnLeftTree;
|
|
begin
|
|
if frmOptions<>nil then frmOptions.tvTreeView.CustomSort(@frmOptions.CompareTwoNodeOfConfigurationOptionTree);
|
|
end;
|
|
|
|
procedure TfrmOptions.FormCreate(Sender: TObject);
|
|
begin
|
|
// Initialize property storage
|
|
InitPropStorage(Self);
|
|
end;
|
|
|
|
procedure TfrmOptions.FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
begin
|
|
CloseAction:= caFree;
|
|
frmOptions:= nil;
|
|
end;
|
|
|
|
procedure TfrmOptions.FormCloseQuery(Sender: TObject; var CanClose: boolean);
|
|
var
|
|
I:integer;
|
|
NeedsUpdateWindowView:boolean=FALSE;
|
|
begin
|
|
CanClose:=TRUE;
|
|
I:=0;
|
|
while (I<FOptionsEditorList.Count) AND (CanClose) do
|
|
begin
|
|
if Assigned(FOptionsEditorList[I].Instance) then CanClose:=FOptionsEditorList[I].Instance.CanWeClose(NeedsUpdateWindowView);
|
|
inc(I);
|
|
end;
|
|
|
|
if NeedsUpdateWindowView then frmMain.UpdateWindowView;
|
|
end;
|
|
|
|
procedure TfrmOptions.btnCancelClick(Sender: TObject);
|
|
begin
|
|
// close window
|
|
Close;
|
|
end;
|
|
|
|
procedure TfrmOptions.btnOKClick(Sender: TObject);
|
|
begin
|
|
// save all configuration
|
|
SaveConfig;
|
|
// write to config file
|
|
SaveGlobs;
|
|
// close window
|
|
Close;
|
|
end;
|
|
|
|
procedure TfrmOptions.btnApplyClick(Sender: TObject);
|
|
begin
|
|
// save all configuration
|
|
SaveConfig;
|
|
// write to config file
|
|
SaveGlobs;
|
|
end;
|
|
|
|
procedure TfrmOptions.FormDestroy(Sender: TObject);
|
|
begin
|
|
FreeThenNil(FOptionsEditorList);
|
|
end;
|
|
|
|
function TfrmOptions.CompareTwoNodeOfConfigurationOptionTree(Node1, Node2: TTreeNode): integer;
|
|
begin
|
|
case gSortOrderOfConfigurationOptionsTree of
|
|
scoClassicLegacy:
|
|
begin
|
|
if TOptionsEditorView(Node1.Data).LegacyOrderIndex < TOptionsEditorView(Node2.Data).LegacyOrderIndex then result:=-1 else result:=1;
|
|
end;
|
|
|
|
scoAlphabeticalButLanguage:
|
|
begin
|
|
if TOptionsEditorView(Node1.Data).EditorClass.ClassName='TfrmOptionsLanguage' then
|
|
result:=-1
|
|
else
|
|
if TOptionsEditorView(Node2.Data).EditorClass.ClassName='TfrmOptionsLanguage' then
|
|
result:=1
|
|
else
|
|
result:=CompareStrings(Node1.Text,Node2.Text, gSortNatural, gSortCaseSensitivity)
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure TfrmOptions.CreateOptionsEditorList;
|
|
procedure AddEditors(EditorClassList: TOptionsEditorClassList; RootNode: TTreeNode);
|
|
var
|
|
I: LongInt;
|
|
aOptionsEditorClass: TOptionsEditorClass;
|
|
aOptionsEditorView: TOptionsEditorView;
|
|
TreeNode: TTreeNode;
|
|
IconIndex: Integer;
|
|
begin
|
|
for I:= 0 to EditorClassList.Count - 1 do
|
|
begin
|
|
aOptionsEditorClass := EditorClassList[I].EditorClass;
|
|
|
|
aOptionsEditorView := TOptionsEditorView.Create;
|
|
aOptionsEditorView.EditorClass := aOptionsEditorClass;
|
|
aOptionsEditorView.Instance := nil;
|
|
aOptionsEditorView.LegacyOrderIndex:=I;
|
|
FOptionsEditorList.Add(aOptionsEditorView);
|
|
|
|
TreeNode := tvTreeView.Items.AddChild(RootNode,
|
|
{$IF lcl_fullversion >= 093100}
|
|
aOptionsEditorClass.GetTitle
|
|
{$ELSE}
|
|
StringReplace(aOptionsEditorClass.GetTitle, '&', '&&', [rfReplaceAll])
|
|
{$ENDIF}
|
|
);
|
|
if Assigned(TreeNode) then
|
|
begin
|
|
IconIndex := aOptionsEditorClass.GetIconIndex;
|
|
TreeNode.ImageIndex := IconIndex;
|
|
TreeNode.SelectedIndex := IconIndex;
|
|
TreeNode.StateIndex := IconIndex;
|
|
TreeNode.Data := aOptionsEditorView;
|
|
end;
|
|
|
|
aOptionsEditorView.TreeNode := TreeNode;
|
|
|
|
if EditorClassList[I].HasChildren then
|
|
AddEditors(EditorClassList[I].Children, TreeNode);
|
|
end;
|
|
|
|
//2014-08-12:Let's sort by alphabetical order this list.
|
|
tvTreeView.CustomSort(@CompareTwoNodeOfConfigurationOptionTree);
|
|
end;
|
|
begin
|
|
FOptionsEditorList:= TOptionsEditorViews.Create;
|
|
AddEditors(OptionsEditorClassList, nil);
|
|
end;
|
|
|
|
function TfrmOptions.GetEditor(EditorClass: TOptionsEditorClass): TOptionsEditor;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FOptionsEditorList.Count - 1 do
|
|
begin
|
|
if FOptionsEditorList[I].EditorClass = EditorClass then
|
|
begin
|
|
if not Assigned(FOptionsEditorList[I].Instance) then
|
|
FOptionsEditorList[I].Instance := CreateEditor(FOptionsEditorList[I].EditorClass);
|
|
Result := FOptionsEditorList[I].Instance;
|
|
Exit;
|
|
end;
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TfrmOptions.LoadSettings;
|
|
begin
|
|
LoadConfig;
|
|
end;
|
|
|
|
procedure TfrmOptions.SelectEditor(EditorClassName: String);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to FOptionsEditorList.Count - 1 do
|
|
begin
|
|
if (FOptionsEditorList[I].EditorClass.ClassName = EditorClassName) then
|
|
if Assigned(FOptionsEditorList[I].TreeNode) then
|
|
begin
|
|
FOptionsEditorList[I].TreeNode.Selected := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
constructor TfrmOptions.Create(TheOwner: TComponent);
|
|
begin
|
|
if not Assigned(LastOpenedEditor) and (OptionsEditorClassList.Count > 0) then
|
|
LastOpenedEditor := OptionsEditorClassList[0].EditorClass; // Select first editor.
|
|
Create(TheOwner, LastOpenedEditor);
|
|
end;
|
|
|
|
constructor TfrmOptions.Create(TheOwner: TComponent; EditorClass: TOptionsEditorClass);
|
|
begin
|
|
if Assigned(EditorClass) then
|
|
Create(TheOwner, EditorClass.ClassName)
|
|
else
|
|
Create(TheOwner, '');
|
|
end;
|
|
|
|
constructor TfrmOptions.Create(TheOwner: TComponent; EditorClassName: String);
|
|
begin
|
|
if (EditorClassName = '') and Assigned(LastOpenedEditor) then
|
|
EditorClassName := LastOpenedEditor.ClassName;
|
|
FOldEditor := nil;
|
|
inherited Create(TheOwner);
|
|
CreateOptionsEditorList;
|
|
SelectEditor(EditorClassName);
|
|
end;
|
|
|
|
procedure TfrmOptions.tvTreeViewChange(Sender: TObject; Node: TTreeNode);
|
|
var
|
|
SelectedEditorView: TOptionsEditorView;
|
|
begin
|
|
SelectedEditorView := TOptionsEditorView(Node.Data);
|
|
|
|
if Assigned(SelectedEditorView) and (FOldEditor <> SelectedEditorView) then
|
|
begin
|
|
if Assigned(FOldEditor) and Assigned(FOldEditor.Instance) then
|
|
FOldEditor.Instance.Visible := False;
|
|
|
|
if not Assigned(SelectedEditorView.Instance) then
|
|
SelectedEditorView.Instance := CreateEditor(SelectedEditorView.EditorClass);
|
|
|
|
if Assigned(SelectedEditorView.Instance) then
|
|
SelectedEditorView.Instance.Visible := True;
|
|
|
|
lblEmptyEditor.Visible := not Assigned(SelectedEditorView.Instance);
|
|
|
|
FOldEditor := SelectedEditorView;
|
|
LastOpenedEditor := SelectedEditorView.EditorClass;
|
|
|
|
pnlCaption.Caption := SelectedEditorView.EditorClass.GetTitle;
|
|
end;
|
|
end;
|
|
|
|
function TfrmOptions.CreateEditor(EditorClass: TOptionsEditorClass): TOptionsEditor;
|
|
begin
|
|
if Assigned(EditorClass) and not EditorClass.IsEmpty then
|
|
begin
|
|
Result := EditorClass.Create(Self);
|
|
Result.Align := alClient;
|
|
Result.Visible := False;
|
|
Result.Init(sboxOptionsEditor, Self, [oeifLoad]);
|
|
end
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TfrmOptions.LoadConfig;
|
|
var
|
|
I: LongInt;
|
|
begin
|
|
{ Load options to frames }
|
|
for I:= 0 to FOptionsEditorList.Count - 1 do
|
|
begin
|
|
if Assigned(FOptionsEditorList[I].Instance) then
|
|
FOptionsEditorList[I].Instance.LoadSettings;
|
|
end;
|
|
end;
|
|
|
|
procedure TfrmOptions.SaveConfig;
|
|
var
|
|
I: LongInt;
|
|
NeedsRestart: Boolean = False;
|
|
begin
|
|
{ Save options from frames }
|
|
for I:= 0 to FOptionsEditorList.Count - 1 do
|
|
begin
|
|
if Assigned(FOptionsEditorList[I].Instance) then
|
|
try
|
|
if oesfNeedsRestart in FOptionsEditorList[I].Instance.SaveSettings then
|
|
NeedsRestart := True;
|
|
except
|
|
on E: Exception do
|
|
MessageDlg(FOptionsEditorList[I].Instance.GetTitle, E.Message, mtError, [mbOK], 0);
|
|
end;
|
|
end;
|
|
|
|
if NeedsRestart then
|
|
MessageDlg(rsMsgRestartForApplyChanges, mtInformation, [mbOK], 0);
|
|
|
|
frmMain.UpdateWindowView;
|
|
end;
|
|
|
|
end.
|