mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
1259 lines
49 KiB
ObjectPascal
1259 lines
49 KiB
ObjectPascal
{
|
|
Double Commander
|
|
-------------------------------------------------------------------------
|
|
Load/Save/WorkingWith HotDir
|
|
|
|
Copyright (C) 2014-2019 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, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
}
|
|
|
|
unit uHotDir;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
//Lazarus, Free-Pascal, etc.
|
|
Classes, SysUtils, Menus, ExtCtrls, Controls, ComCtrls,
|
|
|
|
//DC
|
|
DCClassesUtf8, DCXmlConfig;
|
|
const
|
|
cSectionOfHotDir = 'DirectoryHotList';
|
|
|
|
ACTION_INVALID = 0;
|
|
ACTION_ADDTOHOTLIST = 1;
|
|
ACTION_ADDJUSTSOURCETOHOTLIST = 2;
|
|
ACTION_ADDBOTHTOHOTLIST = 3;
|
|
ACTION_CONFIGTOHOTLIST = 4;
|
|
ACTION_JUSTSHOWCONFIGHOTLIST = 5;
|
|
ACTION_ADDSELECTEDDIR = 6;
|
|
ACTION_DIRECTLYCONFIGENTRY = 7;
|
|
|
|
HOTLISTMAGICWORDS:array[1..7] of string =('add','addsrconly','addboth','config','show','addsel','directconfig');
|
|
|
|
TAGOFFSET_FORCHANGETOSPECIALDIR = $10000;
|
|
|
|
ICONINDEX_SUBMENU = 0;
|
|
ICONINDEX_DIRECTORYNOTPRESENTHERE = 1;
|
|
ICONINDEX_SUBMENUWITHMISSING = 2;
|
|
ICONINDEX_NEWADDEDDIRECTORY = 3;
|
|
ICONINDEXNAME:array[0..3] of string = ('submenu','dirmissing','submenuwithmissing','newaddition');
|
|
|
|
HOTLIST_SEPARATORSTRING:string='···························';
|
|
TERMINATORNOTPRESENT = ':-<#/?*+*?\#>-:';
|
|
|
|
STR_ACTIVEFRAME: string = 'panel=active';
|
|
STR_NOTACTIVEFRAME: string = 'panel=inactive';
|
|
STR_LEFTFRAME: string = 'panel=left';
|
|
STR_RIGHTFRAME: string = 'panel=right';
|
|
STR_NAME: string = 'column=name';
|
|
STR_EXTENSION: string = 'column=ext';
|
|
STR_SIZE: string = 'column=size';
|
|
STR_MODIFICATIONDATETIME: string = 'column=datetime';
|
|
STR_ASCENDING : string = 'order=ascending';
|
|
STR_DESCENDING : string = 'order=descending';
|
|
|
|
|
|
type
|
|
{ TKindOfHotDirEntry }
|
|
TKindOfHotDirEntry = (hd_NULL, hd_CHANGEPATH, hd_SEPARATOR, hd_STARTMENU, hd_ENDMENU, hd_COMMAND);
|
|
|
|
{ TKindHotDirMenuPopulation }
|
|
TKindHotDirMenuPopulation = (mpJUSTHOTDIRS, mpHOTDIRSWITHCONFIG, mpPATHHELPER);
|
|
|
|
{ TPositionWhereToAddHotDir }
|
|
TPositionWhereToAddHotDir = (ahdFirst, ahdLast, ahdSmart);
|
|
|
|
{ TExistingState }
|
|
TExistingState = (DirExistUnknown, DirExist, DirNotExist);
|
|
|
|
{ TProcedureWhenClickMenuItem}
|
|
TProcedureWhenClickOnMenuItem = procedure(Sender: TObject) of object;
|
|
|
|
{ THotDir }
|
|
THotDir = class
|
|
private
|
|
FDispatcher: TKindOfHotDirEntry;
|
|
FHotDirName: string;
|
|
FHotDirPath: string;
|
|
FHotDirPathSort: longint;
|
|
FHotDirTarget: string;
|
|
FHotDirTargetSort: longint;
|
|
FHotDirExistingState: TExistingState;
|
|
FGroupNumber : integer;
|
|
public
|
|
constructor Create;
|
|
procedure CopyToHotDir(var DestinationHotDir: THotDir);
|
|
property Dispatcher: TKindOfHotDirEntry read FDispatcher write FDispatcher;
|
|
property HotDirName: string read FHotDirName write FHotDirName;
|
|
property HotDirPath: string read FHotDirPath write FHotDirPath;
|
|
property HotDirPathSort: longint read FHotDirPathSort write FHotDirPathSort;
|
|
property HotDirTarget: string read FHotDirTarget write FHotDirTarget;
|
|
property HotDirTargetSort: longint read FHotDirTargetSort write FHotDirTargetSort;
|
|
property HotDirExisting: TExistingState read FHotDirExistingState write FHotDirExistingState;
|
|
property GroupNumber: integer read FGroupNumber write FGroupNumber;
|
|
end;
|
|
|
|
{ TDirectoryHotlist }
|
|
TDirectoryHotlist = class(TList)
|
|
private
|
|
function GetHotDir(Index: integer): THotDir;
|
|
public
|
|
constructor Create;
|
|
procedure Clear; override;
|
|
function Add(HotDir: THotDir): integer;
|
|
procedure DeleteHotDir(Index: integer);
|
|
procedure CopyDirectoryHotlistToDirectoryHotlist(var DestinationDirectoryHotlist: TDirectoryHotlist);
|
|
procedure LoadFromXml(AConfig: TXmlConfig; ANode: TXmlNode);
|
|
procedure SaveToXml(AConfig: TXmlConfig; ANode: TXmlNode; FlagEraseOriginalOnes: boolean);
|
|
procedure ImportDoubleCommander(DoubleCommanderFilename: String);
|
|
function ExportDoubleCommander(DoubleCommanderFilename: String; FlagEraseOriginalOnes: boolean): boolean;
|
|
procedure PopulateMenuWithHotDir(mncmpMenuComponentToPopulate: TComponent; ProcedureWhenHotDirItemClicked, ProcedureWhenHotDirAddOrConfigClicked: TProcedureWhenClickOnMenuItem; KindHotDirMenuPopulation: TKindHotDirMenuPopulation; TagOffset: longint);
|
|
function LoadTTreeView(ParamTreeView:TTreeView; DirectoryHotlistIndexToSelectIfAny:longint):TTreeNode;
|
|
procedure RefreshFromTTreeView(ParamTreeView:TTreeView);
|
|
function AddFromAnotherTTreeViewTheSelected(ParamWorkingTreeView, ParamTreeViewToImport:TTreeView; FlagAddThemAll: boolean): longint;
|
|
function ComputeSignature(Seed:dword=$00000000):dword;
|
|
property HotDir[Index: integer]: THotDir read GetHotDir;
|
|
{$IFDEF MSWINDOWS}
|
|
function ImportTotalCommander(TotalCommanderConfigFilename: String): integer;
|
|
function ExportTotalCommander(TotalCommanderConfigFilename: String; FlagEraseOriginalOnes: boolean): boolean;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{ TCheckDrivePresenceThread }
|
|
TCheckDrivePresenceThread = class(TThread)
|
|
private
|
|
FDriveToSearchFor: string;
|
|
FListOfNonExistingDrive: TStringList;
|
|
FThreadCountPoint: ^longint;
|
|
procedure ReportNotPresentInTheThread;
|
|
procedure ReportPresentInTheThread;
|
|
protected
|
|
procedure Execute; override;
|
|
public
|
|
constructor Create(sDrive: string; ParamListOfNonExistingDrive: TStringList; var ThreadCount: longint);
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
//Lazarus, Free-Pascal, etc.
|
|
crc, Graphics, Forms, lazutf8,
|
|
|
|
//DC
|
|
DCFileAttributes, uDebug, uDCUtils, fMain, uFile, uLng, DCOSUtils, DCStrUtils,
|
|
uGlobs, uSpecialDir
|
|
{$IFDEF MSWINDOWS}
|
|
,uTotalCommander
|
|
{$ENDIF}
|
|
;
|
|
|
|
function GetCaption(const ACaption: TCaption): TCaption;
|
|
begin
|
|
{$IFNDEF LCLWIN32}
|
|
if (Pos('&', StringReplace(ACaption, '&&', '', [rfReplaceAll])) = 0) then
|
|
Result:= '&' + ACaption
|
|
else
|
|
{$ENDIF}
|
|
Result:= ACaption;
|
|
end;
|
|
|
|
{ THotDir.Create }
|
|
constructor THotDir.Create;
|
|
begin
|
|
inherited Create;
|
|
FDispatcher := hd_NULL;
|
|
FHotDirName := '';
|
|
FHotDirPath := '';
|
|
FHotDirPathSort := 0;
|
|
FHotDirTarget := '';
|
|
FHotDirTargetSort := 0;
|
|
FHotDirExistingState := DirExistUnknown;
|
|
FGroupNumber := 0;
|
|
end;
|
|
|
|
{ THotDir.CopyToHotDir }
|
|
procedure THotDir.CopyToHotDir(var DestinationHotDir: THotDir);
|
|
begin
|
|
DestinationHotDir.Dispatcher := FDispatcher;
|
|
DestinationHotDir.HotDirName := FHotDirName;
|
|
DestinationHotDir.HotDirPath := FHotDirPath;
|
|
DestinationHotDir.HotDirPathSort := FHotDirPathSort;
|
|
DestinationHotDir.HotDirTarget := FHotDirTarget;
|
|
DestinationHotDir.HotDirTargetSort := FHotDirTargetSort;
|
|
DestinationHotDir.HotDirExisting := FHotDirExistingState;
|
|
DestinationHotDir.GroupNumber := FGroupNumber;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.Create }
|
|
constructor TDirectoryHotlist.Create;
|
|
begin
|
|
inherited Create;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.Clear }
|
|
procedure TDirectoryHotlist.Clear;
|
|
var
|
|
i: integer;
|
|
begin
|
|
for i := 0 to Count - 1 do HotDir[i].Free;
|
|
inherited Clear;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.Add }
|
|
function TDirectoryHotlist.Add(HotDir: THotDir): integer;
|
|
begin
|
|
Result := inherited Add(HotDir);
|
|
end;
|
|
|
|
{ TDirectoryHotlist.DeleteHotDir }
|
|
procedure TDirectoryHotlist.DeleteHotDir(Index: integer);
|
|
begin
|
|
HotDir[Index].Free;
|
|
Delete(Index);
|
|
end;
|
|
|
|
{ TDirectoryHotlist.CopyDirectoryHotlistToDirectoryHotlist }
|
|
procedure TDirectoryHotlist.CopyDirectoryHotlistToDirectoryHotlist(var DestinationDirectoryHotlist: TDirectoryHotlist);
|
|
var
|
|
LocalHotDir: THotDir;
|
|
Index: longint;
|
|
begin
|
|
//Let's delete possible previous list content
|
|
for Index := pred(DestinationDirectoryHotlist.Count) downto 0 do DestinationDirectoryHotlist.DeleteHotDir(Index);
|
|
DestinationDirectoryHotlist.Clear;
|
|
|
|
//Now let's create entries and add them one by one to the destination list
|
|
for Index := 0 to pred(Count) do
|
|
begin
|
|
LocalHotDir := THotDir.Create;
|
|
LocalHotDir.Dispatcher := HotDir[Index].Dispatcher;
|
|
LocalHotDir.HotDirName := HotDir[Index].HotDirName;
|
|
LocalHotDir.HotDirPath := HotDir[Index].HotDirPath;
|
|
LocalHotDir.HotDirPathSort := HotDir[Index].HotDirPathSort;
|
|
LocalHotDir.HotDirTarget := HotDir[Index].HotDirTarget;
|
|
LocalHotDir.HotDirTargetSort := HotDir[Index].HotDirTargetSort;
|
|
LocalHotDir.FHotDirExistingState := HotDir[Index].HotDirExisting;
|
|
LocalHotDir.FGroupNumber := HotDir[Index].GroupNumber;
|
|
DestinationDirectoryHotlist.Add(LocalHotDir);
|
|
end;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.LoadTTreeView }
|
|
//For each node, the "ImageIndex" field is recuperated to be an index of which
|
|
//item in the directory list it represent. Because of the fact that the
|
|
//"hd_ENDMENU's" don't have their direct element in the tree, the field
|
|
//"absoluteindex" cannot be used for that since as soon as there is a subment,
|
|
//we lost the linearity of the matching of absoluteindex vs index of hotdir in
|
|
//the list.
|
|
function TDirectoryHotlist.LoadTTreeView(ParamTreeView:TTreeView; DirectoryHotlistIndexToSelectIfAny:longint):TTreeNode;
|
|
var
|
|
Index: longint;
|
|
|
|
procedure RecursivAddElements(WorkingNode: TTreeNode);
|
|
var
|
|
FlagGetOut: boolean = False;
|
|
LocalNode: TTreeNode;
|
|
begin
|
|
while (FlagGetOut = False) and (Index < Count) do
|
|
begin
|
|
case HotDir[Index].Dispatcher of
|
|
hd_STARTMENU:
|
|
begin
|
|
LocalNode := ParamTreeView.Items.AddChildObject(WorkingNode, HotDir[Index].HotDirName,HotDir[Index]);
|
|
if HotDir[Index].FHotDirExistingState=DirNotExist then
|
|
begin
|
|
LocalNode.ImageIndex:=ICONINDEX_SUBMENUWITHMISSING;
|
|
LocalNode.SelectedIndex:=ICONINDEX_SUBMENUWITHMISSING;
|
|
LocalNode.StateIndex:=ICONINDEX_SUBMENUWITHMISSING;
|
|
end
|
|
else
|
|
begin
|
|
LocalNode.ImageIndex:=ICONINDEX_SUBMENU;
|
|
LocalNode.SelectedIndex:=ICONINDEX_SUBMENU;
|
|
LocalNode.StateIndex:=ICONINDEX_SUBMENU;
|
|
end;
|
|
LocalNode.Data:=HotDir[Index];
|
|
if DirectoryHotlistIndexToSelectIfAny=Index then result:=LocalNode;
|
|
Inc(Index);
|
|
RecursivAddElements(LocalNode);
|
|
end;
|
|
|
|
hd_ENDMENU:
|
|
begin
|
|
FlagGetOut := True;
|
|
Inc(Index);
|
|
end;
|
|
|
|
hd_SEPARATOR:
|
|
begin
|
|
LocalNode:=ParamTreeView.Items.AddChildObject(WorkingNode, HOTLIST_SEPARATORSTRING ,HotDir[Index]);
|
|
LocalNode.Data:=HotDir[Index];
|
|
if DirectoryHotlistIndexToSelectIfAny=Index then result:=LocalNode;
|
|
Inc(Index);
|
|
end
|
|
|
|
else
|
|
begin
|
|
LocalNode:=ParamTreeView.Items.AddChildObject(WorkingNode, HotDir[Index].HotDirName,HotDir[Index]);
|
|
if HotDir[Index].FHotDirExistingState=DirNotExist then
|
|
begin
|
|
LocalNode.ImageIndex:=ICONINDEX_DIRECTORYNOTPRESENTHERE;
|
|
LocalNode.SelectedIndex:=ICONINDEX_DIRECTORYNOTPRESENTHERE;
|
|
LocalNode.StateIndex:=ICONINDEX_DIRECTORYNOTPRESENTHERE;
|
|
end;
|
|
LocalNode.Data:=HotDir[Index];
|
|
if DirectoryHotlistIndexToSelectIfAny=Index then result:=LocalNode;
|
|
Inc(Index);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
result:=nil;
|
|
ParamTreeView.Items.Clear;
|
|
Index := 0;
|
|
RecursivAddElements(nil);
|
|
end;
|
|
|
|
|
|
{ TDirectoryHotlist.PopulateMenuWithHotDir }
|
|
procedure TDirectoryHotlist.PopulateMenuWithHotDir(mncmpMenuComponentToPopulate: TComponent; ProcedureWhenHotDirItemClicked, ProcedureWhenHotDirAddOrConfigClicked: TProcedureWhenClickOnMenuItem; KindHotDirMenuPopulation: TKindHotDirMenuPopulation; TagOffset: longint);
|
|
var
|
|
I: longint; //Same variable for main and local routine
|
|
FlagCurrentPathAlreadyInMenu, FlagSelectedPathAlreadyInMenu: boolean;
|
|
CurrentPathToSearch, SelectedPathToSearch: string;
|
|
MaybeActiveOrSelectedDirectories: TFiles;
|
|
|
|
//Warning: "CompleteMenu" is recursive and call itself.
|
|
function CompleteMenu(ParamMenuItem: TMenuItem): longint;
|
|
var
|
|
localmi: TMenuItem;
|
|
LocalLastAdditionIsASeparator: boolean;
|
|
begin
|
|
Result := 0;
|
|
LocalLastAdditionIsASeparator := False;
|
|
while I < Count do
|
|
begin
|
|
Inc(I);
|
|
|
|
case HotDir[I - 1].Dispatcher of
|
|
hd_CHANGEPATH:
|
|
begin
|
|
case HotDir[I - 1].HotDirExisting of
|
|
DirExistUnknown, DirExist:
|
|
begin
|
|
localmi := TMenuItem.Create(ParamMenuItem);
|
|
localmi.Caption:= GetCaption(GetMenuCaptionAccordingToOptions(HotDir[I - 1].HotDirName,HotDir[I - 1].HotDirPath));
|
|
localmi.tag := (I - 1) + TagOffset;
|
|
localmi.OnClick := ProcedureWhenHotDirItemClicked;
|
|
ParamMenuItem.Add(localmi);
|
|
if CurrentPathToSearch = UpperCase(mbExpandFileName(HotDir[I - 1].FHotDirPath)) then FlagCurrentPathAlreadyInMenu := True;
|
|
if SelectedPathToSearch = UpperCase(mbExpandFileName(HotDir[I - 1].FHotDirPath)) then FlagSelectedPathAlreadyInMenu := True;
|
|
LocalLastAdditionIsASeparator := False;
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
hd_NULL, hd_COMMAND:
|
|
begin
|
|
if KindHotDirMenuPopulation <> mpPATHHELPER then
|
|
begin
|
|
localmi := TMenuItem.Create(ParamMenuItem);
|
|
localmi.Caption := GetCaption(HotDir[I - 1].HotDirName);
|
|
localmi.tag := (I - 1) + TagOffset;
|
|
localmi.OnClick := ProcedureWhenHotDirItemClicked;
|
|
ParamMenuItem.Add(localmi);
|
|
LocalLastAdditionIsASeparator := False;
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
hd_SEPARATOR:
|
|
begin
|
|
if (ParamMenuItem.Count > 0) and (not LocalLastAdditionIsASeparator) then
|
|
begin
|
|
localmi := TMenuItem.Create(ParamMenuItem);
|
|
localmi.Caption := '-';
|
|
ParamMenuItem.Add(localmi);
|
|
LocalLastAdditionIsASeparator := True;
|
|
Inc(Result);
|
|
end;
|
|
end;
|
|
|
|
hd_STARTMENU:
|
|
begin
|
|
localmi := TMenuItem.Create(ParamMenuItem);
|
|
localmi.Caption := GetCaption(HotDir[I - 1].HotDirName);
|
|
if gIconsInMenus then localmi.ImageIndex:=ICONINDEX_SUBMENU;
|
|
ParamMenuItem.Add(localmi);
|
|
CompleteMenu(localmi);
|
|
if localmi.Count <> 0 then
|
|
begin
|
|
LocalLastAdditionIsASeparator := False;
|
|
Inc(Result);
|
|
end
|
|
else
|
|
begin
|
|
localmi.Free;
|
|
end;
|
|
end;
|
|
|
|
hd_ENDMENU:
|
|
begin
|
|
if LocalLastAdditionIsASeparator then
|
|
begin
|
|
ParamMenuItem.Items[pred(ParamMenuItem.Count)].Free;
|
|
Dec(Result);
|
|
end;
|
|
exit;
|
|
end;
|
|
end; //case HotDir[I-1].Dispatcher of
|
|
end; //while I<Count do
|
|
end;
|
|
var
|
|
miMainTree: TMenuItem;
|
|
LastAdditionIsASeparator: boolean;
|
|
NumberOfElementsSoFar, InitialNumberOfItems: longint;
|
|
begin
|
|
MaybeActiveOrSelectedDirectories:=frmMain.ActiveFrame.CloneSelectedOrActiveDirectories;
|
|
try
|
|
// Create All popup menu
|
|
CurrentPathToSearch := UpperCase(mbExpandFileName(frmMain.ActiveFrame.CurrentLocation));
|
|
if MaybeActiveOrSelectedDirectories.Count=1 then SelectedPathToSearch := UpperCase(ExcludeTrailingPathDelimiter(mbExpandFileName(MaybeActiveOrSelectedDirectories.Items[0].FullPath))) else SelectedPathToSearch := TERMINATORNOTPRESENT;
|
|
|
|
FlagCurrentPathAlreadyInMenu := False;
|
|
FlagSelectedPathAlreadyInMenu := FALSE;
|
|
LastAdditionIsASeparator := False;
|
|
|
|
case KindHotDirMenuPopulation of
|
|
mpJUSTHOTDIRS, mpHOTDIRSWITHCONFIG:
|
|
begin
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then
|
|
begin
|
|
TPopupMenu(mncmpMenuComponentToPopulate).Items.Clear;
|
|
InitialNumberOfItems := mncmpMenuComponentToPopulate.ComponentCount;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
I := 0;
|
|
while I < Count do
|
|
begin
|
|
Inc(I);
|
|
|
|
case HotDir[I - 1].Dispatcher of
|
|
hd_CHANGEPATH:
|
|
begin
|
|
case HotDir[I - 1].HotDirExisting of
|
|
DirExistUnknown, DirExist:
|
|
begin
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
miMainTree.Caption := GetCaption(GetMenuCaptionAccordingToOptions(HotDir[I - 1].HotDirName,HotDir[I - 1].HotDirPath));
|
|
miMainTree.tag := (I - 1) + TagOffset;
|
|
miMainTree.OnClick := ProcedureWhenHotDirItemClicked;
|
|
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
|
|
if CurrentPathToSearch = UpperCase(mbExpandFileName(HotDir[I - 1].FHotDirPath)) then FlagCurrentPathAlreadyInMenu := True;
|
|
if SelectedPathToSearch = UpperCase(mbExpandFileName(HotDir[I - 1].FHotDirPath)) then FlagSelectedPathAlreadyInMenu := True;
|
|
LastAdditionIsASeparator := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
hd_NULL, hd_COMMAND:
|
|
begin
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
miMainTree.Caption := GetCaption(HotDir[I - 1].HotDirName);
|
|
miMainTree.tag := (I - 1) + TagOffset;
|
|
miMainTree.OnClick := ProcedureWhenHotDirItemClicked;
|
|
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
|
|
LastAdditionIsASeparator := False;
|
|
end;
|
|
|
|
hd_SEPARATOR:
|
|
begin
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then NumberOfElementsSoFar := TPopupMenu(mncmpMenuComponentToPopulate).Items.Count
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then NumberOfElementsSoFar := TMenuItem(mncmpMenuComponentToPopulate).Count;
|
|
if (NumberOfElementsSoFar > 0) and (not LastAdditionIsASeparator) then
|
|
begin
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
miMainTree.Caption := '-';
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
LastAdditionIsASeparator := True;
|
|
end;
|
|
end;
|
|
|
|
hd_STARTMENU:
|
|
begin
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
miMainTree.Caption := GetCaption(HotDir[I - 1].HotDirName);
|
|
if gIconsInMenus then miMainTree.ImageIndex := ICONINDEX_SUBMENU;
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then
|
|
TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else
|
|
if mncmpMenuComponentToPopulate.ClassType = TMenuItem then
|
|
TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
CompleteMenu(miMainTree);
|
|
if miMainTree.Count <> 0 then
|
|
begin
|
|
LastAdditionIsASeparator := False;
|
|
end
|
|
else
|
|
begin
|
|
miMainTree.Free;
|
|
end;
|
|
end;
|
|
|
|
hd_ENDMENU:
|
|
begin
|
|
if LastAdditionIsASeparator then
|
|
begin
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items[pred(TPopupMenu(mncmpMenuComponentToPopulate).Items.Count)].Free
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Items[pred(TMenuItem(mncmpMenuComponentToPopulate).Count)].Free;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
//2014-08-25:If last item added is a separator, we need to remove it so it will not look bad with another separator added at the end
|
|
if LastAdditionIsASeparator then
|
|
begin
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items[pred(TPopupMenu(mncmpMenuComponentToPopulate).Items.Count)].Free
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Items[pred(TMenuItem(mncmpMenuComponentToPopulate).Count)].Free;
|
|
end;
|
|
|
|
case KindHotDirMenuPopulation of
|
|
mpHOTDIRSWITHCONFIG:
|
|
begin
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then
|
|
begin
|
|
if mncmpMenuComponentToPopulate.ComponentCount>InitialNumberOfItems then
|
|
begin
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
miMainTree.Caption := '-';
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
end;
|
|
end;
|
|
|
|
// Let's add the "Special path" in a context of change directory
|
|
gSpecialDirList.PopulateMenuWithSpecialDir(mncmpMenuComponentToPopulate, mp_CHANGEDIR, ProcedureWhenHotDirItemClicked);
|
|
|
|
// now add delimiter
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
miMainTree.Caption := '-';
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
|
|
//now add the "selected path", if any, if it's the case
|
|
if MaybeActiveOrSelectedDirectories.Count>0 then
|
|
begin
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
case MaybeActiveOrSelectedDirectories.Count of
|
|
1: with Application.MainForm as TForm do if not FlagSelectedPathAlreadyInMenu then miMainTree.Caption := rsMsgHotDirAddSelectedDirectory + MinimizeFilePath(MaybeActiveOrSelectedDirectories.Items[0].FullPath, Canvas, 250).Replace('&','&&') else miMainTree.Caption := rsMsgHotDirReAddSelectedDirectory + MinimizeFilePath(MaybeActiveOrSelectedDirectories.Items[0].FullPath, Canvas, 250).Replace('&','&&');
|
|
else miMainTree.Caption := Format(rsMsgHotDirAddSelectedDirectories,[MaybeActiveOrSelectedDirectories.Count]);
|
|
end;
|
|
miMainTree.Tag := ACTION_ADDSELECTEDDIR;
|
|
miMainTree.OnClick := ProcedureWhenHotDirAddOrConfigClicked;
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
end;
|
|
|
|
// now allow to add or re-add the "current path"
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
with Application.MainForm as TForm do if not FlagCurrentPathAlreadyInMenu then miMainTree.Caption := rsMsgHotDirAddThisDirectory + MinimizeFilePath(frmMain.ActiveFrame.CurrentPath, Canvas, 250).Replace('&','&&') else miMainTree.Caption := rsMsgHotDirReAddThisDirectory + MinimizeFilePath(frmMain.ActiveFrame.CurrentPath, Canvas, 250).Replace('&','&&');
|
|
miMainTree.Tag := ACTION_ADDTOHOTLIST;
|
|
miMainTree.OnClick := ProcedureWhenHotDirAddOrConfigClicked;
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
|
|
// now add configure item
|
|
miMainTree := TMenuItem.Create(mncmpMenuComponentToPopulate);
|
|
miMainTree.Caption := rsMsgHotDirConfigHotlist;
|
|
miMainTree.Tag := ACTION_CONFIGTOHOTLIST;
|
|
miMainTree.ShortCut := frmMain.mnuCmdConfigDirHotlist.ShortCut;
|
|
miMainTree.OnClick := ProcedureWhenHotDirAddOrConfigClicked;
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then TPopupMenu(mncmpMenuComponentToPopulate).Items.Add(miMainTree)
|
|
else if mncmpMenuComponentToPopulate.ClassType = TMenuItem then TMenuItem(mncmpMenuComponentToPopulate).Add(miMainTree);
|
|
end;
|
|
end; //case KindHotDirMenuPopulation of
|
|
finally
|
|
FreeAndNil(MaybeActiveOrSelectedDirectories);
|
|
end;
|
|
|
|
if mncmpMenuComponentToPopulate.ClassType = TPopupMenu then
|
|
if TPopupMenu(mncmpMenuComponentToPopulate).Images=nil then
|
|
TPopupMenu(mncmpMenuComponentToPopulate).Images:= frmMain.imgLstDirectoryHotlist;
|
|
|
|
if mncmpMenuComponentToPopulate.ClassType = TMenuItem then
|
|
if TMenuItem(mncmpMenuComponentToPopulate).GetParentMenu.Images=nil then
|
|
TMenuItem(mncmpMenuComponentToPopulate).GetParentMenu.Images:= frmMain.imgLstDirectoryHotlist;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.LoadFromXml }
|
|
{ Information are stored like originally DC was storing them WITH addition of menu related info in a simular way TC. }
|
|
procedure TDirectoryHotlist.LoadFromXml(AConfig: TXmlConfig; ANode: TXmlNode);
|
|
var
|
|
sName, sPath: string;
|
|
LocalHotDir: THotDir;
|
|
CurrentMenuLevel: integer;
|
|
FlagAvortInsertion: boolean;
|
|
begin
|
|
Clear;
|
|
CurrentMenuLevel := 0;
|
|
|
|
ANode := ANode.FindNode(cSectionOfHotDir);
|
|
if Assigned(ANode) then
|
|
begin
|
|
ANode := ANode.FirstChild;
|
|
while Assigned(ANode) do
|
|
begin
|
|
if ANode.CompareName('HotDir') = 0 then
|
|
begin
|
|
if AConfig.TryGetAttr(ANode, 'Name', sName) and AConfig.TryGetAttr(ANode, 'Path', sPath) then
|
|
begin
|
|
FlagAvortInsertion := False;
|
|
LocalHotDir := THotDir.Create;
|
|
|
|
if sName = '-' then
|
|
begin
|
|
LocalHotDir.Dispatcher := hd_SEPARATOR;
|
|
end
|
|
else
|
|
begin
|
|
if sName = '--' then
|
|
begin
|
|
LocalHotDir.Dispatcher := hd_ENDMENU;
|
|
if CurrentMenuLevel > 0 then Dec(CurrentMenuLevel) else FlagAvortInsertion := True; //Sanity correction in case we got corrupted from any ways
|
|
end
|
|
else
|
|
begin
|
|
if (UTF8Length(sName) > 1) then
|
|
begin
|
|
if (sName[1] = '-') and (sName[2] <> '-') then
|
|
begin
|
|
Inc(CurrentMenuLevel);
|
|
LocalHotDir.Dispatcher := hd_STARTMENU;
|
|
LocalHotDir.HotDirName := UTF8RightStr(sName, UTF8Length(sName) - 1);
|
|
end;
|
|
end;
|
|
|
|
if LocalHotDir.Dispatcher = hd_NULL then
|
|
begin
|
|
LocalHotDir.HotDirName := sName;
|
|
LocalHotDir.HotDirPath := sPath;
|
|
if UTF8Pos('cm_', UTF8LowerCase(sPath)) <> 1 then
|
|
begin
|
|
LocalHotDir.HotDirPathSort := AConfig.GetAttr(Anode, 'PathSort', 0);
|
|
LocalHotDir.HotDirTarget := AConfig.GetAttr(ANode, 'Target', '');
|
|
LocalHotDir.HotDirTargetSort := AConfig.GetAttr(Anode, 'TargetSort', 0);
|
|
if Pos('://', LocalHotDir.HotDirPath) = 0 then LocalHotDir.HotDirPath:=ExcludeBackPathDelimiter(LocalHotDir.HotDirPath);
|
|
if Pos('://', LocalHotDir.HotDirTarget) = 0 then LocalHotDir.HotDirTarget:=ExcludeBackPathDelimiter(LocalHotDir.HotDirTarget);
|
|
LocalHotDir.Dispatcher := hd_CHANGEPATH;
|
|
end
|
|
else
|
|
begin
|
|
LocalHotDir.Dispatcher := hd_COMMAND;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not FlagAvortInsertion then
|
|
begin
|
|
Add(LocalHotDir);
|
|
end
|
|
else
|
|
begin
|
|
LocalHotDir.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
ANode := ANode.NextSibling;
|
|
end;
|
|
|
|
//Try to fix possible problem if the LAST MENU is not ending correctly...
|
|
while CurrentMenuLevel > 0 do
|
|
begin
|
|
Dec(CurrentMenuLevel);
|
|
LocalHotDir := THotDir.Create;
|
|
LocalHotDir.Dispatcher := hd_ENDMENU;
|
|
Add(LocalHotDir);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.SaveToXml }
|
|
// Information are stored like originally DC was storing them WITH addition of menu related info in a simular way TC.
|
|
// When the parameter has the same value as it would have when loaded with no value (so with the default value), the parameter is not saved...
|
|
// ...this way, it makes the overall filelenth smaller. When running on a portable mode from a usb key, everything thing counts! :-)
|
|
// ..."Name" and "Path" always must be present for backward compatibility reason in case someone would go backward.
|
|
// ...Not saving the value that are correctly initialized anyway as default on startup, with a setup of 386 entries for example saved 6642 bytes (5.3% of original 126005 bytes file)
|
|
//
|
|
procedure TDirectoryHotlist.SaveToXml(AConfig: TXmlConfig; ANode: TXmlNode; FlagEraseOriginalOnes: boolean);
|
|
var
|
|
Index: integer;
|
|
SubNode: TXmlNode;
|
|
begin
|
|
ANode := AConfig.FindNode(ANode, cSectionOfHotDir, True);
|
|
if FlagEraseOriginalOnes then AConfig.ClearNode(ANode);
|
|
for Index := 0 to pred(Count) do
|
|
begin
|
|
SubNode := AConfig.AddNode(ANode, 'HotDir');
|
|
|
|
case THotDir(HotDir[Index]).Dispatcher of
|
|
hd_NULL:
|
|
begin
|
|
AConfig.SetAttr(SubNode, 'Name', '');
|
|
AConfig.SetAttr(SubNode, 'Path', '');
|
|
end;
|
|
|
|
hd_CHANGEPATH:
|
|
begin
|
|
AConfig.SetAttr(SubNode, 'Name', HotDir[Index].HotDirName);
|
|
AConfig.SetAttr(SubNode, 'Path', HotDir[Index].HotDirPath);
|
|
if HotDir[Index].HotDirTarget <> '' then AConfig.SetAttr(SubNode, 'Target', HotDir[Index].HotDirTarget);
|
|
if HotDir[Index].HotDirPathSort <> 0 then AConfig.SetAttr(SubNode, 'PathSort', HotDir[Index].HotDirPathSort);
|
|
if HotDir[Index].HotDirTargetSort <> 0 then AConfig.SetAttr(SubNode, 'TargetSort', HotDir[Index].HotDirTargetSort);
|
|
end;
|
|
|
|
hd_SEPARATOR:
|
|
begin
|
|
AConfig.SetAttr(SubNode, 'Name', '-');
|
|
AConfig.SetAttr(SubNode, 'Path', '');
|
|
end;
|
|
|
|
hd_STARTMENU:
|
|
begin
|
|
AConfig.SetAttr(SubNode, 'Name', '-' + THotDir(HotDir[Index]).HotDirName);
|
|
AConfig.SetAttr(SubNode, 'Path', '');
|
|
end;
|
|
|
|
hd_ENDMENU:
|
|
begin
|
|
AConfig.SetAttr(SubNode, 'Name', '--');
|
|
AConfig.SetAttr(SubNode, 'Path', '');
|
|
end;
|
|
|
|
hd_COMMAND:
|
|
begin
|
|
AConfig.SetAttr(SubNode, 'Name', HotDir[Index].HotDirName);
|
|
AConfig.SetAttr(SubNode, 'Path', HotDir[Index].HotDirPath);
|
|
if HotDir[Index].HotDirTarget <> '' then AConfig.SetAttr(SubNode, 'Target', HotDir[Index].HotDirTarget);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.ImportDoubleCommander }
|
|
procedure TDirectoryHotlist.ImportDoubleCommander(DoubleCommanderFilename: String);
|
|
var
|
|
DoubleCommanderXMLToImport: TXmlConfig;
|
|
Root: TXmlNode;
|
|
begin
|
|
DoubleCommanderXMLToImport := TXmlConfig.Create(DoubleCommanderFilename);
|
|
try
|
|
if DoubleCommanderXMLToImport.Load then
|
|
begin
|
|
Root := DoubleCommanderXMLToImport.RootNode;
|
|
LoadFromXML(DoubleCommanderXMLToImport, Root);
|
|
end;
|
|
finally
|
|
FreeAndNil(DoubleCommanderXMLToImport);
|
|
end;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.ExportDoubleCommander }
|
|
function TDirectoryHotlist.ExportDoubleCommander(DoubleCommanderFilename: String; FlagEraseOriginalOnes: boolean): boolean;
|
|
var
|
|
DoubleCommanderXMLToImport: TXmlConfig;
|
|
Root: TXmlNode;
|
|
FlagKeepGoing: boolean;
|
|
begin
|
|
Result := False; //Unless we reach correctly the end, the result is negative
|
|
FlagKeepGoing := True;
|
|
|
|
DoubleCommanderXMLToImport := TXmlConfig.Create(DoubleCommanderFilename);
|
|
try
|
|
//Just in case we're requested to add or update content of a .XML file will already other data in it, first we load the structure
|
|
if FileExists(DoubleCommanderFilename) then FlagKeepGoing := DoubleCommanderXMLToImport.Load;
|
|
|
|
if FlagKeepGoing then
|
|
begin
|
|
Root := DoubleCommanderXMLToImport.RootNode;
|
|
SaveToXml(DoubleCommanderXMLToImport, Root, FlagEraseOriginalOnes);
|
|
Result := DoubleCommanderXMLToImport.Save;
|
|
end;
|
|
finally
|
|
FreeAndNil(DoubleCommanderXMLToImport);
|
|
end;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.AddFromAnotherTTreeViewTheSelected }
|
|
//It looks the ".selected" field only gives us the kind of "itemindex" of current selection in the TTREE.
|
|
//So, the apparent way to detect the current selected node is to check the ".Selection" fields.
|
|
//So, we'll set the "GroupNumber" of pointed HotDir to 1 to indicate the one to import.
|
|
//
|
|
function TDirectoryHotlist.AddFromAnotherTTreeViewTheSelected(ParamWorkingTreeView, ParamTreeViewToImport:TTreeView; FlagAddThemAll: boolean): longint;
|
|
|
|
procedure RecursiveAddTheOnesWithGroupNumberOne(WorkingTreeNode:TTreeNode; InsertionNodePlace:TTreeNode);
|
|
var
|
|
MaybeChildNode:TTreeNode;
|
|
WorkingHotDirEntry:THotDir;
|
|
NewTreeNode:TTreeNode;
|
|
begin
|
|
while WorkingTreeNode<>nil do
|
|
begin
|
|
MaybeChildNode:=WorkingTreeNode.GetFirstChild;
|
|
|
|
if MaybeChildNode<>nil then
|
|
begin
|
|
if (THotDir(WorkingTreeNode.Data).GroupNumber = 1) OR (FlagAddThemAll) then
|
|
begin
|
|
WorkingHotDirEntry:=THotDir.Create;
|
|
THotDir(WorkingTreeNode.Data).CopyToHotDir(WorkingHotDirEntry);
|
|
WorkingHotDirEntry.Dispatcher:=hd_STARTMENU; //Probably not necessary, but let's make sure it will start a menu
|
|
Add(WorkingHotDirEntry);
|
|
if ParamWorkingTreeView<>nil then
|
|
begin
|
|
NewTreeNode := ParamWorkingTreeView.Items.AddChildObject(InsertionNodePlace, WorkingHotDirEntry.HotDirName,HotDir[count-1]);
|
|
NewTreeNode.ImageIndex:=ICONINDEX_SUBMENU;
|
|
NewTreeNode.SelectedIndex:=ICONINDEX_SUBMENU;
|
|
NewTreeNode.StateIndex:=ICONINDEX_SUBMENU;
|
|
end;
|
|
inc(result);
|
|
end;
|
|
|
|
RecursiveAddTheOnesWithGroupNumberOne(MaybeChildNode,NewTreeNode);
|
|
|
|
if (THotDir(WorkingTreeNode.Data).GroupNumber=1) OR (FlagAddThemAll) then
|
|
begin
|
|
WorkingHotDirEntry:=THotDir.Create;
|
|
WorkingHotDirEntry.Dispatcher:=hd_ENDMENU;
|
|
Add(WorkingHotDirEntry);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if (THotDir(WorkingTreeNode.Data).GroupNumber=1) OR (FlagAddThemAll) then
|
|
begin
|
|
WorkingHotDirEntry:=THotDir.Create;
|
|
THotDir(WorkingTreeNode.Data).CopyToHotDir(WorkingHotDirEntry);
|
|
Add(WorkingHotDirEntry);
|
|
if ParamWorkingTreeView<>nil then
|
|
begin
|
|
case WorkingHotDirEntry.Dispatcher of
|
|
hd_Separator: NewTreeNode := ParamWorkingTreeView.Items.AddChildObject(InsertionNodePlace, HOTLIST_SEPARATORSTRING, HotDir[count-1]);
|
|
else NewTreeNode := ParamWorkingTreeView.Items.AddChildObject(InsertionNodePlace, WorkingHotDirEntry.HotDirName, HotDir[count-1]);
|
|
end;
|
|
end;
|
|
inc(result);
|
|
end;
|
|
end;
|
|
|
|
WorkingTreeNode:=WorkingTreeNode.GetNextSibling;
|
|
end;
|
|
end;
|
|
|
|
procedure RecursiveSetGroupNumberToOne(WorkingTreeNode:TTreeNode; FlagTakeAlsoSibling:boolean);
|
|
begin
|
|
repeat
|
|
if WorkingTreeNode.GetFirstChild=nil then
|
|
begin
|
|
if (THotDir(WorkingTreeNode.Data).Dispatcher<>hd_STARTMENU) AND (THotDir(WorkingTreeNode.Data).Dispatcher<>hd_ENDMENU) then
|
|
begin
|
|
THotDir(WorkingTreeNode.Data).GroupNumber:=1;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
THotDir(WorkingTreeNode.Data).GroupNumber:=1;
|
|
RecursiveSetGroupNumberToOne(WorkingTreeNode.GetFirstChild,TRUE);
|
|
end;
|
|
|
|
if FlagTakeAlsoSibling then WorkingTreeNode:=WorkingTreeNode.GetNextSibling;
|
|
until (FlagTakeAlsoSibling=FALSE) OR (WorkingTreeNode=nil);
|
|
end;
|
|
|
|
var
|
|
OutsideIndex:integer;
|
|
begin
|
|
result:=0;
|
|
|
|
//First, make sure no one is marked
|
|
for OutsideIndex:=0 to pred(ParamTreeViewToImport.Items.Count) do THotDir(ParamTreeViewToImport.Items.Item[OutsideIndex].Data).GroupNumber:=0;
|
|
|
|
//Then, set the "GroupNumber" to 1 to the ones to import
|
|
if ParamTreeViewToImport.SelectionCount>0 then for OutsideIndex:=0 to pred(ParamTreeViewToImport.SelectionCount) do RecursiveSetGroupNumberToOne(ParamTreeViewToImport.Selections[OutsideIndex],FALSE);
|
|
|
|
//Finally now collect the one with the "GroupNumber" set to 1.
|
|
RecursiveAddTheOnesWithGroupNumberOne(ParamTreeViewToImport.Items.Item[0],nil);
|
|
end;
|
|
|
|
{ TDirectoryHotlist.ComputeSignature }
|
|
// Routine tries to pickup all char chain from element of directory hotlist and compute a unique CRC32.
|
|
// This CRC32 will bea kind of signature of the directory hotlist.
|
|
function TDirectoryHotlist.ComputeSignature(Seed:dword):dword;
|
|
var
|
|
Index:integer;
|
|
begin
|
|
result:=Seed;
|
|
for Index := 0 to pred(Count) do
|
|
begin
|
|
Result := crc32(Result,@HotDir[Index].Dispatcher,1);
|
|
if length(HotDir[Index].HotDirName)>0 then Result := crc32(Result,@HotDir[Index].HotDirName[1],length(HotDir[Index].HotDirName));
|
|
if length(HotDir[Index].HotDirPath)>0 then Result := crc32(Result,@HotDir[Index].HotDirPath[1],length(HotDir[Index].HotDirPath));
|
|
Result := crc32(Result,@HotDir[Index].HotDirPathSort,4);
|
|
if length(HotDir[Index].HotDirTarget)>0 then Result := crc32(Result,@HotDir[Index].HotDirTarget[1],length(HotDir[Index].HotDirTarget));
|
|
Result := crc32(Result,@HotDir[Index].HotDirTargetSort,4);
|
|
Result := crc32(Result,@HotDir[Index].HotDirExisting,1);
|
|
Result := crc32(Result,@HotDir[Index].GroupNumber,4);
|
|
end;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.GetHotDir }
|
|
function TDirectoryHotlist.GetHotDir(Index: integer): THotDir;
|
|
begin
|
|
Result := THotDir(Items[Index]);
|
|
end;
|
|
|
|
{ TDirectoryHotlist.RefreshFromTTreeView }
|
|
//The routine will recreate the complete TDirectoryHotlist from a TTreeView.
|
|
//It cannot erase or replace immediately the current list because the TTreeView refer to it!
|
|
//So it create it into the "TransitDirectoryHotlist" and then, it will copy it to self one.
|
|
//
|
|
procedure TDirectoryHotlist.RefreshFromTTreeView(ParamTreeView:TTreeView);
|
|
var
|
|
TransitDirectoryHotlist:TDirectoryHotlist;
|
|
IndexToTryToRestore:longint=-1;
|
|
MaybeTTreeNodeToSelect:TTreeNode;
|
|
|
|
procedure RecursiveEncapsulateSubMenu(WorkingTreeNode:TTreeNode);
|
|
var
|
|
MaybeChildNode:TTreeNode;
|
|
WorkingHotDirEntry:THotDir;
|
|
begin
|
|
while WorkingTreeNode<>nil do
|
|
begin
|
|
if WorkingTreeNode=ParamTreeView.Selected then IndexToTryToRestore:=TransitDirectoryHotlist.Count;
|
|
|
|
MaybeChildNode:=WorkingTreeNode.GetFirstChild;
|
|
if MaybeChildNode<>nil then
|
|
begin
|
|
WorkingHotDirEntry:=THotDir.Create;
|
|
THotDir(WorkingTreeNode.Data).CopyToHotDir(WorkingHotDirEntry);
|
|
WorkingHotDirEntry.Dispatcher:=hd_STARTMENU; //Probably not necessary, but let's make sure it will start a menu
|
|
TransitDirectoryHotlist.Add(WorkingHotDirEntry);
|
|
|
|
RecursiveEncapsulateSubMenu(MaybeChildNode);
|
|
|
|
WorkingHotDirEntry:=THotDir.Create;
|
|
WorkingHotDirEntry.Dispatcher:=hd_ENDMENU;
|
|
TransitDirectoryHotlist.Add(WorkingHotDirEntry);
|
|
end
|
|
else
|
|
begin
|
|
//We won't copy EMPTY submenu so that's why we check for "hd_STARTMENU". And the check for "hd_ENDMENU" is simply probably unecessary protection
|
|
if (THotDir(WorkingTreeNode.Data).Dispatcher<>hd_STARTMENU) AND (THotDir(WorkingTreeNode.Data).Dispatcher<>hd_ENDMENU) then
|
|
begin
|
|
WorkingHotDirEntry:=THotDir.Create;
|
|
THotDir(WorkingTreeNode.Data).CopyToHotDir(WorkingHotDirEntry);
|
|
TransitDirectoryHotlist.Add(WorkingHotDirEntry);
|
|
end;
|
|
end;
|
|
WorkingTreeNode:=WorkingTreeNode.GetNextSibling;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if ParamTreeView.Items.count>0 then
|
|
begin
|
|
TransitDirectoryHotlist:=TDirectoryHotlist.Create;
|
|
try
|
|
RecursiveEncapsulateSubMenu(ParamTreeView.Items.Item[0]);
|
|
TransitDirectoryHotlist.CopyDirectoryHotlistToDirectoryHotlist(self);
|
|
MaybeTTreeNodeToSelect:=LoadTTreeView(ParamTreeView,IndexToTryToRestore);
|
|
if MaybeTTreeNodeToSelect<>nil then MaybeTTreeNodeToSelect.Selected:=TRUE else if ParamTreeView.Items.count>0 then ParamTreeView.Items.Item[0].Selected:=TRUE;
|
|
finally
|
|
TransitDirectoryHotlist.Clear;
|
|
TransitDirectoryHotlist.Free;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
Self.Clear;
|
|
end;
|
|
end;
|
|
|
|
{ TCheckDrivePresenceThread.Create }
|
|
constructor TCheckDrivePresenceThread.Create(sDrive: string; ParamListOfNonExistingDrive: TStringList; var ThreadCount: longint);
|
|
begin
|
|
FListOfNonExistingDrive := ParamListOfNonExistingDrive;
|
|
FDriveToSearchFor := sDrive;
|
|
FThreadCountPoint := addr(ThreadCount);
|
|
FreeOnTerminate := True;
|
|
inherited Create(False);
|
|
end;
|
|
|
|
{ TCheckDrivePresenceThread.Destroy }
|
|
destructor TCheckDrivePresenceThread.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{TCheckDrivePresenceThread.Execute}
|
|
procedure TCheckDrivePresenceThread.Execute;
|
|
begin
|
|
if FDriveToSearchFor = '' then
|
|
begin
|
|
Synchronize(@Self.ReportPresentInTheThread);
|
|
end
|
|
else
|
|
begin
|
|
if mbDirectoryExists(FDriveToSearchFor) then
|
|
begin
|
|
Synchronize(@Self.ReportPresentInTheThread);
|
|
end
|
|
else
|
|
begin
|
|
Synchronize(@Self.ReportNotPresentInTheThread);
|
|
end;
|
|
end;
|
|
Terminate;
|
|
end;
|
|
|
|
{ TCheckDrivePresenceThread.ReportPresentInTheThread }
|
|
procedure TCheckDrivePresenceThread.ReportPresentInTheThread;
|
|
begin
|
|
Dec(FThreadCountPoint^);
|
|
end;
|
|
|
|
{ TCheckDrivePresenceThread.ReportNotPresentInTheThread }
|
|
procedure TCheckDrivePresenceThread.ReportNotPresentInTheThread;
|
|
begin
|
|
FListOfNonExistingDrive.Add(FDriveToSearchFor);
|
|
Dec(FThreadCountPoint^);
|
|
end;
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
{ TDirectoryHotlist.ImportTotalCommander }
|
|
function TDirectoryHotlist.ImportTotalCommander(TotalCommanderConfigFilename: String): integer;
|
|
const
|
|
CONFIGFILE_SECTIONNAME = 'DirMenu';
|
|
CONFIGFILE_NAMEPREFIX = 'menu';
|
|
CONFIGFILE_PATHPREFIX = 'cmd';
|
|
CONFIGFILE_TARGETPREFIX = 'path';
|
|
var
|
|
LocalHotDir: THotDir;
|
|
ConfigFile: TIniFileEx;
|
|
sName, sPath, sTarget: string;
|
|
Index, CurrentMenuLevel, InitialNumberOfElement: longint;
|
|
FlagAvortInsertion: boolean;
|
|
begin
|
|
InitialNumberOfElement := Count;
|
|
Index := 1;
|
|
CurrentMenuLevel := 0;
|
|
|
|
ConfigFile := TIniFileEx.Create(mbExpandFilename(TotalCommanderConfigFilename));
|
|
|
|
try
|
|
repeat
|
|
sName := ConvertTCStringToString(ConfigFile.ReadString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(Index), TERMINATORNOTPRESENT));
|
|
|
|
if sName <> TERMINATORNOTPRESENT then
|
|
begin
|
|
FlagAvortInsertion := False;
|
|
LocalHotDir := THotDir.Create;
|
|
|
|
if sName = '-' then //Was it a separator?
|
|
begin
|
|
LocalHotDir.Dispatcher := hd_SEPARATOR;
|
|
end
|
|
else
|
|
begin
|
|
if sName = '--' then //Was is a end of menu?
|
|
begin
|
|
LocalHotDir.Dispatcher := hd_ENDMENU;
|
|
if CurrentMenuLevel > 0 then Dec(CurrentMenuLevel) else FlagAvortInsertion := True; //Sanity correction since Total Commande may contains extra end of menu...
|
|
end
|
|
else
|
|
begin
|
|
if (UTF8Length(sName) > 1) then //Was it a menu start?
|
|
begin
|
|
if (sName[1] = '-') and (sName[2] <> '-') then
|
|
begin
|
|
Inc(CurrentMenuLevel);
|
|
LocalHotDir.Dispatcher := hd_STARTMENU;
|
|
LocalHotDir.HotDirName := UTF8RightStr(sName, UTF8Length(sName) - 1);
|
|
end;
|
|
end;
|
|
|
|
if LocalHotDir.Dispatcher = hd_NULL then
|
|
begin
|
|
LocalHotDir.HotDirName := sName;
|
|
|
|
sPath := ReplaceTCEnvVars(ConvertTCStringToString(ConfigFile.ReadString(CONFIGFILE_SECTIONNAME, CONFIGFILE_PATHPREFIX + IntToStr(Index), '')));
|
|
if UTF8Length(sPath) > 3 then if UTF8Pos('cd ', UTF8LowerCase(sPath)) = 1 then sPath := UTF8Copy(sPath, 4, UTF8Length(sPath) - 3);
|
|
|
|
if UTF8Pos('cm_', UTF8LowerCase(sPath)) = 0 then //Make sure it's not a command
|
|
begin
|
|
if sPath <> '' then sPath := ExcludeBackPathDelimiter(sPath); //Not an obligation but DC convention seems to like a backslash at the end
|
|
|
|
sTarget := ReplaceTCEnvVars(ConvertTCStringToString(ConfigFile.ReadString(CONFIGFILE_SECTIONNAME, CONFIGFILE_TARGETPREFIX + IntToStr(Index), '')));
|
|
if UTF8Length(sTarget) > 3 then if UTF8Pos('cd ', UTF8LowerCase(sTarget)) = 1 then sTarget := UTF8Copy(sTarget, 4, UTF8Length(sTarget) - 3);
|
|
if sTarget <> '' then sTarget := ExcludeBackPathDelimiter(sTarget); //Not an obligation but DC convention seems to like a backslash at the end
|
|
|
|
LocalHotDir.Dispatcher := hd_CHANGEPATH;
|
|
LocalHotDir.HotDirPath := sPath;
|
|
LocalHotDir.HotDirTarget := sTarget;
|
|
end
|
|
else
|
|
begin //If it's command, store it as a command
|
|
LocalHotDir.Dispatcher := hd_COMMAND;
|
|
LocalHotDir.HotDirPath := sPath;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not FlagAvortInsertion then Add(LocalHotDir) else LocalHotDir.Free;
|
|
Inc(Index);
|
|
end;
|
|
until sName = TERMINATORNOTPRESENT;
|
|
|
|
//Try to fix possible problem if the LAST MENU is not ending correctly...
|
|
while CurrentMenuLevel > 0 do
|
|
begin
|
|
Dec(CurrentMenuLevel);
|
|
LocalHotDir := THotDir.Create;
|
|
LocalHotDir.Dispatcher := hd_ENDMENU;
|
|
Add(LocalHotDir);
|
|
end;
|
|
finally
|
|
ConfigFile.Free;
|
|
end;
|
|
Result := Count - InitialNumberOfElement;
|
|
end;
|
|
|
|
{ TDirectoryHotlist.ExportTotalCommander }
|
|
function TDirectoryHotlist.ExportTotalCommander(TotalCommanderConfigFilename: String; FlagEraseOriginalOnes: boolean): boolean;
|
|
const
|
|
CONFIGFILE_SECTIONNAME = 'DirMenu';
|
|
CONFIGFILE_NAMEPREFIX = 'menu';
|
|
CONFIGFILE_PATHPREFIX = 'cmd';
|
|
CONFIGFILE_TARGETPREFIX = 'path';
|
|
TERMINATORNOTPRESENT = ':-<#/?*+*?\#>-:';
|
|
var
|
|
ConfigFile: TIniFileEx;
|
|
Index, OffsetForOnesAlreadyThere: integer;
|
|
sName: string;
|
|
RememberCursor: TCursor;
|
|
begin
|
|
Result := True;
|
|
OffsetForOnesAlreadyThere := 0;
|
|
|
|
try
|
|
RememberCursor := Screen.Cursor;
|
|
Screen.Cursor := crHourGlass;
|
|
try
|
|
ConfigFile := TIniFileEx.Create(mbExpandFileName(TotalCommanderConfigFilename));
|
|
try
|
|
with ConfigFile do
|
|
begin
|
|
if FlagEraseOriginalOnes then
|
|
begin
|
|
EraseSection(CONFIGFILE_SECTIONNAME);
|
|
end
|
|
else
|
|
begin
|
|
Index := 1;
|
|
repeat
|
|
sName := ConfigFile.ReadString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(Index), TERMINATORNOTPRESENT);
|
|
if sName <> TERMINATORNOTPRESENT then Inc(OffsetForOnesAlreadyThere);
|
|
Inc(Index);
|
|
until sName = TERMINATORNOTPRESENT;
|
|
end;
|
|
|
|
for Index := 0 to pred(Count) do
|
|
begin
|
|
case THotDir(HotDir[Index]).Dispatcher of
|
|
hd_NULL:
|
|
begin
|
|
end;
|
|
|
|
hd_CHANGEPATH:
|
|
begin
|
|
WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(THotDir(HotDir[Index]).HotDirName));
|
|
if THotDir(HotDir[Index]).HotDirPath <> '' then WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_PATHPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString('cd ' + ReplaceDCEnvVars(THotDir(HotDir[Index]).HotDirPath)));
|
|
if THotDir(HotDir[Index]).HotDirTarget <> '' then WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_TARGETPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(ReplaceDCEnvVars(THotDir(HotDir[Index]).HotDirTarget)));
|
|
end;
|
|
|
|
hd_SEPARATOR:
|
|
begin
|
|
WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), '-');
|
|
end;
|
|
|
|
hd_STARTMENU:
|
|
begin
|
|
//See the position of the '-'. It *must* be inside the parameter for calling "ConvertStringToTCString" because the expected utf8 signature of TC must be before the '-'.
|
|
WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString('-' + THotDir(HotDir[Index]).HotDirName));
|
|
end;
|
|
|
|
hd_ENDMENU:
|
|
begin
|
|
WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), '--');
|
|
end;
|
|
|
|
hd_COMMAND:
|
|
begin
|
|
WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_NAMEPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(THotDir(HotDir[Index]).HotDirName));
|
|
if THotDir(HotDir[Index]).HotDirPath <> '' then WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_PATHPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(THotDir(HotDir[Index]).HotDirPath));
|
|
if THotDir(HotDir[Index]).HotDirTarget <> '' then WriteString(CONFIGFILE_SECTIONNAME, CONFIGFILE_TARGETPREFIX + IntToStr(OffsetForOnesAlreadyThere + Index + 1), ConvertStringToTCString(THotDir(HotDir[Index]).HotDirTarget));
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
ConfigFile.UpdateFile;
|
|
finally
|
|
ConfigFile.Free;
|
|
end;
|
|
|
|
except
|
|
Result := False;
|
|
end;
|
|
|
|
finally
|
|
Screen.Cursor := RememberCursor;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
end.
|
|
|