mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
ADD: Warn the user when attempting to quit the plugin configuration without having saved possible unsaved modification. ADD: In the plugin configuration table, if a text is too large to fit in a column, a tooltip is displayed showing the complete text. ADD: Individual configuration pages for DSX, WCX, WDX, WFX and WLX plugins. ADD: Plugin tweak dialog windows now remember their dimensions from a session to another. ADD: Double-click on an item in the list of plugins in the configuration now trigs the tweak window for selected plugin. ADD: When we just add a plugin, it is now the selected one in the list. ADD: Add an option to go to tweak dialog window right after a plugin in added. CHG: The path to the plugin is now *loaded*, *displayed* and *saved* as what the user sees. CHG: The path for the plugin files may now be defined with full relative path based on either windows special folders, environment variables or full complete path. It is not simply on a path deeper than %COMMANDERPATH% like it was before. ADD: In the plugin tweak dialog window, we now have an actual "TFileNameEdit" with a button and the file requester to select our plugin location. ADD: In the plugin tweak dialog window, we now have a button with a popup menu to help to adapt the path of the plugin location like to make it relative to a specified location. ADD: There is now an option to make DC automatically use relative path to what we want when we add a plugin file. We may also apply that retro-active. ADD: In the plugin configuration, do not display a column if not pertinent (like column 2 in WFX). ADD: In the WCX plugin configuration window, we may display plugins grouped by plugin file or by file extension as they appear in config file AND how they are actually used when searching for a qualified one. ADD: Add the internal command "cm_ConfigPlugins". FIX: Added WCX plugin associated with an empty extension was not displayed at first in the grid and needed to close and reopen the configuration window. This is fixed. FIX: Adding a file extension associated with a WCX plugin in the tweaking window from a WCX where previously *just one* extension was associated was not switching enabled the "Remove" button. This is fixed. UPD: Languages files have been modified, but efforts have been made to re-use existing translations and to avoid "fuzzy" attributes.
405 lines
10 KiB
ObjectPascal
405 lines
10 KiB
ObjectPascal
{
|
|
Double Commander
|
|
-------------------------------------------------------------------------
|
|
(DSX) Search plugin API implementation.
|
|
DSX - Double commander Search eXtentions.
|
|
|
|
Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru)
|
|
Copyright (C) 2008-2018 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
}
|
|
|
|
unit uDsxModule;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, dynlibs, LCLProc, DsxPlugin, DCClassesUtf8, uDCUtils,
|
|
DCXmlConfig;
|
|
|
|
type
|
|
|
|
{ TDsxModule }
|
|
|
|
TDsxModule = class
|
|
protected
|
|
SStartSearch: TSStartSearch;
|
|
SStopSearch: TSStopSearch;
|
|
SAddFileProc: TSAddFileProc;
|
|
SUpdateStatusProc: TSUpdateStatusProc;
|
|
SInit: TSInit;
|
|
SFinalize: TSFinalize;
|
|
private
|
|
FPluginNr: integer;
|
|
FModuleHandle: TLibHandle; // Handle to .DLL or .so
|
|
function GIsLoaded: boolean;
|
|
public
|
|
Name: string;
|
|
FileName: string;
|
|
Descr: string;
|
|
//---------------------
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
//---------------------
|
|
function LoadModule: boolean;
|
|
procedure UnloadModule;
|
|
//---------------------
|
|
function CallInit(pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): integer;
|
|
procedure CallStartSearch(SearchRec: TDsxSearchRecord);
|
|
procedure CallStopSearch;
|
|
procedure CallFinalize;
|
|
//---------------------
|
|
property IsLoaded: boolean read GIsLoaded;
|
|
property ModuleHandle: TLibHandle read FModuleHandle write FModuleHandle;
|
|
end;
|
|
|
|
{ TDSXModuleList }
|
|
|
|
TDSXModuleList = class
|
|
private
|
|
Flist: TStringList;
|
|
function GetCount: integer;
|
|
public
|
|
//---------------------
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
//---------------------
|
|
procedure Clear;
|
|
procedure Exchange(Index1, Index2: Integer);
|
|
procedure Move(CurIndex, NewIndex: Integer);
|
|
procedure Load(AConfig: TXmlConfig; ANode: TXmlNode); overload;
|
|
procedure Save(AConfig: TXmlConfig; ANode: TXmlNode); overload;
|
|
function ComputeSignature(seed: dword): dword;
|
|
procedure DeleteItem(Index: integer);
|
|
//---------------------
|
|
function Add(Item: TDSXModule): integer; overload;
|
|
function Add(FileName: string): integer; overload;
|
|
function Add(AName, FileName, Descr: string): integer; overload;
|
|
//---------------------
|
|
procedure Assign(OtherList: TDSXModuleList);
|
|
//---------------------
|
|
function IsLoaded(AName: string): boolean; overload;
|
|
function IsLoaded(Index: integer): boolean; overload;
|
|
function LoadModule(AName: string): boolean; overload;
|
|
function LoadModule(Index: integer): boolean; overload;
|
|
//---------------------
|
|
function GetDSXModule(Index: integer): TDSXModule; overload;
|
|
function GetDSXModule(AName: string): TDSXModule; overload;
|
|
//---------------------
|
|
property Count: integer read GetCount;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
//Lazarus, Free-Pascal, etc.
|
|
|
|
//DC
|
|
DCOSUtils, uDebug, uGlobs, uGlobsPaths, uComponentsSignature;
|
|
|
|
const
|
|
DsxIniFileName = 'dsx.ini';
|
|
|
|
{ TDsxModule }
|
|
|
|
function TDsxModule.GIsLoaded: boolean;
|
|
begin
|
|
Result := FModuleHandle <> 0;
|
|
end;
|
|
|
|
constructor TDsxModule.Create;
|
|
begin
|
|
FModuleHandle := 0;
|
|
inherited Create;
|
|
end;
|
|
|
|
destructor TDsxModule.Destroy;
|
|
begin
|
|
if GIsLoaded then
|
|
UnloadModule;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TDsxModule.LoadModule: boolean;
|
|
begin
|
|
FModuleHandle := mbLoadLibrary(mbExpandFileName(Self.FileName));
|
|
Result := (FModuleHandle <> 0);
|
|
if FModuleHandle = 0 then
|
|
exit;
|
|
|
|
SStopSearch := TSStopSearch(GetProcAddress(FModuleHandle, 'StopSearch'));
|
|
SStartSearch := TSStartSearch(GetProcAddress(FModuleHandle, 'StartSearch'));
|
|
SInit := TSInit(GetProcAddress(FModuleHandle, 'Init'));
|
|
SFinalize := TSFinalize(GetProcAddress(FModuleHandle, 'Finalize'));
|
|
end;
|
|
|
|
procedure TDsxModule.UnloadModule;
|
|
begin
|
|
if Assigned(SFinalize) then
|
|
SFinalize(FPluginNr);
|
|
|
|
{$IF (not DEFINED(LINUX)) or ((FPC_VERSION > 2) or ((FPC_VERSION=2) and (FPC_RELEASE >= 5)))}
|
|
if FModuleHandle <> 0 then
|
|
FreeLibrary(FModuleHandle);
|
|
{$ENDIF}
|
|
FModuleHandle := 0;
|
|
|
|
SStartSearch := nil;
|
|
SStopSearch := nil;
|
|
SInit := nil;
|
|
SFinalize := nil;
|
|
end;
|
|
|
|
function TDsxModule.CallInit(pAddFileProc: TSAddFileProc; pUpdateStatus: TSUpdateStatusProc): integer;
|
|
var
|
|
dps: TDsxDefaultParamStruct;
|
|
begin
|
|
if Assigned(SInit) then
|
|
begin
|
|
dps.DefaultIniName := gpCfgDir + DsxIniFileName;
|
|
dps.PluginInterfaceVersionHi := 0;
|
|
dps.PluginInterfaceVersionLow := 10;
|
|
dps.size := SizeOf(TDsxDefaultParamStruct);
|
|
FPluginNr := Sinit(@dps, pAddFileProc, pUpdateStatus);
|
|
Result := FPluginNr;
|
|
end;
|
|
end;
|
|
|
|
procedure TDsxModule.CallStartSearch(SearchRec: TDsxSearchRecord);
|
|
begin
|
|
if Assigned(SStartSearch) then
|
|
SStartSearch(FPluginNr, @SearchRec);
|
|
end;
|
|
|
|
procedure TDsxModule.CallStopSearch;
|
|
begin
|
|
if Assigned(SStopSearch) then
|
|
SStopSearch(FPluginNr);
|
|
end;
|
|
|
|
procedure TDsxModule.CallFinalize;
|
|
begin
|
|
if Assigned(SFinalize) then
|
|
SFinalize(FPluginNr);
|
|
end;
|
|
|
|
{ TDSXModuleList }
|
|
|
|
function TDSXModuleList.GetCount: integer;
|
|
begin
|
|
if Assigned(Flist) then
|
|
Result := Flist.Count
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
constructor TDSXModuleList.Create;
|
|
begin
|
|
Flist := TStringList.Create;
|
|
end;
|
|
|
|
destructor TDSXModuleList.Destroy;
|
|
begin
|
|
Clear;
|
|
FreeAndNil(Flist);
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TDSXModuleList.Clear;
|
|
begin
|
|
while Flist.Count > 0 do
|
|
begin
|
|
TDSXModule(Flist.Objects[0]).Free;
|
|
Flist.Delete(0);
|
|
end;
|
|
end;
|
|
|
|
procedure TDSXModuleList.Exchange(Index1, Index2: Integer);
|
|
begin
|
|
FList.Exchange(Index1, Index2);
|
|
end;
|
|
|
|
procedure TDSXModuleList.Move(CurIndex, NewIndex: Integer);
|
|
begin
|
|
FList.Move(CurIndex, NewIndex);
|
|
end;
|
|
|
|
procedure TDSXModuleList.Load(AConfig: TXmlConfig; ANode: TXmlNode);
|
|
var
|
|
AName, APath: String;
|
|
ADsxModule: TDSXModule;
|
|
begin
|
|
Clear;
|
|
|
|
ANode := ANode.FindNode('DsxPlugins');
|
|
if Assigned(ANode) then
|
|
begin
|
|
ANode := ANode.FirstChild;
|
|
while Assigned(ANode) do
|
|
begin
|
|
if ANode.CompareName('DsxPlugin') = 0 then
|
|
begin
|
|
if AConfig.TryGetValue(ANode, 'Name', AName) and
|
|
AConfig.TryGetValue(ANode, 'Path', APath) then
|
|
begin
|
|
ADsxModule := TDsxModule.Create;
|
|
Flist.AddObject(UpCase(AName), ADsxModule);
|
|
ADsxModule.Name := AName;
|
|
ADsxModule.FileName := APath;
|
|
ADsxModule.Descr := AConfig.GetValue(ANode, 'Description', '');
|
|
end
|
|
else
|
|
DCDebug('Invalid entry in configuration: ' + AConfig.GetPathFromNode(ANode) + '.');
|
|
end;
|
|
ANode := ANode.NextSibling;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TDSXModuleList.Save(AConfig: TXmlConfig; ANode: TXmlNode);
|
|
var
|
|
i: Integer;
|
|
SubNode: TXmlNode;
|
|
begin
|
|
ANode := AConfig.FindNode(ANode, 'DsxPlugins', True);
|
|
AConfig.ClearNode(ANode);
|
|
|
|
for i := 0 to Flist.Count - 1 do
|
|
begin
|
|
SubNode := AConfig.AddNode(ANode, 'DsxPlugin');
|
|
AConfig.AddValue(SubNode, 'Name', TDSXModule(Flist.Objects[I]).Name);
|
|
AConfig.AddValue(SubNode, 'Path', TDSXModule(Flist.Objects[I]).FileName);
|
|
AConfig.AddValue(SubNode, 'Description', TDSXModule(Flist.Objects[I]).Descr);
|
|
end;
|
|
end;
|
|
|
|
{ TDSXModuleList.ComputeSignature }
|
|
function TDSXModuleList.ComputeSignature(seed: dword): dword;
|
|
var
|
|
iIndex: integer;
|
|
begin
|
|
result := seed;
|
|
for iIndex := 0 to pred(Count) do
|
|
begin
|
|
result := ComputeSignatureString(result, TDSXModule(Flist.Objects[iIndex]).Name);
|
|
result := ComputeSignatureString(result, TDSXModule(Flist.Objects[iIndex]).FileName);
|
|
result := ComputeSignatureString(result, TDSXModule(Flist.Objects[iIndex]).Descr);
|
|
end;
|
|
end;
|
|
|
|
procedure TDSXModuleList.DeleteItem(Index: integer);
|
|
begin
|
|
if (Index > -1) and (Index < Flist.Count) then
|
|
begin
|
|
TDSXModule(Flist.Objects[Index]).Free;
|
|
Flist.Delete(Index);
|
|
end;
|
|
end;
|
|
|
|
function TDSXModuleList.Add(Item: TDSXModule): integer;
|
|
begin
|
|
Result := Flist.AddObject(UpCase(item.Name), Item);
|
|
end;
|
|
|
|
function TDSXModuleList.Add(FileName: string): integer;
|
|
var
|
|
s: string;
|
|
begin
|
|
s := ExtractFileName(FileName);
|
|
if pos('.', s) > 0 then
|
|
Delete(s, pos('.', s), length(s));
|
|
Result := Flist.AddObject(UpCase(s), TDSXModule.Create);
|
|
TDSXModule(Flist.Objects[Result]).Name := s;
|
|
TDSXModule(Flist.Objects[Result]).FileName := FileName;
|
|
end;
|
|
|
|
function TDSXModuleList.Add(AName, FileName, Descr: string): integer;
|
|
begin
|
|
Result := Flist.AddObject(UpCase(AName), TDSXModule.Create);
|
|
TDSXModule(Flist.Objects[Result]).Name := AName;
|
|
TDSXModule(Flist.Objects[Result]).Descr := Descr;
|
|
TDSXModule(Flist.Objects[Result]).FileName := FileName;
|
|
end;
|
|
|
|
procedure TDSXModuleList.Assign(OtherList: TDSXModuleList);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Clear;
|
|
for i := 0 to OtherList.Flist.Count - 1 do
|
|
begin
|
|
with TDSXModule(OtherList.Flist.Objects[I]) do
|
|
Add(Name, FileName, Descr);
|
|
end;
|
|
end;
|
|
|
|
function TDSXModuleList.IsLoaded(AName: string): boolean;
|
|
var
|
|
x: integer;
|
|
begin
|
|
x := Flist.IndexOf(AName);
|
|
if x = -1 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := GetDSXModule(x).IsLoaded;
|
|
end;
|
|
end;
|
|
|
|
function TDSXModuleList.IsLoaded(Index: integer): boolean;
|
|
begin
|
|
Result := GetDSXModule(Index).IsLoaded;
|
|
end;
|
|
|
|
function TDSXModuleList.LoadModule(AName: string): boolean;
|
|
var
|
|
x: integer;
|
|
begin
|
|
x := Flist.IndexOf(UpCase(AName));
|
|
if x = -1 then
|
|
Result := False
|
|
else
|
|
begin
|
|
Result := GetDSXModule(x).LoadModule;
|
|
end;
|
|
end;
|
|
|
|
function TDSXModuleList.LoadModule(Index: integer): boolean;
|
|
begin
|
|
Result := GetDSXModule(Index).LoadModule;
|
|
end;
|
|
|
|
function TDSXModuleList.GetDSXModule(Index: integer): TDSXModule;
|
|
begin
|
|
Result := TDSXModule(Flist.Objects[Index]);
|
|
end;
|
|
|
|
function TDSXModuleList.GetDSXModule(AName: string): TDSXModule;
|
|
var
|
|
tmp: integer;
|
|
begin
|
|
tmp := Flist.IndexOf(upcase(AName));
|
|
if tmp > -1 then
|
|
Result := TDSXModule(Flist.Objects[tmp]);
|
|
end;
|
|
|
|
end.
|
|
|