mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
535 lines
15 KiB
ObjectPascal
535 lines
15 KiB
ObjectPascal
unit uStashFileSource;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,
|
|
Graphics, Menus, ActnList,
|
|
uFile, uFileProperty, uFileSourceManager,
|
|
uFileSourceProperty, uFileSourceOperation, uFileSourceOperationTypes,
|
|
uFileSource, uVirtualFileSource, uFileSystemFileSource,
|
|
uDCUtils, DCStrUtils, uLng, uSysFolders,
|
|
uStashFilesBackend
|
|
{$IFDEF DARWIN}
|
|
, uDarwinImage
|
|
{$ENDIF}
|
|
;
|
|
|
|
type
|
|
|
|
{ TStashFileSourceProcessor }
|
|
|
|
TStashFileSourceProcessor = class( TDefaultFileSourceProcessor )
|
|
private
|
|
procedure consultCopyOperation( var params: TFileSourceConsultParams );
|
|
procedure consultMoveOperation( var params: TFileSourceConsultParams );
|
|
procedure consultPackOperation( var params: TFileSourceConsultParams );
|
|
public
|
|
procedure consultOperation( var params: TFileSourceConsultParams ); override;
|
|
procedure confirmOperation(var params: TFileSourceConsultParams); override;
|
|
end;
|
|
|
|
{ TStashFileSource }
|
|
|
|
TStashFileSource = class(TVirtualFileSource)
|
|
private
|
|
_fileSystemFS: IFileSystemFileSource;
|
|
private
|
|
procedure onFileSystemEvent(var params: TFileSourceEventParams);
|
|
procedure onStashChanged(Sender: TObject);
|
|
procedure reload; overload;
|
|
public
|
|
constructor Create; override; overload;
|
|
destructor Destroy; override;
|
|
class function GetFileSource: IFileSource; override;
|
|
|
|
function GetLocalName(var aFile: TFile): Boolean; override;
|
|
function GetRootDir(sPath : String): String; override;
|
|
function GetRealPath(const path: String): String; override;
|
|
function IsPathAtRoot(Path: String): Boolean; override;
|
|
class function IsSupportedPath(const Path: String): Boolean; override;
|
|
|
|
class function GetMainIcon(out Path: String): Boolean; override;
|
|
function GetCustomIcon(const path: String; const iconSize: Integer): TBitmap; override; overload;
|
|
function GetDisplayFileName(aFile: TFile): String; override;
|
|
function QueryContextMenu(AFiles: TFiles; var AMenu: TPopupMenu): Boolean; override;
|
|
|
|
function GetProcessor: TFileSourceProcessor; override;
|
|
function GetProperties: TFileSourceProperties; override;
|
|
function GetSupportedFileProperties: TFilePropertiesTypes; override;
|
|
function GetRetrievableFileProperties: TFilePropertiesTypes; override;
|
|
function GetOperationsTypes: TFileSourceOperationTypes; override;
|
|
class function CreateFile(const APath: String): TFile; override;
|
|
procedure RetrieveProperties(AFile: TFile; PropertiesToSet: TFilePropertiesTypes; const AVariantProperties: array of String); override;
|
|
function CreateListOperation(TargetPath: String): TFileSourceOperation; override;
|
|
function CreateCopyInOperation(SourceFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override;
|
|
function CreateCopyOutOperation(TargetFileSource: IFileSource; var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override;
|
|
function CreateMoveOperation(var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation; override;
|
|
function CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation; override;
|
|
function CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation; override;
|
|
function CreateSplitOperation(var aSourceFile: TFile; aTargetPath: String): TFileSourceOperation; override;
|
|
function CreateCombineOperation(var theSourceFiles: TFiles; aTargetFile: String): TFileSourceOperation; override;
|
|
function CreateCalcStatisticsOperation(var theFiles: TFiles): TFileSourceOperation; override;
|
|
function CreateSetFilePropertyOperation(var theTargetFiles: TFiles; var theNewProperties: TFileProperties): TFileSourceOperation; override;
|
|
function CreateExecuteOperation(var ExecutableFile: TFile; BasePath, Verb: String): TFileSourceOperation; override;
|
|
|
|
function needReload(const PathToReload: String; const PathToCheck: String): Boolean; override;
|
|
procedure AddSearchPath( const startPath: String; paths: TStringList); override;
|
|
end;
|
|
|
|
var
|
|
stashActionAddToStash: TAction;
|
|
stashActionRemoveFromStash: TAction;
|
|
stashActionEmptyStash: TAction;
|
|
|
|
const
|
|
STASH_SCHEME = 'stash://';
|
|
|
|
implementation
|
|
|
|
uses
|
|
uStashFileSourceOperation;
|
|
|
|
var
|
|
stashFileSourceProcessor: TFileSourceProcessor;
|
|
|
|
{ TStashFileSourceProcessor }
|
|
|
|
procedure TStashFileSourceProcessor.consultCopyOperation(
|
|
var params: TFileSourceConsultParams);
|
|
var
|
|
sourceFS: IFileSource;
|
|
targetFS: IFileSource;
|
|
|
|
procedure doSource;
|
|
begin
|
|
if NOT (fspDirectAccess in targetFS.Properties) and
|
|
NOT (fsoCopyIn in targetFS.GetOperationsTypes) then
|
|
Exit;
|
|
|
|
if fspDirectAccess in targetFS.Properties then begin
|
|
params.resultOperationType:= fsoCopyOut;
|
|
params.resultFS:= sourceFS;
|
|
end else begin
|
|
params.resultOperationType:= fsoCopyIn;
|
|
params.resultFS:= targetFS;
|
|
end;
|
|
params.operationTemp:= False;
|
|
params.consultResult:= fscrSuccess;
|
|
params.handled:= False;
|
|
end;
|
|
|
|
procedure doTarget;
|
|
begin
|
|
if NOT (fspDirectAccess in sourceFS.Properties) then
|
|
Exit;
|
|
|
|
params.resultOperationType:= fsoCopyIn;
|
|
params.resultFS:= targetFS;
|
|
params.operationTemp:= False;
|
|
params.consultResult:= fscrSuccess;
|
|
end;
|
|
|
|
begin
|
|
sourceFS:= params.sourceFS;
|
|
targetFS:= params.targetFS;
|
|
|
|
if params.phase=TFileSourceConsultPhase.source then
|
|
doSource
|
|
else
|
|
doTarget;
|
|
end;
|
|
|
|
procedure TStashFileSourceProcessor.consultMoveOperation(
|
|
var params: TFileSourceConsultParams);
|
|
begin
|
|
if params.phase=TFileSourceConsultPhase.target then
|
|
Exit;
|
|
|
|
if fspDirectAccess in params.targetFS.Properties then
|
|
params.consultResult:= fscrSuccess;
|
|
end;
|
|
|
|
procedure TStashFileSourceProcessor.consultPackOperation(
|
|
var params: TFileSourceConsultParams);
|
|
begin
|
|
if params.phase=TFileSourceConsultPhase.target then
|
|
Exit;
|
|
Inherited consultOperation( params );
|
|
end;
|
|
|
|
procedure TStashFileSourceProcessor.consultOperation(
|
|
var params: TFileSourceConsultParams);
|
|
begin
|
|
params.consultResult:= fscrNotSupported;
|
|
params.handled:= True;
|
|
|
|
if params.partnerFS.IsClass(TStashFileSource) then
|
|
Exit;
|
|
|
|
if fspImmutable in params.targetFS.Properties then
|
|
Exit;
|
|
|
|
case params.operationType of
|
|
fsoCopy:
|
|
self.consultCopyOperation( params );
|
|
fsoMove:
|
|
self.consultMoveOperation( params );
|
|
fsoPack:
|
|
self.consultPackOperation( params );
|
|
end;
|
|
end;
|
|
|
|
procedure TStashFileSourceProcessor.confirmOperation(
|
|
var params: TFileSourceConsultParams);
|
|
begin
|
|
case params.operationType of
|
|
fsoCopy: begin
|
|
if (params.resultFS=params.partnerFS) then begin
|
|
params.files.setPathBaseOnAllFiles;
|
|
params.handled:= True;
|
|
end;
|
|
end;
|
|
fsoPack:
|
|
params.files.setPathBaseOnAllFiles;
|
|
end;
|
|
end;
|
|
|
|
{ TStashFileSource }
|
|
|
|
procedure TStashFileSource.onFileSystemEvent(var params: TFileSourceEventParams);
|
|
begin
|
|
self.Reload( params.paths );
|
|
end;
|
|
|
|
procedure TStashFileSource.onStashChanged(Sender: TObject);
|
|
begin
|
|
TThread.Synchronize( nil, @self.reload );
|
|
end;
|
|
|
|
procedure TStashFileSource.reload;
|
|
begin
|
|
self.Reload( self.GetRootDir );
|
|
end;
|
|
|
|
constructor TStashFileSource.Create;
|
|
begin
|
|
Inherited Create;
|
|
stashFilesBackend.setListener( @self.onStashChanged );
|
|
FCurrentAddress:= STASH_SCHEME;
|
|
_fileSystemFS:= IFileSystemFileSource(FileSourceManager.Find(TFileSystemFileSource,EmptyStr));
|
|
_fileSystemFS.AddEventListener( @self.onFileSystemEvent );
|
|
|
|
FOperationsClasses[fsoCopyIn] := TStashCopyInOperation.GetOperationClass;
|
|
FOperationsClasses[fsoCopyOut] := _fileSystemFS.GetOperationClass(fsoCopyOut);
|
|
FOperationsClasses[fsoMove] := _fileSystemFS.GetOperationClass(fsoMove);;
|
|
end;
|
|
|
|
destructor TStashFileSource.Destroy;
|
|
begin
|
|
stashFilesBackend.setListener( nil );
|
|
_fileSystemFS.RemoveEventListener( @self.onFileSystemEvent );
|
|
inherited Destroy;
|
|
end;
|
|
|
|
class function TStashFileSource.GetFileSource: IFileSource;
|
|
begin
|
|
Result:= FileSourceManager.Find( TStashFileSource, STASH_SCHEME );
|
|
if not Assigned(Result) then
|
|
Result:= TStashFileSource.Create;
|
|
end;
|
|
|
|
function TStashFileSource.GetLocalName(var aFile: TFile): Boolean;
|
|
begin
|
|
Result:= True;
|
|
end;
|
|
|
|
class function TStashFileSource.GetMainIcon(out Path: String): Boolean;
|
|
begin
|
|
Path:= 'cm_openstash';
|
|
Result:= True;
|
|
end;
|
|
|
|
function TStashFileSource.GetCustomIcon(
|
|
const path: String;
|
|
const iconSize: Integer): TBitmap;
|
|
{$IFDEF DARWIN}
|
|
var
|
|
iconPath: String;
|
|
begin
|
|
self.GetMainIcon( iconPath );
|
|
Result:= darwinImageCacheForPath.copyBitmapForFileContent( iconPath, iconSize, False );
|
|
end;
|
|
{$ELSE}
|
|
begin
|
|
Result:= nil;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
function TStashFileSource.GetDisplayFileName(aFile: TFile): String;
|
|
var
|
|
fullpath: String;
|
|
begin
|
|
fullpath:= aFile.FullPath;
|
|
if fullpath = self.GetRootDir() then
|
|
Result:= rsStashName
|
|
else
|
|
Result:= ExtractFileName( ExcludeTrailingPathDelimiter(fullpath) );
|
|
end;
|
|
|
|
function TStashFileSource.needReload(
|
|
const PathToReload: String;
|
|
const PathToCheck: String): Boolean;
|
|
begin
|
|
// todo: it should check the path in StashFilesBackend
|
|
Result:= True;
|
|
end;
|
|
|
|
function TStashFileSource.GetProcessor: TFileSourceProcessor;
|
|
begin
|
|
Result:= stashFileSourceProcessor;
|
|
end;
|
|
|
|
function TStashFileSource.GetRootDir(sPath: String): String;
|
|
begin
|
|
Result:= PathDelim + rsStashName + PathDelim;
|
|
end;
|
|
|
|
function TStashFileSource.GetRealPath(const path: String): String;
|
|
begin
|
|
if self.IsPathAtRoot(path) then
|
|
Result:= GetHomeDir
|
|
else
|
|
Result:= Path;
|
|
end;
|
|
|
|
function TStashFileSource.IsPathAtRoot(Path: String): Boolean;
|
|
var
|
|
dirs: TStringList;
|
|
dirCount: Integer;
|
|
begin
|
|
dirs:= TStringList.Create;
|
|
dirCount:= GetDirs( ExcludeTrailingPathDelimiter(Path), dirs );
|
|
Result:= (dirCount <= 1);
|
|
dirs.Free;
|
|
end;
|
|
|
|
class function TStashFileSource.IsSupportedPath(const Path: String): Boolean;
|
|
begin
|
|
Result:= Path.StartsWith( STASH_SCHEME );
|
|
end;
|
|
|
|
function TStashFileSource.GetProperties: TFileSourceProperties;
|
|
begin
|
|
Result:= _fileSystemFS.Properties;
|
|
Result+= [fspLinksToLocalFiles, fspDontChangePath, fspDontCreateDirectory];
|
|
end;
|
|
|
|
function TStashFileSource.GetSupportedFileProperties: TFilePropertiesTypes;
|
|
begin
|
|
Result:= _fileSystemFS.SupportedFileProperties;
|
|
end;
|
|
|
|
function TStashFileSource.GetRetrievableFileProperties: TFilePropertiesTypes;
|
|
begin
|
|
Result:= _fileSystemFS.RetrievableFileProperties;
|
|
end;
|
|
|
|
function TStashFileSource.GetOperationsTypes: TFileSourceOperationTypes;
|
|
begin
|
|
Result:= [fsoList,
|
|
fsoCopyIn, fsoCopyOut, fsoMove,
|
|
fsoDelete, fsoWipe,
|
|
fsoSplit, fsoCombine,
|
|
fsoCalcStatistics,
|
|
fsoSetFileProperty,
|
|
fsoExecute,
|
|
fsoTestArchive];
|
|
end;
|
|
|
|
class function TStashFileSource.CreateFile(const APath: String): TFile;
|
|
begin
|
|
Result:= TFileSystemFileSource.CreateFile(APath);
|
|
end;
|
|
|
|
procedure TStashFileSource.RetrieveProperties(AFile: TFile;
|
|
PropertiesToSet: TFilePropertiesTypes;
|
|
const AVariantProperties: array of String);
|
|
begin
|
|
_fileSystemFS.RetrieveProperties(AFile, PropertiesToSet, AVariantProperties);
|
|
end;
|
|
|
|
function TStashFileSource.CreateListOperation(TargetPath: String): TFileSourceOperation;
|
|
begin
|
|
Result:= TStashListOperation.Create(Self, TargetPath);
|
|
end;
|
|
|
|
function TStashFileSource.CreateCopyInOperation(SourceFileSource: IFileSource;
|
|
var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation;
|
|
begin
|
|
Result:= TStashCopyInOperation.Create(
|
|
SourceFileSource,
|
|
self,
|
|
SourceFiles,
|
|
TargetPath );
|
|
end;
|
|
|
|
function TStashFileSource.CreateCopyOutOperation(TargetFileSource: IFileSource;
|
|
var SourceFiles: TFiles; TargetPath: String): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateCopyOutOperation(
|
|
TargetFileSource,
|
|
SourceFiles,
|
|
TargetPath );
|
|
end;
|
|
|
|
function TStashFileSource.CreateMoveOperation(var SourceFiles: TFiles;
|
|
TargetPath: String): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateMoveOperation(SourceFiles, TargetPath);
|
|
end;
|
|
|
|
function TStashFileSource.CreateDeleteOperation(var FilesToDelete: TFiles): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateDeleteOperation( FilesToDelete );
|
|
end;
|
|
|
|
function TStashFileSource.CreateWipeOperation(var FilesToWipe: TFiles): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateWipeOperation( FilesToWipe );
|
|
end;
|
|
|
|
function TStashFileSource.CreateSplitOperation(var aSourceFile: TFile;
|
|
aTargetPath: String): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateSplitOperation(aSourceFile, aTargetPath);
|
|
end;
|
|
|
|
function TStashFileSource.CreateCombineOperation(var theSourceFiles: TFiles;
|
|
aTargetFile: String): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateCombineOperation(theSourceFiles, aTargetFile);
|
|
end;
|
|
|
|
function TStashFileSource.CreateCalcStatisticsOperation(var theFiles: TFiles
|
|
): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateCalcStatisticsOperation(theFiles);
|
|
end;
|
|
|
|
function TStashFileSource.CreateSetFilePropertyOperation(
|
|
var theTargetFiles: TFiles; var theNewProperties: TFileProperties
|
|
): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateSetFilePropertyOperation(
|
|
theTargetFiles,
|
|
theNewProperties );
|
|
end;
|
|
|
|
function TStashFileSource.CreateExecuteOperation(var ExecutableFile: TFile;
|
|
BasePath, Verb: String): TFileSourceOperation;
|
|
begin
|
|
Result:= _fileSystemFS.CreateExecuteOperation(ExecutableFile, BasePath, Verb);
|
|
end;
|
|
|
|
function TStashFileSource.QueryContextMenu(AFiles: TFiles; var AMenu: TPopupMenu): Boolean;
|
|
var
|
|
removedIndex: Integer;
|
|
index: Integer;
|
|
|
|
function hasValidPath: Boolean;
|
|
var
|
|
testPath: String;
|
|
begin
|
|
Result:= False;
|
|
if AFiles.Count = 0 then
|
|
Exit;
|
|
if AFiles.Count = 1 then begin
|
|
testPath:= IncludeTrailingPathDelimiter( AFiles[0].FullPath );
|
|
Result:= NOT self.IsPathAtRoot( testPath );
|
|
end else begin
|
|
Result:= True;
|
|
end;
|
|
end;
|
|
|
|
procedure removeAddToStash;
|
|
begin
|
|
removedIndex:= AMenu.Items.IndexOfCaption( stashActionAddToStash.Caption );
|
|
if removedIndex >= 0 then
|
|
AMenu.Items.Delete( removedIndex );
|
|
end;
|
|
|
|
procedure addRemoveStashItems;
|
|
var
|
|
item: TMenuItem;
|
|
begin
|
|
item:= TMenuItem.Create( AMenu );
|
|
item.Action:= stashActionRemoveFromStash;
|
|
AMenu.Items.Insert(index, item);
|
|
inc( index );
|
|
end;
|
|
|
|
procedure addEmptyStash;
|
|
var
|
|
item: TMenuItem;
|
|
begin
|
|
item:= TMenuItem.Create( AMenu );
|
|
item.Action:= stashActionEmptyStash;
|
|
AMenu.Items.Insert(index, item);
|
|
inc( index );
|
|
end;
|
|
|
|
procedure addSeperator;
|
|
var
|
|
item: TMenuItem;
|
|
begin
|
|
item:= TMenuItem.Create( AMenu );
|
|
item.Caption:= '-';
|
|
AMenu.Items.Insert(index, item);
|
|
end;
|
|
|
|
begin
|
|
Result:= True;
|
|
|
|
removeAddToStash;
|
|
|
|
if removedIndex >= 0 then
|
|
index:= removedIndex
|
|
else
|
|
index:= 0;
|
|
|
|
if hasValidPath then
|
|
addRemoveStashItems;
|
|
|
|
if stashFilesBackend.count > 0 then
|
|
addEmptyStash;
|
|
|
|
if (removedIndex < 0) and (AMenu.Items.Count > 0) then
|
|
addSeperator;
|
|
end;
|
|
|
|
procedure TStashFileSource.AddSearchPath(
|
|
const startPath: String;
|
|
paths: TStringList );
|
|
var
|
|
files: TFiles;
|
|
i: Integer;
|
|
begin
|
|
if paths.Count > 0 then
|
|
Exit;
|
|
files:= self.GetFiles( self.GetRootDir );
|
|
for i:= 0 to files.Count-1 do
|
|
paths.Add( files[i].FullPath );
|
|
files.Free;
|
|
end;
|
|
|
|
initialization
|
|
stashFileSourceProcessor:= TStashFileSourceProcessor.Create;
|
|
|
|
finalization
|
|
FreeAndNil( stashFileSourceProcessor );
|
|
|
|
end.
|
|
|