View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0001927 | Double Commander | Logic | public | 2017-10-06 17:39 | 2020-11-30 07:44 |
| Reporter | CryHam | Assigned To | cordylus | ||
| Priority | high | Severity | minor | Reproducibility | always |
| Status | closed | Resolution | open | ||
| Projection | none | ETA | none | ||
| Product Version | 1.0.0 (trunk) | Product Build | trunk@7564 | ||
| Summary | 0001927: Compare by Contents - Not Implemented from Search result and archives. | ||||
| Description | The command: File - Compare by Contents, does not work from: - search results (after find with Alt-f7 and used Feed to listbox) - archives (e.g. browsing inside a zip) It shows a messagebox "Not Implemented." Basically it only works when both files are in a regular view of directory. In code as: msgWarning(rsMsgNotImplemented); in file umaincommands.pas, procedure TMainCommands.cm_CompareContents Not sure what extra code search result needs. But for archives I guess a standard way is to extract to a random temporary file (in system TEMP) and use pass its name to the diff tool. Would be great to implement it. | ||||
| Steps To Reproduce | (are in description) | ||||
| Tags | No tags attached. | ||||
| Attached Files | compare-search-result.diff (1,456 bytes)
Index: src/umaincommands.pas
===================================================================
--- src/umaincommands.pas (revision 7831)
+++ src/umaincommands.pas (working copy)
@@ -2674,7 +2674,7 @@
begin
with frmMain do
begin
- // For now work only for filesystem.
+ // For now work only for filesystem and search result.
// Later use temporary file system for other file sources.
try
@@ -2689,8 +2689,9 @@
end
else
begin
- // For now work only for filesystem.
- if not (ActiveFrame.FileSource.IsClass(TFileSystemFileSource)) then
+ // For now work only for filesystem and search result.
+ if not (ActiveFrame.FileSource.IsClass(TFileSystemFileSource))
+ and not (ActiveFrame.FileSource.IsClass(TSearchResultFileSource)) then
begin
msgWarning(rsMsgNotImplemented);
Exit;
@@ -2719,8 +2720,9 @@
if NotActiveSelectedFiles.Count = 1 then
begin
- // For now work only for filesystem.
- if not (NotActiveFrame.FileSource.IsClass(TFileSystemFileSource)) then
+ // For now work only for filesystem and search result.
+ if not (NotActiveFrame.FileSource.IsClass(TFileSystemFileSource))
+ and not (NotActiveFrame.FileSource.IsClass(TSearchResultFileSource)) then
begin
msgWarning(rsMsgNotImplemented);
Exit;
bug1927.patch (38,295 bytes)
Index: src/fdiffer.pas
===================================================================
--- src/fdiffer.pas (revision 7907)
+++ src/fdiffer.pas (working copy)
@@ -29,7 +29,7 @@
Classes, SysUtils, FileUtil, Forms, Controls, Dialogs, Menus, ComCtrls,
ActnList, ExtCtrls, EditBtn, Buttons, SynEdit, uSynDiffControls,
uPariterControls, uDiffOND, uFormCommands, uHotkeyManager, uOSForms,
- uBinaryDiffViewer;
+ uBinaryDiffViewer, uShowForm;
type
@@ -214,6 +214,7 @@
EncodingList: TStringList;
ScrollLock: LongInt;
FShowIdentical: Boolean;
+ FWaitData: TWaitData;
FCommands: TFormCommands;
procedure ShowIdentical;
procedure Clear(bLeft, bRight: Boolean);
@@ -248,7 +249,7 @@
procedure cm_SaveRight(const Params: array of string);
end;
-procedure ShowDiffer(const FileNameLeft, FileNameRight: String);
+procedure ShowDiffer(const FileNameLeft, FileNameRight: String; WaitData: TWaitData = nil);
implementation
@@ -261,10 +262,11 @@
const
HotkeysCategory = 'Differ';
-procedure ShowDiffer(const FileNameLeft, FileNameRight: String);
+procedure ShowDiffer(const FileNameLeft, FileNameRight: String; WaitData: TWaitData = nil);
begin
with TfrmDiffer.Create(Application) do
begin
+ FWaitData := WaitData;
edtFileNameLeft.Text:= FileNameLeft;
edtFileNameRight.Text:= FileNameRight;
FShowIdentical:= actAutoCompare.Checked;
@@ -984,6 +986,7 @@
BinaryViewerRight.SecondViewer:= nil;
HotMan.UnRegister(Self);
inherited Destroy;
+ if Assigned(FWaitData) then FWaitData.Done;
end;
procedure TfrmDiffer.BuildHashList(bLeft, bRight: Boolean);
Index: src/feditor.pas
===================================================================
--- src/feditor.pas (revision 7907)
+++ src/feditor.pas (working copy)
@@ -161,7 +161,7 @@
sEncodingIn,
sEncodingOut,
sOriginalText: String;
- FWaitData: TEditorWaitData;
+ FWaitData: TWaitData;
FCommands: TFormCommands;
property Commands: TFormCommands read FCommands implements IFormCommands;
@@ -222,8 +222,7 @@
procedure cm_EditRplc(const {%H-}Params:array of string);
end;
- procedure ShowEditor(WaitData: TEditorWaitData);
- function ShowEditor(const sFileName: String): TfrmEditor;
+ procedure ShowEditor(const sFileName: String; WaitData: TWaitData = nil);
implementation
@@ -234,29 +233,24 @@
uLng, uShowMsg, fEditSearch, uGlobs, fOptions, DCClassesUtf8,
uOSUtils, uConvEncoding, fOptionsToolsEditor, uDCUtils, uClipboard;
-function ShowEditor(const sFileName: String): TfrmEditor;
+procedure ShowEditor(const sFileName: String; WaitData: TWaitData = nil);
+var
+ Editor: TfrmEditor;
begin
- Result := TfrmEditor.Create(Application);
+ Editor := TfrmEditor.Create(Application);
+ Editor.FWaitData := WaitData;
if sFileName = '' then
- Result.cm_FileNew([''])
+ Editor.cm_FileNew([''])
else
begin
- if not Result.OpenFile(sFileName) then
+ if not Editor.OpenFile(sFileName) then
Exit;
end;
- Result.ShowOnTop;
+ Editor.ShowOnTop;
end;
-procedure ShowEditor(WaitData: TEditorWaitData);
-var
- Editor: TfrmEditor;
-begin
- Editor:= ShowEditor(WaitData.FileName);
- Editor.FWaitData:= WaitData
-end;
-
procedure TfrmEditor.FormCreate(Sender: TObject);
var
i:Integer;
@@ -536,7 +530,7 @@
begin
HotMan.UnRegister(Self);
inherited Destroy;
- if Assigned(FWaitData) then EditDone(FWaitData);
+ if Assigned(FWaitData) then FWaitData.Done;
end;
Index: src/ffileexecuteyourself.pas
===================================================================
--- src/ffileexecuteyourself.pas (revision 7907)
+++ src/ffileexecuteyourself.pas (working copy)
@@ -46,13 +46,13 @@
procedure FormCreate(Sender: TObject);
private
FFileSource: IFileSource;
- FWaitData: TEditorWaitData;
+ FWaitData: TWaitData;
public
constructor Create(TheOwner: TComponent; aFileSource: IFileSource; const FileName, FromPath: String); reintroduce;
destructor Destroy; override;
end;
- procedure ShowFileEditExternal(aWaitData: TEditorWaitData);
+ procedure ShowFileEditExternal(const FileName, FromPath: string; aWaitData: TWaitData);
function ShowFileExecuteYourSelf(aFileView: TFileView; aFile: TFile; bWithAll: Boolean): Boolean;
implementation
@@ -62,13 +62,10 @@
uses
LCLProc, uTempFileSystemFileSource, uFileSourceOperation, uShellExecute, DCOSUtils;
-procedure ShowFileEditExternal(aWaitData: TEditorWaitData);
-var
- APath: String;
+procedure ShowFileEditExternal(const FileName, FromPath: string; aWaitData: TWaitData);
begin
- APath:= aWaitData.TargetFileSource.CurrentAddress + aWaitData.TargetPath;
// Create wait window
- with TfrmFileExecuteYourSelf.Create(Application, nil, ExtractFileName(aWaitData.FileName), APath) do
+ with TfrmFileExecuteYourSelf.Create(Application, nil, FileName, FromPath) do
begin
FWaitData:= aWaitData;
// Show wait window
@@ -155,7 +152,7 @@
// Delete the temporary file source and all files inside.
FFileSource:= nil;
inherited Destroy;
- if Assigned(FWaitData) then EditDone(FWaitData);
+ if Assigned(FWaitData) then FWaitData.Done;
end;
end.
Index: src/umaincommands.pas
===================================================================
--- src/umaincommands.pas (revision 7907)
+++ src/umaincommands.pas (working copy)
@@ -505,31 +505,13 @@
procedure TMainCommands.OnEditCopyOutStateChanged(Operation: TFileSourceOperation;
State: TFileSourceOperationState);
var
- aFile: TFile;
WaitData: TEditorWaitData;
- aFileSource: ITempFileSystemFileSource;
- aCopyOutOperation: TFileSourceCopyOperation;
begin
if (State = fsosStopped) and (Operation.Result = fsorFinished) then
begin
- aCopyOutOperation := Operation as TFileSourceCopyOperation;
- aFileSource := aCopyOutOperation.TargetFileSource as ITempFileSystemFileSource;
-
try
- aFile := aCopyOutOperation.SourceFiles[0];
-
- WaitData:= TEditorWaitData.Create;
-
+ WaitData := TEditorWaitData.Create(Operation as TFileSourceCopyOperation);
try
- WaitData.TargetPath:= aCopyOutOperation.SourceFiles.Path;
-
- ChangeFileListRoot(aFileSource.FileSystemRoot, aCopyOutOperation.SourceFiles);
-
- WaitData.FileName:= aFile.FullPath;
- WaitData.SourceFileSource:= aFileSource;
- WaitData.FileTime:= mbFileAge(WaitData.FileName);
- WaitData.TargetFileSource:= aCopyOutOperation.FileSource as IFileSource;
-
ShowEditorByGlob(WaitData);
except
WaitData.Free;
@@ -1737,9 +1719,6 @@
ActiveFile: TFile = nil;
AllFiles: TFiles = nil;
SelectedFiles: TFiles = nil;
- TempFiles: TFiles = nil;
- TempFileSource: ITempFileSystemFileSource = nil;
- Operation: TFileSourceOperation;
aFileSource: IFileSource;
sCmd: string = '';
sParams: string = '';
@@ -1767,44 +1746,8 @@
// Default to using the file source directly.
aFileSource := ActiveFrame.FileSource;
- // If files are links to local files
- if (fspLinksToLocalFiles in ActiveFrame.FileSource.Properties) then
- begin
- for I := 0 to SelectedFiles.Count - 1 do
- begin
- aFile := SelectedFiles[I];
- ActiveFrame.FileSource.GetLocalName(aFile);
- end;
- end
- // If files not directly accessible copy them to temp file source.
- else if not (fspDirectAccess in ActiveFrame.FileSource.Properties) then
- begin
- if not (fsoCopyOut in ActiveFrame.FileSource.GetOperationsTypes) then
- begin
- msgWarning(rsMsgErrNotSupported);
- Exit;
- end;
-
- TempFiles := SelectedFiles.Clone;
-
- TempFileSource := TTempFileSystemFileSource.GetFileSource;
-
- Operation := ActiveFrame.FileSource.CreateCopyOutOperation(
- TempFileSource,
- TempFiles,
- TempFileSource.FileSystemRoot);
-
- if Assigned(Operation) then
- begin
- Operation.AddStateChangedListener([fsosStopped], @OnCopyOutStateChanged);
- OperationsManager.AddOperation(Operation);
- end
- else
- begin
- msgWarning(rsMsgErrNotSupported);
- end;
+ if PrepareData(ActiveFrame.FileSource, SelectedFiles, @OnCopyOutStateChanged) <> pdrSynchronous then
Exit;
- end;
try
aFile := SelectedFiles[0];
@@ -1875,7 +1818,6 @@
FreeAndNil(sl);
FreeAndNil(AllFiles);
FreeAndNil(SelectedFiles);
- FreeAndNil(TempFiles);
FreeAndNil(ActiveFile);
end;
end;
@@ -2026,10 +1968,7 @@
var
i: Integer;
aFile: TFile;
- TempFiles: TFiles;
SelectedFiles: TFiles = nil;
- Operation: TFileSourceOperation;
- TempFileSource: ITempFileSystemFileSource = nil;
sCmd: string = '';
sParams: string = '';
sStartPath: string = '';
@@ -2037,44 +1976,9 @@
with frmMain do
try
SelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles;
- // If files are links to local files
- if (fspLinksToLocalFiles in ActiveFrame.FileSource.Properties) then
- begin
- for I := 0 to SelectedFiles.Count - 1 do
- begin
- aFile := SelectedFiles[I];
- ActiveFrame.FileSource.GetLocalName(aFile);
- end;
- end
- // If files not directly accessible copy them to temp file source.
- else if not (fspDirectAccess in ActiveFrame.FileSource.Properties) then
- begin
- if not (fsoCopyOut in ActiveFrame.FileSource.GetOperationsTypes) then
- begin
- msgWarning(rsMsgErrNotSupported);
- Exit;
- end;
- TempFiles := SelectedFiles.Clone;
-
- TempFileSource := TTempFileSystemFileSource.GetFileSource;
-
- Operation := ActiveFrame.FileSource.CreateCopyOutOperation(
- TempFileSource,
- TempFiles,
- TempFileSource.FileSystemRoot);
-
- if Assigned(Operation) then
- begin
- Operation.AddStateChangedListener([fsosStopped], @OnEditCopyOutStateChanged);
- OperationsManager.AddOperation(Operation);
- end
- else
- begin
- msgWarning(rsMsgErrNotSupported);
- end;
+ if PrepareData(ActiveFrame.FileSource, SelectedFiles, @OnEditCopyOutStateChanged) <> pdrSynchronous then
Exit;
- end;
try
for i := 0 to SelectedFiles.Count - 1 do
@@ -2655,15 +2559,18 @@
procedure TMainCommands.cm_CompareContents(const Params: array of string);
var
- FilesToCompare: TStringList = nil;
- DirsToCompare: TStringList = nil;
+ FilesNumber: Integer = 0;
+ DirsNumber: Integer = 0;
- procedure AddItem(const aFile: TFile);
+ procedure CountFiles(const Files: TFiles);
+ var I: Integer;
begin
- if not aFile.IsDirectory then
- FilesToCompare.Add(aFile.FullPath)
- else
- DirsToCompare.Add(aFile.FullPath);
+ if Assigned(Files) then
+ for I := 0 to Files.Count - 1 do
+ if Files[I].IsDirectory then
+ Inc(DirsNumber)
+ else
+ Inc(FilesNumber);
end;
var
@@ -2671,31 +2578,19 @@
Param: String;
ActiveSelectedFiles: TFiles = nil;
NotActiveSelectedFiles: TFiles = nil;
+ FirstFileSource: IFileSource = nil;
+ FirstFileSourceFiles: TFiles = nil;
+ SecondFileSource: IFileSource = nil;
+ SecondFileSourceFiles: TFiles = nil;
begin
with frmMain do
begin
- // For now works only for file source with direct access.
- // Later use temporary file system for other file sources.
-
- try
- FilesToCompare := TStringList.Create;
- DirsToCompare := TStringList.Create;
Param := GetDefaultParam(Params);
if Param = 'dir' then
- begin
- DirsToCompare.Add(FrameLeft.CurrentPath);
- DirsToCompare.Add(FrameRight.CurrentPath);
- end
+ ShowDifferByGlob(FrameLeft.CurrentPath, FrameRight.CurrentPath)
else
begin
- // For now works only for file source with direct access.
- if not (fspDirectAccess in ActiveFrame.FileSource.Properties) then
- begin
- msgWarning(rsMsgNotImplemented);
- Exit;
- end;
-
try
ActiveSelectedFiles := ActiveFrame.CloneSelectedOrActiveFiles;
@@ -2719,31 +2614,31 @@
if NotActiveSelectedFiles.Count = 1 then
begin
- // For now works only for file source with direct access.
- if not (fspDirectAccess in NotActiveFrame.FileSource.Properties) then
- begin
- msgWarning(rsMsgNotImplemented);
- Exit;
- end;
{ compare single selected files in both panels }
case gResultingFramePositionAfterCompare of
rfpacActiveOnLeft:
- begin;
- AddItem(ActiveSelectedFiles[0]);
- AddItem(NotActiveSelectedFiles[0]);
+ begin
+ FirstFileSource := ActiveFrame.FileSource;
+ FirstFileSourceFiles := ActiveSelectedFiles;
+ SecondFileSource := NotActiveFrame.FileSource;
+ SecondFileSourceFiles := NotActiveSelectedFiles;
end;
rfpacLeftOnLeft:
begin
if ActiveFrame = FrameLeft then
begin
- AddItem(ActiveSelectedFiles[0]);
- AddItem(NotActiveSelectedFiles[0]);
+ FirstFileSource := ActiveFrame.FileSource;
+ FirstFileSourceFiles := ActiveSelectedFiles;
+ SecondFileSource := NotActiveFrame.FileSource;
+ SecondFileSourceFiles := NotActiveSelectedFiles;
end
else begin
- AddItem(NotActiveSelectedFiles[0]);
- AddItem(ActiveSelectedFiles[0]);
+ FirstFileSource := NotActiveFrame.FileSource;
+ FirstFileSourceFiles := NotActiveSelectedFiles;
+ SecondFileSource := ActiveFrame.FileSource;
+ SecondFileSourceFiles := ActiveSelectedFiles;
end;
end;
end;
@@ -2760,45 +2655,39 @@
begin
{ compare all selected files in active frame }
- for I := 0 to ActiveSelectedFiles.Count - 1 do
- AddItem(ActiveSelectedFiles[I]);
+ FirstFileSource := ActiveFrame.FileSource;
+ FirstFileSourceFiles := ActiveSelectedFiles;
end;
+ CountFiles(FirstFileSourceFiles);
+ CountFiles(SecondFileSourceFiles);
+
+ if ((FilesNumber > 0) and (DirsNumber > 0))
+ or ((FilesNumber = 1) or (DirsNumber = 1)) then
+ // Either files or directories must be selected and more than one.
+ MsgWarning(rsMsgInvalidSelection)
+ else if (FilesNumber = 0) and (DirsNumber = 0) then
+ MsgWarning(rsMsgNoFilesSelected)
+ else if (FilesNumber > 2) and not gExternalTools[etDiffer].Enabled then
+ MsgWarning(rsMsgTooManyFilesSelected)
+ else if (DirsNumber > 0) and not gExternalTools[etDiffer].Enabled then
+ MsgWarning(rsMsgNotImplemented)
+ else
+ begin
+ if not Assigned(SecondFileSource) then
+ PrepareToolData(FirstFileSource, FirstFileSourceFiles,
+ @ShowDifferByGlobList)
+ else
+ PrepareToolData(FirstFileSource, FirstFileSourceFiles,
+ SecondFileSource, SecondFileSourceFiles,
+ @ShowDifferByGlobList);
+ end;
+
finally
FreeAndNil(ActiveSelectedFiles);
FreeAndNil(NotActiveSelectedFiles);
end;
end;
-
- if ((FilesToCompare.Count > 0) and (DirsToCompare.Count > 0))
- or ((FilesToCompare.Count = 1) or (DirsToCompare.Count = 1)) then
- begin
- // Either files or directories must be selected and more than one.
- MsgWarning(rsMsgInvalidSelection);
- end
- else if FilesToCompare.Count > 0 then
- begin
- if gExternalTools[etDiffer].Enabled then
- RunExtDiffer(FilesToCompare)
- else if FilesToCompare.Count = 2 then
- ShowDiffer(FilesToCompare.Strings[0], FilesToCompare.Strings[1])
- else
- MsgWarning(rsMsgTooManyFilesSelected);
- end
- else if DirsToCompare.Count > 0 then
- begin
- if gExternalTools[etDiffer].Enabled then
- RunExtDiffer(DirsToCompare)
- else
- MsgWarning(rsMsgNotImplemented);
- end
- else
- msgWarning(rsMsgNoFilesSelected);
-
- finally
- FreeAndNil(FilesToCompare);
- FreeAndNil(DirsToCompare);
- end;
end;
end;
Index: src/ushowform.pas
===================================================================
--- src/ushowform.pas (revision 7907)
+++ src/ushowform.pas (working copy)
@@ -19,27 +19,57 @@
interface
uses
- Classes, DCBasicTypes, uFileSource, uFileSourceOperation;
+ Classes, DCBasicTypes, uFileSource, uFileSourceOperation, uFile,
+ uFileSourceCopyOperation;
type
+ { TWaitData }
+
+ TWaitData = class
+ public
+ procedure ShowWaitForm; virtual; abstract;
+ procedure Done; virtual; abstract;
+ end;
+
{ TEditorWaitData }
- TEditorWaitData = class
+ TEditorWaitData = class(TWaitData)
public
- FileName: String;
+ Files: TFiles;
+ function GetFileList: TStringList;
+ protected
+ FileTimes: array of TFileTime;
TargetPath: String;
- FileTime: TFileTime;
SourceFileSource: IFileSource;
TargetFileSource: IFileSource;
+ function GetRelativeFileName(const FullPath: string): string;
+ function GetRelativeFileNames: string;
+ function GetFromPath: string;
public
+ constructor Create(aCopyOutOperation: TFileSourceCopyOperation);
destructor Destroy; override;
+ procedure ShowWaitForm; override;
+ procedure Done; override;
protected
procedure OnCopyInStateChanged(Operation: TFileSourceOperation;
State: TFileSourceOperationState);
end;
-procedure EditDone(WaitData: TEditorWaitData);
+ TToolDataPreparedProc = procedure(const FileList: TStringList; WaitData: TWaitData);
+
+ TPrepareDataResult = (pdrFailed, pdrSynchronous, pdrAsynchronous);
+
+function PrepareData(FileSource: IFileSource; var SelectedFiles: TFiles;
+ FunctionToCall: TFileSourceOperationStateChangedNotify): TPrepareDataResult;
+
+procedure PrepareToolData(FileSource: IFileSource; var SelectedFiles: TFiles;
+ FunctionToCall: TToolDataPreparedProc); overload;
+
+procedure PrepareToolData(FileSource1: IFileSource; var SelectedFiles1: TFiles;
+ FileSource2: IFileSource; var SelectedFiles2: TFiles;
+ FunctionToCall: TToolDataPreparedProc); overload;
+
procedure RunExtDiffer(CompareList: TStringList);
procedure ShowEditorByGlob(const sFileName: String);
@@ -46,6 +76,7 @@
procedure ShowEditorByGlob(WaitData: TEditorWaitData); overload;
procedure ShowDifferByGlob(const LeftName, RightName: String);
+procedure ShowDifferByGlobList(const CompareList: TStringList; WaitData: TWaitData);
procedure ShowViewerByGlob(const sFileName: String);
procedure ShowViewerByGlobList(const FilesToView: TStringList;
@@ -57,12 +88,24 @@
SysUtils, Process, DCProcessUtf8, Dialogs, LCLIntf,
uShellExecute, uGlobs, uOSUtils, fEditor, fViewer, uDCUtils,
uTempFileSystemFileSource, uLng, fDiffer, uDebug, DCOSUtils, uShowMsg,
- uFile, uFileSourceCopyOperation, uFileSystemFileSource,
+ DCStrUtils, uFileSourceProperty,
uFileSourceOperationOptions, uOperationsManager, uFileSourceOperationTypes,
uMultiArchiveFileSource, fFileExecuteYourSelf;
type
+ { TWaitDataDouble }
+
+ TWaitDataDouble = class(TWaitData)
+ private
+ FWaitData1, FWaitData2: TEditorWaitData;
+ public
+ constructor Create(WaitData1: TEditorWaitData; WaitData2: TEditorWaitData);
+ procedure ShowWaitForm; override;
+ procedure Done; override;
+ destructor Destroy; override;
+ end;
+
{ TViewerWaitThread }
TViewerWaitThread = class(TThread)
@@ -76,11 +119,13 @@
destructor Destroy; override;
end;
- { TEditorWaitThread }
+ { TExtToolWaitThread }
- TEditorWaitThread = class(TThread)
+ TExtToolWaitThread = class(TThread)
private
- FWaitData: TEditorWaitData;
+ FExternalTool: TExternalTool;
+ FFileList: TStringList;
+ FWaitData: TWaitData;
private
procedure RunEditDone;
procedure ShowWaitForm;
@@ -87,7 +132,10 @@
protected
procedure Execute; override;
public
- constructor Create(WaitData: TEditorWaitData);
+ constructor Create(ExternalTool: TExternalTool;
+ const FileList: TStringList;
+ WaitData: TWaitData);
+ destructor Destroy; override;
end;
procedure RunExtTool(const ExtTool: TExternalToolOptions; sFileName: String);
@@ -147,11 +195,21 @@
end;
procedure ShowEditorByGlob(WaitData: TEditorWaitData);
+var
+ FileList: TStringList;
begin
if gExternalTools[etEditor].Enabled then
- with TEditorWaitThread.Create(WaitData) do Start
+ begin
+ FileList := TStringList.Create;
+ try
+ FileList.Add(WaitData.Files[0].FullPath);
+ with TExtToolWaitThread.Create(etEditor, FileList, WaitData) do Start;
+ finally
+ FileList.Free
+ end;
+ end
else begin
- ShowEditor(WaitData);
+ ShowEditor(WaitData.Files[0].FullPath, WaitData);
end;
end;
@@ -201,6 +259,19 @@
ShowDiffer(LeftName, RightName);
end;
+procedure ShowDifferByGlobList(const CompareList: TStringList; WaitData: TWaitData);
+begin
+ if gExternalTools[etDiffer].Enabled then
+ begin
+ if Assigned(WaitData) then
+ with TExtToolWaitThread.Create(etDiffer, CompareList, WaitData) do Start
+ else
+ RunExtDiffer(CompareList);
+ end
+ else
+ ShowDiffer(CompareList[0], CompareList[1], WaitData);
+end;
+
procedure ShowViewerByGlobList(const FilesToView : TStringList;
const aFileSource: IFileSource);
var
@@ -227,51 +298,147 @@
ShowViewer(FilesToView, aFileSource);
end;
-procedure EditDone(WaitData: TEditorWaitData);
+procedure TEditorWaitData.Done;
var
- Files: TFiles;
+ I: Integer;
Operation: TFileSourceCopyOperation;
+ DoNotFreeYet: Boolean = False;
begin
- with WaitData do
try
- // File was modified
- if mbFileAge(FileName) <> FileTime then
+ for I := Files.Count - 1 downto 0 do
+ if (mbFileAge(Files[I].FullPath) = FileTimes[I]) or
+ not msgYesNo(Format(rsMsgCopyBackward, [GetRelativeFileName(Files[I].FullPath)]) + LineEnding + LineEnding + GetFromPath) then
+ Files.Delete(I);
+
+ // Files were modified
+ if Files.Count > 0 then
begin
- if not msgYesNo(Format(rsMsgCopyBackward, [ExtractFileName(FileName)])) then Exit;
if (fsoCopyIn in TargetFileSource.GetOperationsTypes) and
(not (TargetFileSource is TMultiArchiveFileSource)) then
begin
- Files:= TFiles.Create(SourceFileSource.GetRootDir);
- Files.Add(TFileSystemFileSource.CreateFileFromFile(FileName));
Operation:= TargetFileSource.CreateCopyInOperation(SourceFileSource, Files, TargetPath) as TFileSourceCopyOperation;
- // Copy file back
+ // Copy files back
if Assigned(Operation) then
begin
Operation.AddStateChangedListener([fsosStopped], @OnCopyInStateChanged);
Operation.FileExistsOption:= fsoofeOverwrite;
OperationsManager.AddOperation(Operation);
- WaitData:= nil; // Will be free in operation
+ DoNotFreeYet:= True; // Will be free in operation
end;
end
- else if msgYesNo(rsMsgCouldNotCopyBackward + LineEnding + FileName) then
+ else if msgYesNo(rsMsgCouldNotCopyBackward + LineEnding + GetRelativeFileNames) then
begin
(SourceFileSource as ITempFileSystemFileSource).DeleteOnDestroy:= False;
end;
end;
finally
- WaitData.Free;
+ if not DoNotFreeYet then
+ Free;
end;
end;
+{ TWaitDataDouble }
+
+constructor TWaitDataDouble.Create(WaitData1: TEditorWaitData; WaitData2: TEditorWaitData);
+begin
+ FWaitData1 := WaitData1;
+ FWaitData2 := WaitData2;
+end;
+
+procedure TWaitDataDouble.ShowWaitForm;
+begin
+ try
+ FWaitData1.ShowWaitForm;
+ finally
+ FWaitData2.ShowWaitForm;
+ end;
+end;
+
+procedure TWaitDataDouble.Done;
+begin
+ try
+ if Assigned(FWaitData1) then
+ FWaitData1.Done;
+ finally
+ FWaitData1 := nil;
+ try
+ if Assigned(FWaitData2) then
+ FWaitData2.Done;
+ finally
+ FWaitData2 := nil;
+ Free;
+ end;
+ end;
+end;
+
+destructor TWaitDataDouble.Destroy;
+begin
+ inherited Destroy;
+ if Assigned(FWaitData1) then
+ FWaitData1.Free;
+ if Assigned(FWaitData2) then
+ FWaitData2.Free;
+end;
+
{ TEditorWaitData }
+constructor TEditorWaitData.Create(aCopyOutOperation: TFileSourceCopyOperation);
+var
+ I: Integer;
+ aFileSource: ITempFileSystemFileSource;
+begin
+ aFileSource := aCopyOutOperation.TargetFileSource as ITempFileSystemFileSource;
+ TargetPath := aCopyOutOperation.SourceFiles.Path;
+ Files := aCopyOutOperation.SourceFiles.Clone;
+ ChangeFileListRoot(aFileSource.FileSystemRoot, Files);
+ SetLength(FileTimes, Files.Count);
+ for I := 0 to Files.Count - 1 do
+ FileTimes[I] := mbFileAge(Files[I].FullPath);
+ SourceFileSource := aFileSource;
+ TargetFileSource := aCopyOutOperation.FileSource as IFileSource;
+end;
+
destructor TEditorWaitData.Destroy;
begin
inherited Destroy;
+ Files.Free;
SourceFileSource:= nil;
TargetFileSource:= nil;
end;
+function TEditorWaitData.GetRelativeFileName(const FullPath: string): string;
+begin
+ Result := ExtractDirLevel(IncludeTrailingPathDelimiter(Files.Path), FullPath);
+end;
+
+function TEditorWaitData.GetRelativeFileNames: string;
+var
+ I: Integer;
+begin
+ Result := GetRelativeFileName(Files[0].FullPath);
+ for I := 1 to Files.Count - 1 do
+ Result := Result + ', ' + GetRelativeFileName(Files[I].FullPath);
+end;
+
+function TEditorWaitData.GetFromPath: string;
+begin
+ Result := TargetFileSource.CurrentAddress + TargetPath;
+end;
+
+procedure TEditorWaitData.ShowWaitForm;
+begin
+ ShowFileEditExternal(GetRelativeFileNames, GetFromPath, Self);
+end;
+
+function TEditorWaitData.GetFileList: TStringList;
+var
+ I: Integer;
+begin
+ Result := TStringList.Create;
+ for I := 0 to Files.Count - 1 do
+ Result.Add(Files[I].FullPath);
+end;
+
procedure TEditorWaitData.OnCopyInStateChanged(Operation: TFileSourceOperation;
State: TFileSourceOperationState);
var
@@ -296,27 +463,29 @@
end;
end;
-{ TEditorWaitThread }
+{ TExtToolWaitThread }
-procedure TEditorWaitThread.RunEditDone;
+procedure TExtToolWaitThread.RunEditDone;
begin
- EditDone(FWaitData);
+ FWaitData.Done;
end;
-procedure TEditorWaitThread.ShowWaitForm;
+procedure TExtToolWaitThread.ShowWaitForm;
begin
- ShowFileEditExternal(FWaitData);
+ FWaitData.ShowWaitForm;
end;
-procedure TEditorWaitThread.Execute;
+procedure TExtToolWaitThread.Execute;
var
+ I: Integer;
StartTime: QWord;
Process : TProcessUTF8;
sCmd, sSecureEmptyStr: String;
begin
+ try
Process := TProcessUTF8.Create(nil);
-
- with gExternalTools[etEditor] do
+ try
+ with gExternalTools[FExternalTool] do
begin
sCmd := ReplaceEnvVars(Path);
// TProcess arguments must be enclosed with double quotes and not escaped.
@@ -325,7 +494,8 @@
sCmd := QuoteStr(sCmd);
if Parameters <> EmptyStr then
sCmd := sCmd + ' ' + Parameters;
- sCmd := sCmd + ' ' + QuoteStr(FWaitData.FileName);
+ for I := 0 to FFileList.Count - 1 do
+ sCmd := sCmd + ' ' + QuoteStr(FFileList[I]);
sSecureEmptyStr := EmptyStr; // Let's play safe and don't let EmptyStr being passed as "VAR" parameter of "FormatTerminal"
FormatTerminal(sCmd, sSecureEmptyStr, False);
end
@@ -334,7 +504,8 @@
sCmd := '"' + sCmd + '"';
if Parameters <> EmptyStr then
sCmd := sCmd + ' ' + Parameters;
- sCmd := sCmd + ' "' + FWaitData.FileName + '"';
+ for I := 0 to FFileList.Count - 1 do
+ sCmd := sCmd + ' "' + FFileList[I] + '"';
end;
end;
@@ -342,7 +513,6 @@
Process.Options := [poWaitOnExit];
StartTime:= GetTickCount64;
Process.Execute;
- Process.Free;
// If an editor closes within gEditWaitTime amount of milliseconds,
// assume that it's a multiple document editor and show dialog where
@@ -354,17 +524,38 @@
else begin
Synchronize(@RunEditDone);
end;
+
+ finally
+ Process.Free;
+ end;
+ except
+ FWaitData.Free;
+ end;
end;
-constructor TEditorWaitThread.Create(WaitData: TEditorWaitData);
+constructor TExtToolWaitThread.Create(ExternalTool: TExternalTool;
+ const FileList: TStringList;
+ WaitData: TWaitData);
begin
inherited Create(True);
FreeOnTerminate := True;
+ FExternalTool := ExternalTool;
+
+ FFileList := TStringList.Create;
+ // Make a copy of list elements.
+ FFileList.Assign(FileList);
+
FWaitData := WaitData;
end;
+destructor TExtToolWaitThread.Destroy;
+begin
+ FFileList.Free;
+ inherited Destroy;
+end;
+
{ TViewerWaitThread }
constructor TViewerWaitThread.Create(const FilesToView: TStringList; const aFileSource: IFileSource);
@@ -425,4 +616,306 @@
Process.Free;
end;
+{ PrepareData }
+
+function PrepareData(FileSource: IFileSource; var SelectedFiles: TFiles;
+ FunctionToCall: TFileSourceOperationStateChangedNotify): TPrepareDataResult;
+var
+ aFile: TFile;
+ I: Integer;
+ TempFiles: TFiles = nil;
+ TempFileSource: ITempFileSystemFileSource = nil;
+ Operation: TFileSourceOperation;
+begin
+ // If files are links to local files
+ if (fspLinksToLocalFiles in FileSource.Properties) then
+ begin
+ for I := 0 to SelectedFiles.Count - 1 do
+ begin
+ aFile := SelectedFiles[I];
+ FileSource.GetLocalName(aFile);
+ end;
+ end
+ // If files not directly accessible copy them to temp file source.
+ else if not (fspDirectAccess in FileSource.Properties) then
+ begin
+ if not (fsoCopyOut in FileSource.GetOperationsTypes) then
+ begin
+ msgWarning(rsMsgErrNotSupported);
+ Exit(pdrFailed);
+ end;
+
+ TempFileSource := TTempFileSystemFileSource.GetFileSource;
+
+ TempFiles := SelectedFiles.Clone;
+ try
+ Operation := FileSource.CreateCopyOutOperation(
+ TempFileSource,
+ TempFiles,
+ TempFileSource.FileSystemRoot);
+ finally
+ TempFiles.Free;
+ end;
+
+ if not Assigned(Operation) then
+ begin
+ msgWarning(rsMsgErrNotSupported);
+ Exit(pdrFailed);
+ end;
+
+ Operation.AddStateChangedListener([fsosStopped], FunctionToCall);
+
+ OperationsManager.AddOperation(Operation);
+
+ Exit(pdrAsynchronous);
+ end;
+ Exit(pdrSynchronous);
+end;
+
+{ TToolDataPreparator }
+
+type
+ TToolDataPreparator = class
+ protected
+ FFunc: TToolDataPreparedProc;
+ FCallOnFail: Boolean;
+ procedure OnCopyOutStateChanged(Operation: TFileSourceOperation;
+ State: TFileSourceOperationState);
+ public
+ constructor Create(FunctionToCall: TToolDataPreparedProc; CallOnFail: Boolean = False);
+ procedure Prepare(FileSource: IFileSource; var SelectedFiles: TFiles);
+ end;
+
+constructor TToolDataPreparator.Create(FunctionToCall: TToolDataPreparedProc; CallOnFail: Boolean = False);
+begin
+ FFunc := FunctionToCall;
+ FCallOnFail := CallOnFail;
+end;
+
+procedure TToolDataPreparator.Prepare(FileSource: IFileSource; var SelectedFiles: TFiles);
+var
+ I: Integer;
+ FileList: TStringList;
+begin
+ case PrepareData(FileSource, SelectedFiles, @OnCopyOutStateChanged) of
+ pdrSynchronous:
+ try
+ FileList := TStringList.Create;
+ for I := 0 to SelectedFiles.Count - 1 do
+ FileList.Add(SelectedFiles[i].FullPath);
+ FFunc(FileList, nil);
+ finally
+ Free;
+ end;
+ pdrFailed:
+ try
+ if FCallOnFail then
+ FFunc(nil, nil);
+ finally
+ Free;
+ end;
+ end;
+end;
+
+procedure TToolDataPreparator.OnCopyOutStateChanged(
+ Operation: TFileSourceOperation; State: TFileSourceOperationState);
+var WaitData: TEditorWaitData;
+begin
+ if (State <> fsosStopped) then
+ Exit;
+ try
+ if Operation.Result = fsorFinished then
+ begin
+ WaitData := TEditorWaitData.Create(Operation as TFileSourceCopyOperation);
+ FFunc(WaitData.GetFileList, WaitData);
+ end
+ else
+ begin
+ if FCallOnFail then
+ FFunc(nil, nil);
+ end;
+ finally
+ Free;
+ end;
+end;
+
+{ TToolDataPreparator2 }
+
+type
+ TToolDataPreparator2 = class
+ protected
+ FFunc: TToolDataPreparedProc;
+ FCallOnFail: Boolean;
+ FFailed: Boolean;
+ FFileList1: TStringList;
+ FFileList2: TStringList;
+ FPrepared1: Boolean;
+ FPrepared2: Boolean;
+ FWaitData1: TEditorWaitData;
+ FWaitData2: TEditorWaitData;
+ procedure OnCopyOutStateChanged1(Operation: TFileSourceOperation;
+ State: TFileSourceOperationState);
+ procedure OnCopyOutStateChanged2(Operation: TFileSourceOperation;
+ State: TFileSourceOperationState);
+ procedure TryFinish;
+ public
+ constructor Create(FunctionToCall: TToolDataPreparedProc; CallOnFail: Boolean = False);
+ procedure Prepare(FileSource1: IFileSource; var SelectedFiles1: TFiles;
+ FileSource2: IFileSource; var SelectedFiles2: TFiles);
+ destructor Destroy; override;
+ end;
+
+constructor TToolDataPreparator2.Create(FunctionToCall: TToolDataPreparedProc; CallOnFail: Boolean = False);
+begin
+ FFunc := FunctionToCall;
+ FCallOnFail := CallOnFail;
+end;
+
+procedure TToolDataPreparator2.Prepare(FileSource1: IFileSource; var SelectedFiles1: TFiles;
+ FileSource2: IFileSource; var SelectedFiles2: TFiles);
+var
+ I: Integer;
+begin
+ case PrepareData(FileSource1, SelectedFiles1, @OnCopyOutStateChanged1) of
+ pdrSynchronous:
+ begin
+ FFileList1 := TStringList.Create;
+ for I := 0 to SelectedFiles1.Count - 1 do
+ FFileList1.Add(SelectedFiles1[I].FullPath);
+ FPrepared1 := True;
+ end;
+ pdrFailed:
+ begin
+ try
+ if FCallOnFail then
+ FFunc(nil, nil);
+ finally
+ Free;
+ end;
+ Exit;
+ end;
+ end;
+
+ case PrepareData(FileSource2, SelectedFiles2, @OnCopyOutStateChanged2) of
+ pdrSynchronous:
+ begin
+ FFileList2 := TStringList.Create;
+ for I := 0 to SelectedFiles2.Count - 1 do
+ FFileList2.Add(SelectedFiles2[I].FullPath);
+ FPrepared2 := True;
+ end;
+ pdrFailed:
+ begin
+ FPrepared2 := True;
+ FFailed := True;
+ end;
+ end;
+
+ TryFinish;
+end;
+
+procedure TToolDataPreparator2.OnCopyOutStateChanged1(
+ Operation: TFileSourceOperation; State: TFileSourceOperationState);
+begin
+ if (State <> fsosStopped) then
+ Exit;
+ FPrepared1 := True;
+ if not FFailed then
+ begin
+ if Operation.Result = fsorFinished then
+ begin
+ FWaitData1 := TEditorWaitData.Create(Operation as TFileSourceCopyOperation);
+ FFileList1 := FWaitData1.GetFileList;
+ end
+ else
+ begin
+ FFailed := True;
+// if not FPrepared2 and Assigned(FOperation2) then
+// FOperation2.Stop();
+ end;
+ end;
+ TryFinish;
+end;
+
+procedure TToolDataPreparator2.OnCopyOutStateChanged2(
+ Operation: TFileSourceOperation; State: TFileSourceOperationState);
+begin
+ if (State <> fsosStopped) then
+ Exit;
+ FPrepared2 := True;
+ if not FFailed then
+ begin
+ if Operation.Result = fsorFinished then
+ begin
+ FWaitData2 := TEditorWaitData.Create(Operation as TFileSourceCopyOperation);
+ FFileList2 := FWaitData2.GetFileList;
+ end
+ else
+ begin
+ FFailed := True;
+// if not FPrepared1 and Assigned(FOperation1) then
+// FOperation1.Stop();
+ end;
+ end;
+ TryFinish;
+end;
+
+procedure TToolDataPreparator2.TryFinish;
+var
+ s: string;
+ WaitData: TWaitDataDouble;
+begin
+ if FPrepared1 and FPrepared2 then
+ try
+ if FFailed then
+ begin
+ if FCallOnFail then
+ FFunc(nil, nil);
+ Exit;
+ end;
+ if Assigned(FFileList2) then
+ for s in FFileList2 do
+ FFileList1.Append(s);
+ if Assigned(FWaitData1) or Assigned(FWaitData2) then
+ begin
+ WaitData := TWaitDataDouble.Create(FWaitData1, FWaitData2);
+ FWaitData1 := nil;
+ FWaitData2 := nil;
+ FFunc(FFileList1, WaitData);
+ end
+ else
+ FFunc(FFileList1, nil);
+ finally
+ Free;
+ end;
+end;
+
+destructor TToolDataPreparator2.Destroy;
+begin
+ inherited Destroy;
+ if Assigned(FFileList1) then
+ FFileList1.Free;
+ if Assigned(FFileList2) then
+ FFileList2.Free;
+ if Assigned(FWaitData1) then
+ FWaitData1.Free;
+ if Assigned(FWaitData2) then
+ FWaitData2.Free;
+end;
+
+procedure PrepareToolData(FileSource: IFileSource; var SelectedFiles: TFiles;
+ FunctionToCall: TToolDataPreparedProc);
+begin
+ with TToolDataPreparator.Create(FunctionToCall) do
+ Prepare(FileSource, SelectedFiles);
+end;
+
+procedure PrepareToolData(FileSource1: IFileSource; var SelectedFiles1: TFiles;
+ FileSource2: IFileSource; var SelectedFiles2: TFiles;
+ FunctionToCall: TToolDataPreparedProc);
+begin
+ with TToolDataPreparator2.Create(FunctionToCall) do
+ Prepare(FileSource1, SelectedFiles1, FileSource2, SelectedFiles2);
+end;
+
end.
| ||||
| Fixed in Revision | 7834,7935 | ||||
| Operating system | Windows, Linux | ||||
| Widgetset | |||||
| Architecture | 64-bit | ||||
|
|
To compare files from search result no extra code is needed, just rewrite condition to allow it. |
|
|
In this case is better to check "fspDirectAccess" property. Done (revision 7834). |
|
|
Patch for supporting archives and other indirect filesystems, such as FTP. The code to handle such cases was taken from the viewer and editor openers, but the inability to wait for two operations required either additional variables and complex logic directly in the TMainCommands class or creating a separate class for files preparation, which I did. Apart from implementing the feature, the effort resulted in complex refactoring, its goal was to unify files preparation for viewer, editor and differ. This part was not fully met, but the foundations are laid. |
|
|
Also I intentionally did not make some changes for the purpose of patch readability: - Almost all of the cm_CompareContents procedure should be indented by two spaces less. - TEditorWaitData.Done (former EditDone) should be moved to the place of other class members. - TExtToolWaitThread.Execute (former TEditorWaitThread) could be indented more to take into account two try clauses that it is now wrapped in. |
|
|
I've done the corrections mentioned in the previous note, refactored the main procedure a bit to reduce nesting, changed some messages, added support for launching it from directory synchronization tool, and commited. |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2017-10-06 17:39 | CryHam | New Issue | |
| 2017-10-07 02:06 | accorp | Note Added: 0002370 | |
| 2017-10-07 02:06 | accorp | File Added: compare-search-result.diff | |
| 2017-10-08 12:02 | Alexx2000 | Fixed in Revision | => 7834 |
| 2017-10-08 12:02 | Alexx2000 | Note Added: 0002371 | |
| 2017-10-08 12:02 | Alexx2000 | Status | new => acknowledged |
| 2017-12-17 01:15 | cordylus | File Added: bug1927.patch | |
| 2017-12-17 01:53 | cordylus | Note Added: 0002429 | |
| 2017-12-17 02:29 | cordylus | Note Added: 0002430 | |
| 2017-12-17 02:31 | cordylus | Note Edited: 0002430 | |
| 2017-12-17 03:17 | cordylus | Note Edited: 0002430 | |
| 2017-12-17 03:19 | cordylus | Note Edited: 0002430 | |
| 2017-12-20 19:55 | cordylus | Note Added: 0002442 | |
| 2017-12-20 19:56 | cordylus | Fixed in Revision | 7834 => 7834,7935 |
| 2017-12-20 19:56 | cordylus | Assigned To | => cordylus |
| 2017-12-20 19:56 | cordylus | Status | acknowledged => resolved |
| 2020-11-30 07:44 | Alexx2000 | Status | resolved => closed |