doublecmd/src/fdiffer.pas

1522 lines
45 KiB
ObjectPascal

{
Double Commander
-------------------------------------------------------------------------
Internal diff and merge tool
Copyright (C) 2010-2021 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, see <http://www.gnu.org/licenses/>.
}
unit fDiffer;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Dialogs, Menus, ComCtrls,
ActnList, ExtCtrls, EditBtn, Buttons, SynEdit, uSynDiffControls,
uPariterControls, uDiffOND, uFormCommands, uHotkeyManager, uOSForms,
uBinaryDiffViewer, uShowForm, KASStatusBar, Graphics, StdCtrls;
type
{ TStatusBar }
TStatusBar = class(TKASStatusBar);
{ TfrmDiffer }
TfrmDiffer = class(TAloneForm, IFormCommands)
actBinaryCompare: TAction;
actCopyLeftToRight: TAction;
actCopyRightToLeft: TAction;
actExit: TAction;
actEditCut: TAction;
actEditCopy: TAction;
actEditDelete: TAction;
actEditUndo: TAction;
actEditRedo: TAction;
actEditSelectAll: TAction;
actEditPaste: TAction;
actAbout: TAction;
actAutoCompare: TAction;
actLineDifferences: TAction;
actSaveRightAs: TAction;
actSaveLeftAs: TAction;
actOpenRight: TAction;
actOpenLeft: TAction;
actReload: TAction;
actSaveRight: TAction;
actSaveLeft: TAction;
actPaintBackground: TAction;
actStartCompare: TAction;
actFirstDifference: TAction;
actIgnoreCase: TAction;
actIgnoreWhiteSpace: TAction;
actCancelCompare: TAction;
actKeepScrolling: TAction;
actPrevDifference: TAction;
actLastDifference: TAction;
actNextDifference: TAction;
actSaveAs: TAction;
actSave: TAction;
ActionList: TActionList;
edtFileNameLeft: TFileNameEdit;
edtFileNameRight: TFileNameEdit;
MainMenu: TMainMenu;
miAutoCompare: TMenuItem;
miDivider10: TMenuItem;
miLineDifferences: TMenuItem;
miEncodingRight: TMenuItem;
miEncodingLeft: TMenuItem;
miAbout: TMenuItem;
mnuEncoding: TMenuItem;
miSaveRightAs: TMenuItem;
miSaveLeftAs: TMenuItem;
miCopyContext: TMenuItem;
miCutContext: TMenuItem;
miDeleteContext: TMenuItem;
miEditSelectAll: TMenuItem;
miDivider9: TMenuItem;
miEditDelete: TMenuItem;
miEditPaste: TMenuItem;
miEditCopy: TMenuItem;
miEditCut: TMenuItem;
miDivider8: TMenuItem;
miEditRedo: TMenuItem;
miEditUndo: TMenuItem;
miDivider7: TMenuItem;
miPasteContext: TMenuItem;
miReload: TMenuItem;
miDivider6: TMenuItem;
miExit: TMenuItem;
miSaveRight: TMenuItem;
miOpenRight: TMenuItem;
miOpenLeft: TMenuItem;
miCopyRightToLeft: TMenuItem;
miCopyLeftToRight: TMenuItem;
miDivider5: TMenuItem;
miPaintBackground: TMenuItem;
miDivider4: TMenuItem;
miBinaryCompare: TMenuItem;
miKeepScrolling: TMenuItem;
miDivider3: TMenuItem;
miLastDiff: TMenuItem;
miFirstDiff: TMenuItem;
miDivider2: TMenuItem;
miPrevDiff: TMenuItem;
miNextDiff: TMenuItem;
miDivider1: TMenuItem;
miCancelCompare: TMenuItem;
miSelectAllContext: TMenuItem;
miSeparator1: TMenuItem;
miSeparator2: TMenuItem;
miStartCompare: TMenuItem;
miUndoContext: TMenuItem;
mnuActions: TMenuItem;
miIgnoreCase: TMenuItem;
miIgnoreWhiteSpace: TMenuItem;
mnuOptions: TMenuItem;
mnuEdit: TMenuItem;
miSaveLeft: TMenuItem;
mnuFile: TMenuItem;
ContextMenu: TPopupMenu;
pnlLeftBox: TPanel;
pnlRight: TPanel;
pnlLeft: TPanel;
pnlRightBox: TPanel;
btnLeftEncoding: TSpeedButton;
btnRightEncoding: TSpeedButton;
btnLeftSave: TSpeedButton;
btnLeftSaveAs: TSpeedButton;
btnRightSave: TSpeedButton;
btnRightSaveAs: TSpeedButton;
pmEncodingLeft: TPopupMenu;
pmEncodingRight: TPopupMenu;
Splitter: TSplitter;
StatusBar: TStatusBar;
tmProgress: TTimer;
ToolBar: TToolBar;
btnSave: TToolButton;
btnSaveAs: TToolButton;
Divider1: TToolButton;
btnCompare: TToolButton;
btnLast: TToolButton;
btnNext: TToolButton;
btnPrev: TToolButton;
btnFirst: TToolButton;
Divider2: TToolButton;
Divider3: TToolButton;
btnCancelCompare: TToolButton;
Divider4: TToolButton;
btnReload: TToolButton;
btnCopyRightToLeft: TToolButton;
btnCopyLeftToRight: TToolButton;
Divider5: TToolButton;
btnEditUndo: TToolButton;
btnEditRedo: TToolButton;
procedure actAboutExecute(Sender: TObject);
procedure actBinaryCompareExecute(Sender: TObject);
procedure actCancelCompareExecute(Sender: TObject);
procedure actExecute(Sender: TObject);
procedure actEditCopyExecute(Sender: TObject);
procedure actEditCutExecute(Sender: TObject);
procedure actEditDeleteExecute(Sender: TObject);
procedure actEditPasteExecute(Sender: TObject);
procedure actEditRedoExecute(Sender: TObject);
procedure actEditSelectAllExecute(Sender: TObject);
procedure actEditUndoExecute(Sender: TObject);
procedure actIgnoreCaseExecute(Sender: TObject);
procedure actLineDifferencesExecute(Sender: TObject);
procedure actOpenLeftExecute(Sender: TObject);
procedure actOpenRightExecute(Sender: TObject);
procedure actPaintBackgroundExecute(Sender: TObject);
procedure actSaveAsExecute(Sender: TObject);
procedure actSaveExecute(Sender: TObject);
procedure actSaveLeftAsExecute(Sender: TObject);
procedure actSaveRightAsExecute(Sender: TObject);
procedure actStartCompareExecute(Sender: TObject);
procedure actKeepScrollingExecute(Sender: TObject);
procedure btnLeftEncodingClick(Sender: TObject);
procedure btnRightEncodingClick(Sender: TObject);
procedure edtFileNameLeftAcceptFileName(Sender: TObject; var Value: String);
procedure edtFileNameRightAcceptFileName(Sender: TObject; var Value: String);
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure FormResize(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure tmProgressTimer(Sender: TObject);
private
BinaryDiffList: TFPList;
BinaryDiffIndex: Integer;
BinaryCompare: TBinaryCompare;
BinaryViewerLeft,
BinaryViewerRight: TBinaryDiffViewer;
procedure BinaryCompareFinish;
private
Diff: TDiff;
SynDiffEditActive: TSynDiffEdit;
SynDiffEditLeft: TSynDiffEdit;
SynDiffEditRight: TSynDiffEdit;
SynDiffHighlighterLeft,
SynDiffHighlighterRight: TSynDiffHighlighter;
HashListLeft,
HashListRight: array of Integer;
EncodingList: TStringList;
ScrollLock: LongInt;
FShowIdentical: Boolean;
FModal: Boolean;
FCancel: Boolean;
frmProgress: TForm;
FWaitData: TWaitData;
FElevate: TDuplicates;
FCommands: TFormCommands;
private
procedure ShowDialog;
procedure ShowIdentical;
procedure ShowProgressDialog;
procedure CloseProgressDialog;
procedure Clear(bLeft, bRight: Boolean);
procedure BuildHashList(bLeft, bRight: Boolean);
procedure ChooseEncoding(SynDiffEdit: TSynDiffEdit);
procedure SetColors(cAdded, cDeleted, cModified: TColor);
procedure ChooseEncoding(MenuItem: TMenuItem; Encoding: String);
procedure FillEncodingMenu(TheOwner: TMenuItem; MenuHandler: TNotifyEvent; GroupIndex: LongInt);
procedure LoadFromFile(SynDiffEdit: TSynDiffEdit; const FileName: String);
procedure SaveToFile(SynDiffEdit: TSynDiffEdit; const FileName: String);
procedure OpenFileLeft(const FileName: String);
procedure OpenFileRight(const FileName: String);
procedure SetEncodingLeft(Sender: TObject);
procedure SetEncodingRight(Sender: TObject);
procedure SynDiffEditEnter(Sender: TObject);
procedure ShowFirstDifference(Data: PtrInt);
procedure SynDiffEditLeftStatusChange(Sender: TObject; Changes: TSynStatusChanges);
procedure SynDiffEditRightStatusChange(Sender: TObject; Changes: TSynStatusChanges);
property Commands: TFormCommands read FCommands implements IFormCommands;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure AfterConstruction; override;
published
procedure cm_CopyLeftToRight(const Params: array of string);
procedure cm_CopyRightToLeft(const Params: array of string);
procedure cm_Exit(const Params: array of string);
procedure cm_FirstDifference(const Params: array of string);
procedure cm_LastDifference(const Params: array of string);
procedure cm_NextDifference(const Params: array of string);
procedure cm_PrevDifference(const Params: array of string);
procedure cm_Reload(const Params: array of string);
procedure cm_SaveLeft(const Params: array of string);
procedure cm_SaveRight(const Params: array of string);
end;
procedure ShowDiffer(const FileNameLeft, FileNameRight: String; WaitData: TWaitData = nil; Modal: Boolean = False);
implementation
{$R *.lfm}
uses
Math, LCLType, LazFileUtils, LConvEncoding, SynEditTypes, uHash, uLng, uGlobs,
uShowMsg, DCClassesUtf8, dmCommonData, uDCUtils, uConvEncoding, uAdministrator;
const
HotkeysCategory = 'Differ';
procedure ShowDiffer(const FileNameLeft, FileNameRight: String; WaitData: TWaitData = nil; Modal: Boolean = False);
var
Differ: TfrmDiffer;
begin
Differ := TfrmDiffer.Create(Application);
with Differ do
begin
FModal := Modal;
FWaitData := WaitData;
FShowIdentical := True;
edtFileNameLeft.Text:= FileNameLeft;
edtFileNameRight.Text:= FileNameRight;
SetColors(gDifferAddedColor, gDifferDeletedColor, gDifferModifiedColor);
try
if not (FileIsText(FileNameLeft) and FileIsText(FileNameRight)) then
actBinaryCompare.Execute
else begin
OpenFileLeft(FileNameLeft);
OpenFileRight(FileNameRight);
actStartCompare.Execute;
end;
except
on E: Exception do
begin
tmProgress.Enabled:= False;
msgError(E.Message);
Free;
end;
end;
end;
end;
{ TfrmDiffer }
procedure TfrmDiffer.actStartCompareExecute(Sender: TObject);
var
I: Integer;
LineNumberLeft,
LineNumberRight: PtrInt;
begin
FCancel:= False;
try
if actBinaryCompare.Checked then
begin
if (BinaryViewerLeft.IsFileOpen and BinaryViewerRight.IsFileOpen) then
begin
actStartCompare.Enabled := False;
actCancelCompare.Enabled := True;
actBinaryCompare.Enabled := False;
BinaryCompare:= TBinaryCompare.Create(BinaryViewerLeft.GetDataAdr,
BinaryViewerRight.GetDataAdr,
BinaryViewerLeft.FileSize,
BinaryViewerRight.FileSize,
BinaryDiffList);
BinaryCompare.OnFinish:= @BinaryCompareFinish;
BinaryCompare.Start;
end;
end
else try
Inc(ScrollLock);
Screen.Cursor := crHourGlass;
if SynDiffEditLeft.Modified then SynDiffEditLeft.Lines.RemoveFake;
if SynDiffEditRight.Modified then SynDiffEditRight.Lines.RemoveFake;
BuildHashList(SynDiffEditLeft.Modified, SynDiffEditRight.Modified);
if (Length(HashListLeft) = 0) or (Length(HashListRight) = 0) then
begin
FCancel := True;
Exit;
end;
actStartCompare.Enabled := False;
actCancelCompare.Enabled := True;
Diff.Execute(
PInteger(@HashListLeft[0]),
PInteger(@HashListRight[0]),
Length(HashListLeft),
Length(HashListRight)
);
tmProgress.Enabled:= False;
if Diff.Cancelled then Exit;
SynDiffEditLeft.StartCompare;
SynDiffEditRight.StartCompare;
for I := 0 to Diff.Count - 1 do
with Diff.Compares[I] do
begin
LineNumberLeft:= oldIndex1 + 1;
LineNumberRight:= oldIndex2 + 1;
case Kind of
ckAdd:
begin
SynDiffEditLeft.Lines.InsertFake(I, Kind);
SynDiffEditRight.Lines.SetKindAndNumber(I, Kind, LineNumberRight);
end;
ckDelete:
begin
SynDiffEditLeft.Lines.SetKindAndNumber(I, Kind, LineNumberLeft);
SynDiffEditRight.Lines.InsertFake(I, Kind);
end;
else
begin
SynDiffEditLeft.Lines.SetKindAndNumber(I, Kind, LineNumberLeft);
SynDiffEditRight.Lines.SetKindAndNumber(I, Kind, LineNumberRight);
end;
end;
end;
with Diff.DiffStats do
begin
StatusBar.Panels[0].Text := rsDiffMatches + IntToStr(matches);
StatusBar.Panels[1].Text := rsDiffModifies + IntToStr(modifies);
StatusBar.Panels[2].Text := rsDiffAdds + IntToStr(adds);
StatusBar.Panels[3].Text := rsDiffDeletes + IntToStr(deletes);
if FShowIdentical then
begin
CloseProgressDialog;
FShowIdentical:= (modifies = 0) and (adds = 0) and (deletes = 0);
if FShowIdentical then
ShowIdentical
else begin
FShowIdentical:= False;
Application.QueueAsyncCall(@ShowFirstDifference, 0);
ShowDialog;
end;
end;
end;
finally
SynDiffEditLeft.FinishCompare;
SynDiffEditRight.FinishCompare;
Screen.Cursor := crDefault;
actStartCompare.Enabled := True;
actCancelCompare.Enabled := False;
Dec(ScrollLock);
end;
if actLineDifferences.Checked then
begin
SynDiffEditLeft.Highlighter:= SynDiffHighlighterLeft;
SynDiffEditRight.Highlighter:= SynDiffHighlighterRight;
end;
finally
if FShowIdentical and FCancel then Free;
end;
end;
procedure TfrmDiffer.actOpenLeftExecute(Sender: TObject);
begin
dmComData.OpenDialog.FileName:= edtFileNameLeft.Text;
dmComData.OpenDialog.Filter:= AllFilesMask;
if dmComData.OpenDialog.Execute then
begin
edtFileNameLeft.Text:= dmComData.OpenDialog.FileName;
actReload.Execute;
end;
end;
procedure TfrmDiffer.actOpenRightExecute(Sender: TObject);
begin
dmComData.OpenDialog.FileName:= edtFileNameRight.Text;
dmComData.OpenDialog.Filter:= AllFilesMask;
if dmComData.OpenDialog.Execute then
begin
edtFileNameRight.Text:= dmComData.OpenDialog.FileName;
actReload.Execute;
end;
end;
procedure TfrmDiffer.actPaintBackgroundExecute(Sender: TObject);
begin
if actPaintBackground.Checked then
begin
SynDiffEditLeft.PaintStyle:= psBackground;
SynDiffEditRight.PaintStyle:= psBackground;
end
else
begin
SynDiffEditLeft.PaintStyle:= psForeground;
SynDiffEditRight.PaintStyle:= psForeground;
end;
SynDiffHighlighterLeft.UpdateColors;
SynDiffHighlighterRight.UpdateColors;
end;
procedure TfrmDiffer.actSaveAsExecute(Sender: TObject);
begin
if SynDiffEditActive = SynDiffEditLeft then
actSaveLeftAs.Execute
else if SynDiffEditActive = SynDiffEditRight then
actSaveRightAs.Execute;
end;
procedure TfrmDiffer.actSaveExecute(Sender: TObject);
begin
if SynDiffEditActive = SynDiffEditLeft then
actSaveLeft.Execute
else if SynDiffEditActive = SynDiffEditRight then
actSaveRight.Execute;
end;
procedure TfrmDiffer.actSaveLeftAsExecute(Sender: TObject);
begin
dmComData.SaveDialog.FileName:= edtFileNameLeft.FileName;
if dmComData.SaveDialog.Execute then
begin
PushPop(FElevate);
try
SaveToFile(SynDiffEditLeft, dmComData.SaveDialog.FileName);
finally
PushPop(FElevate);
end;
edtFileNameLeft.FileName:= dmComData.SaveDialog.FileName;
end;
end;
procedure TfrmDiffer.actSaveRightAsExecute(Sender: TObject);
begin
dmComData.SaveDialog.FileName:= edtFileNameRight.FileName;
if dmComData.SaveDialog.Execute then
begin
PushPop(FElevate);
try
SaveToFile(SynDiffEditRight, dmComData.SaveDialog.FileName);
finally
PushPop(FElevate);
end;
edtFileNameRight.FileName:= dmComData.SaveDialog.FileName;
end;
end;
procedure TfrmDiffer.actBinaryCompareExecute(Sender: TObject);
begin
mnuEdit.Enabled:= not actBinaryCompare.Checked;
mnuEncoding.Enabled:= not actBinaryCompare.Checked;
btnLeftEncoding.Enabled:= not actBinaryCompare.Checked;
btnRightEncoding.Enabled:= not actBinaryCompare.Checked;
actCopyLeftToRight.Enabled:= not actBinaryCompare.Checked;
actCopyRightToLeft.Enabled:= not actBinaryCompare.Checked;
actEditUndo.Enabled:= not actBinaryCompare.Checked;
actEditRedo.Enabled:= not actBinaryCompare.Checked;
actSave.Enabled:= not actBinaryCompare.Checked;
actSaveAs.Enabled:= not actBinaryCompare.Checked;
actSaveLeft.Enabled:= not actBinaryCompare.Checked;
actSaveLeftAs.Enabled:= not actBinaryCompare.Checked;
actSaveRight.Enabled:= not actBinaryCompare.Checked;
actSaveRightAs.Enabled:= not actBinaryCompare.Checked;
actIgnoreCase.Enabled:= not actBinaryCompare.Checked;
actIgnoreWhiteSpace.Enabled:= not actBinaryCompare.Checked;
actPaintBackground.Enabled:= not actBinaryCompare.Checked;
actLineDifferences.Enabled:= not actBinaryCompare.Checked;
SynDiffEditLeft.Visible:= not actBinaryCompare.Checked;
SynDiffEditRight.Visible:= not actBinaryCompare.Checked;
BinaryViewerLeft.Visible:= actBinaryCompare.Checked;
BinaryViewerRight.Visible:= actBinaryCompare.Checked;
if actBinaryCompare.Checked then
begin
PushPop(FElevate);
try
BinaryDiffList.Clear;
BinaryViewerLeft.FileName:= edtFileNameLeft.Text;
BinaryViewerRight.FileName:= edtFileNameRight.Text;
finally
PushPop(FElevate);
end;
if FShowIdentical then
begin
if not BinaryViewerLeft.IsFileOpen then
raise EFOpenError.Create(BinaryViewerLeft.LastError + LineEnding + edtFileNameLeft.Text);
if not BinaryViewerRight.IsFileOpen then
raise EFOpenError.Create(BinaryViewerRight.LastError + LineEnding + edtFileNameRight.Text);
end;
StatusBar.Panels[0].Text := EmptyStr;
StatusBar.Panels[1].Text := EmptyStr;
StatusBar.Panels[2].Text := EmptyStr;
StatusBar.Panels[3].Text := EmptyStr;
end
else
begin
BinaryViewerLeft.FileName:= EmptyStr;
BinaryViewerRight.FileName:= EmptyStr;
OpenFileLeft(edtFileNameLeft.Text);
OpenFileRight(edtFileNameRight.Text);
end;
actStartCompare.Execute;
end;
procedure TfrmDiffer.actCancelCompareExecute(Sender: TObject);
begin
if not actBinaryCompare.Checked then
Diff.Cancel
else begin
if Assigned(BinaryCompare) then
begin
BinaryCompare.Terminate;
BinaryCompare:= nil;
end;
end;
end;
procedure TfrmDiffer.actAboutExecute(Sender: TObject);
begin
ShowMessage('Internal Differ tool of Double Commander.' + LineEnding + LineEnding +
'It is inspired by Flavio Etrusco''s Pariter tool.' + LineEnding +
'You can find it on: http://sourceforge.net/projects/pariter' + LineEnding +
'It is based on Angus Johnson''s excellent TDiff component.' + LineEnding +
'You can find it on: http://www.users.on.net/johnson/delphi');
end;
procedure TfrmDiffer.actEditCopyExecute(Sender: TObject);
begin
SynDiffEditActive.CopyToClipboard;
end;
procedure TfrmDiffer.actEditCutExecute(Sender: TObject);
begin
SynDiffEditActive.CutToClipboard;
end;
procedure TfrmDiffer.actEditDeleteExecute(Sender: TObject);
begin
SynDiffEditActive.ClearSelection;
end;
procedure TfrmDiffer.actEditPasteExecute(Sender: TObject);
begin
SynDiffEditActive.PasteFromClipboard;
end;
procedure TfrmDiffer.actEditRedoExecute(Sender: TObject);
begin
SynDiffEditActive.Redo;
end;
procedure TfrmDiffer.actEditSelectAllExecute(Sender: TObject);
begin
SynDiffEditActive.SelectAll;
end;
procedure TfrmDiffer.actEditUndoExecute(Sender: TObject);
begin
SynDiffEditActive.Undo;
end;
procedure TfrmDiffer.actExecute(Sender: TObject);
var
cmd: string;
begin
cmd := (Sender as TAction).Name;
cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3);
Commands.ExecuteCommand(cmd, []);
end;
procedure TfrmDiffer.actIgnoreCaseExecute(Sender: TObject);
begin
if actAutoCompare.Checked then actStartCompare.Execute;
end;
procedure TfrmDiffer.actLineDifferencesExecute(Sender: TObject);
begin
if actLineDifferences.Checked and (Diff.Count <> 0) then
begin
SynDiffEditLeft.Highlighter:= SynDiffHighlighterLeft;
SynDiffEditRight.Highlighter:= SynDiffHighlighterRight;
end
else
begin
SynDiffEditLeft.Highlighter:= nil;
SynDiffEditRight.Highlighter:= nil;
end;
SynDiffEditLeft.Repaint;
SynDiffEditRight.Repaint;
end;
procedure TfrmDiffer.actKeepScrollingExecute(Sender: TObject);
begin
BinaryViewerLeft.KeepScrolling:= actKeepScrolling.Checked;
BinaryViewerRight.KeepScrolling:= actKeepScrolling.Checked;
end;
procedure TfrmDiffer.btnLeftEncodingClick(Sender: TObject);
begin
pmEncodingLeft.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y);
end;
procedure TfrmDiffer.btnRightEncodingClick(Sender: TObject);
begin
pmEncodingRight.PopUp(Mouse.CursorPos.X, Mouse.CursorPos.Y);
end;
procedure TfrmDiffer.edtFileNameLeftAcceptFileName(Sender: TObject;
var Value: String);
begin
OpenFileLeft(Value);
if actAutoCompare.Checked then actStartCompare.Execute;
end;
procedure TfrmDiffer.edtFileNameRightAcceptFileName(Sender: TObject;
var Value: String);
begin
OpenFileRight(Value);
if actAutoCompare.Checked then actStartCompare.Execute;
end;
procedure TfrmDiffer.FormCreate(Sender: TObject);
begin
ScrollLock:= 0;
Diff:= TDiff.Create(Self);
SynDiffEditLeft:= TSynDiffEdit.Create(Self);
SynDiffEditRight:= TSynDiffEdit.Create(Self);
SynDiffHighlighterLeft:= TSynDiffHighlighter.Create(SynDiffEditLeft);
SynDiffHighlighterRight:= TSynDiffHighlighter.Create(SynDiffEditRight);
SynDiffEditLeft.Parent:= pnlLeft;
SynDiffEditRight.Parent:= pnlRight;
SynDiffEditLeft.Align:= alClient;
SynDiffEditRight.Align:= alClient;
SynDiffEditLeft.PopupMenu:= ContextMenu;
SynDiffEditRight.PopupMenu:= ContextMenu;
SynDiffEditLeft.ModifiedFile:= SynDiffEditRight;
SynDiffEditRight.OriginalFile:= SynDiffEditLeft;
SynDiffEditLeft.OnEnter:= @SynDiffEditEnter;
SynDiffEditRight.OnEnter:= @SynDiffEditEnter;
SynDiffEditLeft.OnStatusChange:= @SynDiffEditLeftStatusChange;
SynDiffEditRight.OnStatusChange:= @SynDiffEditRightStatusChange;
// Set active editor
SynDiffEditActive:= SynDiffEditLeft;
BinaryDiffList:= TFPList.Create;
BinaryViewerLeft:= TBinaryDiffViewer.Create(Self);
BinaryViewerRight:= TBinaryDiffViewer.Create(Self);
BinaryViewerLeft.OnFileOpen:= @FileOpenUAC;
BinaryViewerRight.OnFileOpen:= @FileOpenUAC;
BinaryViewerLeft.Visible:= False;
BinaryViewerRight.Visible:= False;
BinaryViewerLeft.Parent:= pnlLeft;
BinaryViewerRight.Parent:= pnlRight;
BinaryViewerLeft.Align:= alClient;
BinaryViewerRight.Align:= alClient;
BinaryViewerLeft.SecondViewer:= BinaryViewerRight;
BinaryViewerRight.SecondViewer:= BinaryViewerLeft;
BinaryViewerLeft.Modified:= gDifferModifiedBinaryColor;
BinaryViewerRight.Modified:= gDifferModifiedBinaryColor;
FontOptionsToFont(gFonts[dcfEditor], SynDiffEditLeft.Font);
FontOptionsToFont(gFonts[dcfEditor], SynDiffEditRight.Font);
FontOptionsToFont(gFonts[dcfViewer], BinaryViewerLeft.Font);
FontOptionsToFont(gFonts[dcfViewer], BinaryViewerRight.Font);
// Load settings
actIgnoreCase.Checked := gDifferIgnoreCase;
actKeepScrolling.Checked := gDifferKeepScrolling;
actLineDifferences.Checked := gDifferLineDifferences;
actPaintBackground.Checked := gDifferPaintBackground;
actIgnoreWhiteSpace.Checked := gDifferIgnoreWhiteSpace;
// Initialize mode
actKeepScrollingExecute(actKeepScrolling);
actPaintBackgroundExecute(actPaintBackground);
// Initialize property storage
InitPropStorage(Self);
// Fill encoding menu
EncodingList:= TStringList.Create;
GetSupportedEncodings(EncodingList);
FillEncodingMenu(miEncodingLeft, @SetEncodingLeft, 1);
FillEncodingMenu(miEncodingRight, @SetEncodingRight, 2);
FillEncodingMenu(pmEncodingLeft.Items, @SetEncodingLeft, 1);
FillEncodingMenu(pmEncodingRight.Items, @SetEncodingRight, 2);
EncodingList.Free;
end;
procedure TfrmDiffer.FormDestroy(Sender: TObject);
begin
FreeAndNil(Diff);
FreeAndNil(BinaryDiffList);
end;
procedure TfrmDiffer.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_ESCAPE then
begin
Key:= 0;
Close;
end;
end;
procedure TfrmDiffer.FormResize(Sender: TObject);
begin
pnlLeft.Width:= (ClientWidth div 2) - (Splitter.Width div 2);
end;
procedure TfrmDiffer.btnCancelClick(Sender: TObject);
begin
FCancel:= True;
if actBinaryCompare.Checked and Assigned(BinaryCompare) then
BinaryCompare.Terminate
else begin
Diff.Cancel;
end;
CloseProgressDialog;
end;
procedure TfrmDiffer.tmProgressTimer(Sender: TObject);
begin
tmProgress.Enabled:= False;
ShowProgressDialog;
end;
procedure TfrmDiffer.BinaryCompareFinish;
begin
BinaryCompare:= nil;
if FCancel then begin
if FShowIdentical then Free;
Exit;
end;
BinaryDiffIndex:= -1;
tmProgress.Enabled:= False;
StatusBar.Panels[0].Text := EmptyStr;
StatusBar.Panels[1].Text := rsDiffModifies + IntToStr(BinaryDiffList.Count);
StatusBar.Panels[2].Text := EmptyStr;
StatusBar.Panels[3].Text := EmptyStr;
actStartCompare.Enabled := True;
actCancelCompare.Enabled := False;
actBinaryCompare.Enabled := True;
if FShowIdentical then
begin
CloseProgressDialog;
FShowIdentical:= (BinaryDiffList.Count = 0);
if FShowIdentical then
ShowIdentical
else begin
FShowIdentical:= False;
Application.QueueAsyncCall(@ShowFirstDifference, 0);
ShowDialog;
end;
end;
end;
procedure TfrmDiffer.ShowDialog;
begin
if FModal then
ShowModal
else if (FWaitData = nil) then
ShowOnTop
else
FWaitData.ShowOnTop(Self);
end;
procedure TfrmDiffer.ShowIdentical;
var
Message: String;
begin
Message:= rsDiffFilesIdentical + LineEnding + LineEnding;
Message+= edtFileNameLeft.Text + LineEnding + edtFileNameRight.Text;
if MessageDlg(rsToolDiffer, Message, mtWarning, [mbIgnore, mbCancel], 0, mbIgnore) = mrCancel then
Close
else begin
FShowIdentical:= False;
ShowDialog;
end;
end;
procedure TfrmDiffer.ShowProgressDialog;
var
lblPrompt : TLabel;
btnCancel : TBitBtn;
pbProgress: TProgressBar;
begin
frmProgress := TModalDialog.CreateNew(nil, 0);
with frmProgress do
begin
BorderStyle := bsDialog;
Position := poOwnerFormCenter;
AutoSize := True;
Height := 120;
ChildSizing.TopBottomSpacing := 8;
ChildSizing.LeftRightSpacing := 8;
Caption := Self.Caption;
lblPrompt := TLabel.Create(frmProgress);
with lblPrompt do
begin
Parent := frmProgress;
Caption := rsDiffComparing;
Top := 6;
Left := 6;
end;
pbProgress:= TProgressBar.Create(frmProgress);
with pbProgress do
begin
Parent := frmProgress;
Style:= pbstMarquee;
Left := 6;
AnchorToNeighbour(akTop, 6, lblPrompt);
Constraints.MinWidth := Math.Max(280, Screen.Width div 4);
end;
btnCancel := TBitBtn.Create(frmProgress);
with btnCancel do
begin
AutoSize := True;
Parent := frmProgress;
Kind := bkCancel;
Cancel := True;
OnClick:= @btnCancelClick;
Anchors := [akTop, akRight];
AnchorToNeighbour(akTop, 18, pbProgress);
AnchorSide[akRight].Control := pbProgress;
AnchorSide[akRight].Side := asrCenter;
end;
if FModal then
ShowModal
else if (FWaitData = nil) then
ShowOnTop
else
FWaitData.ShowOnTop(frmProgress);
end;
end;
procedure TfrmDiffer.CloseProgressDialog;
begin
if Assigned(frmProgress) then
begin
frmProgress.Close;
FreeAndNil(frmProgress);
end;
end;
procedure TfrmDiffer.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
CloseAction:= caFree;
// Save settings
gDifferIgnoreCase := actIgnoreCase.Checked;
gDifferKeepScrolling := actKeepScrolling.Checked;
gDifferLineDifferences := actLineDifferences.Checked;
gDifferPaintBackground := actPaintBackground.Checked;
gDifferIgnoreWhiteSpace := actIgnoreWhiteSpace.Checked;
end;
procedure TfrmDiffer.FormCloseQuery(Sender: TObject; var CanClose: boolean);
var
Result: TMyMsgResult;
begin
if SynDiffEditLeft.Modified then
begin
Result:= msgYesNoCancel(Format(rsMsgFileChangedSave, [edtFileNameLeft.FileName]));
CanClose:= Result <> mmrCancel;
if Result = mmrYes then
actSaveLeft.Execute
else if Result = mmrCancel then
Exit;
end;
if SynDiffEditRight.Modified then
begin
Result:= msgYesNoCancel(Format(rsMsgFileChangedSave, [edtFileNameRight.FileName]));
CanClose:= Result <> mmrCancel;
if Result = mmrYes then
actSaveRight.Execute
else if Result = mmrCancel then
Exit;
end;
end;
procedure TfrmDiffer.Clear(bLeft, bRight: Boolean);
begin
if bLeft then
begin
SynDiffEditLeft.Lines.Clear;
SetLength(HashListLeft, 0);
end;
if bRight then
begin
SynDiffEditRight.Lines.Clear;
SetLength(HashListRight, 0);
end;
Diff.Clear;
StatusBar.Panels[0].Text := EmptyStr;
StatusBar.Panels[1].Text := EmptyStr;
StatusBar.Panels[2].Text := EmptyStr;
StatusBar.Panels[3].Text := EmptyStr;
actStartCompare.Enabled := True;
end;
procedure TfrmDiffer.cm_CopyLeftToRight(const Params: array of string);
var
I, iStart,
iFinish: Integer;
begin
I := SynDiffEditLeft.CaretY - 1;
iStart:= SynDiffEditLeft.DiffBegin(I);
iFinish:= SynDiffEditLeft.DiffEnd(I);
if SynDiffEditLeft.Lines.Kind[iStart] <> ckAdd then
begin
for I:= iStart to iFinish do
begin
SynDiffEditRight.Lines[I]:= SynDiffEditLeft.Lines[I];
if SynDiffEditLeft.Lines.Kind[I] = ckDelete then
begin
SynDiffEditLeft.Lines.Kind[I]:= ckNone;
SynDiffEditRight.Lines.SetKindAndNumber(I, ckNone, 0);
end;
end;
end
else begin
for I:= iStart to iFinish do
begin
if SynDiffEditLeft.Lines[iStart] <> EmptyStr then
begin
SynDiffEditRight.Lines[iStart]:= SynDiffEditLeft.Lines[iStart];
Inc(iStart);
end
else begin
SynDiffEditLeft.Lines.Delete(iStart);
SynDiffEditRight.Lines.Delete(iStart);
end;
end;
end;
SynDiffEditLeft.Renumber;
SynDiffEditRight.Renumber;
end;
procedure TfrmDiffer.cm_CopyRightToLeft(const Params: array of string);
var
I, iStart,
iFinish: Integer;
begin
I := SynDiffEditRight.CaretY - 1;
iStart:= SynDiffEditRight.DiffBegin(I);
iFinish:= SynDiffEditRight.DiffEnd(I);
if SynDiffEditLeft.Lines.Kind[iStart] <> ckDelete then
begin
for I:= iStart to iFinish do
begin
SynDiffEditLeft.Lines[I]:= SynDiffEditRight.Lines[I];
if SynDiffEditRight.Lines.Kind[I] = ckAdd then
begin
SynDiffEditRight.Lines.Kind[I]:= ckNone;
SynDiffEditLeft.Lines.SetKindAndNumber(I, ckNone, 0);
end;
end;
end
else begin
for I:= iStart to iFinish do
begin
if SynDiffEditRight.Lines[iStart] <> EmptyStr then
begin
SynDiffEditLeft.Lines[iStart]:= SynDiffEditRight.Lines[iStart];
Inc(iStart);
end
else begin
SynDiffEditLeft.Lines.Delete(iStart);
SynDiffEditRight.Lines.Delete(iStart);
end;
end;
end;
SynDiffEditLeft.Renumber;
SynDiffEditRight.Renumber;
end;
procedure TfrmDiffer.cm_Exit(const Params: array of string);
begin
Close;
end;
procedure TfrmDiffer.cm_FirstDifference(const Params: array of string);
var
Line: Integer;
Kind: TChangeKind;
begin
if actBinaryCompare.Checked then
begin
if BinaryDiffList.Count > 0 then
begin
BinaryDiffIndex:= 0;
BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
if not actKeepScrolling.Checked then
BinaryViewerRight.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
end;
end
else begin
// Start at first line
Line := 0;
if Line = SynDiffEditLeft.Lines.Count then Exit;
// Skip unmodified lines
Kind := ckNone;
while (Line < SynDiffEditLeft.Lines.Count - 1) and
(SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line);
Inc(Line);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
SynDiffEditRight.CaretY := Line;
if not actKeepScrolling.Checked then begin
SynDiffEditRight.TopLine := Line;
end;
end;
end;
procedure TfrmDiffer.cm_LastDifference(const Params: array of string);
var
Line: Integer;
Kind: TChangeKind;
begin
if actBinaryCompare.Checked then
begin
if BinaryDiffList.Count > 0 then
begin
BinaryDiffIndex:= BinaryDiffList.Count - 1;
BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
if not actKeepScrolling.Checked then
BinaryViewerRight.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
end;
end
else begin
Line := SynDiffEditLeft.Lines.Count - 1;
if Line = 0 then Exit;
// Skip unmodified lines
Kind := ckNone;
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
// Find top line of previous difference
Kind:= SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
if (Line <> 0) then Inc(Line, 2);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
SynDiffEditRight.CaretY := Line;
if not actKeepScrolling.Checked then begin
SynDiffEditRight.TopLine := Line;
end;
end;
end;
procedure TfrmDiffer.cm_NextDifference(const Params: array of string);
var
Line: Integer;
Kind: TChangeKind;
begin
if actBinaryCompare.Checked then
begin
if BinaryDiffIndex < BinaryDiffList.Count - 1 then
begin
BinaryDiffIndex:= BinaryDiffIndex + 1;
BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
if not actKeepScrolling.Checked then
BinaryViewerRight.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
end;
end
else begin
Line := SynDiffEditLeft.CaretY - 1;
if Line = SynDiffEditLeft.Lines.Count - 1 then Exit;
// Skip lines with current difference type
Kind := SynDiffEditLeft.Lines.Kind[Line];
while (Line < SynDiffEditLeft.Lines.Count - 1) and
(SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line);
if SynDiffEditLeft.Lines.Kind[Line] = ckNone then
begin
// Skip unmodified lines
Kind := ckNone;
while (Line < SynDiffEditLeft.Lines.Count - 1) and
(SynDiffEditLeft.Lines.Kind[Line] = Kind) do Inc(Line);
end;
Inc(Line);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
SynDiffEditRight.CaretY := Line;
if not actKeepScrolling.Checked then begin
SynDiffEditRight.TopLine := Line;
end;
end;
end;
procedure TfrmDiffer.cm_PrevDifference(const Params: array of string);
var
Line: Integer;
Kind: TChangeKind;
begin
if actBinaryCompare.Checked then
begin
if BinaryDiffIndex > 0 then
begin
BinaryDiffIndex:= BinaryDiffIndex - 1;
BinaryViewerLeft.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
if not actKeepScrolling.Checked then
BinaryViewerRight.Position:= PtrInt(BinaryDiffList[BinaryDiffIndex]);
end;
end
else begin
Line := SynDiffEditLeft.CaretY - 1;
if Line = 0 then Exit;
// Skip lines with current difference type
Kind := SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
if SynDiffEditLeft.Lines.Kind[Line] = ckNone then
begin
// Skip unmodified lines
Kind := ckNone;
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
end;
// Find top line of previous difference
Kind:= SynDiffEditLeft.Lines.Kind[Line];
while (Line > 0) and (SynDiffEditLeft.Lines.Kind[Line] = Kind) do Dec(Line);
if (Line <> 0) then Inc(Line, 2);
SynDiffEditLeft.CaretY := Line;
SynDiffEditLeft.TopLine := Line;
SynDiffEditRight.CaretY := Line;
if not actKeepScrolling.Checked then begin
SynDiffEditRight.TopLine := Line;
end;
end;
end;
procedure TfrmDiffer.cm_Reload(const Params: array of string);
begin
OpenFileLeft(edtFileNameLeft.FileName);
OpenFileRight(edtFileNameRight.FileName);
if actAutoCompare.Checked then actStartCompare.Execute;
end;
procedure TfrmDiffer.cm_SaveLeft(const Params: array of string);
begin
PushPop(FElevate);
try
SaveToFile(SynDiffEditLeft, edtFileNameLeft.FileName);
finally
PushPop(FElevate);
end;
end;
procedure TfrmDiffer.cm_SaveRight(const Params: array of string);
begin
PushPop(FElevate);
try
SaveToFile(SynDiffEditRight, edtFileNameRight.FileName);
finally
PushPop(FElevate);
end;
end;
constructor TfrmDiffer.Create(TheOwner: TComponent);
var
HMForm: THMForm;
begin
inherited Create(TheOwner);
FCommands := TFormCommands.Create(Self, actionList);
HMForm := HotMan.Register(Self, HotkeysCategory);
HMForm.RegisterActionList(actionList);
end;
destructor TfrmDiffer.Destroy;
begin
BinaryViewerLeft.SecondViewer:= nil;
BinaryViewerRight.SecondViewer:= nil;
HotMan.UnRegister(Self);
inherited Destroy;
if Assigned(FWaitData) then FWaitData.Done;
end;
procedure TfrmDiffer.AfterConstruction;
begin
inherited AfterConstruction;
ToolBar.ImagesWidth:= gToolIconsSize;
ToolBar.SetButtonSize(gToolIconsSize + ScaleX(6, 96),
gToolIconsSize + ScaleY(6, 96));
end;
procedure TfrmDiffer.BuildHashList(bLeft, bRight: Boolean);
var
I: Integer;
begin
if bLeft then
begin
SetLength(HashListLeft, SynDiffEditLeft.Lines.Count);
for I := 0 to SynDiffEditLeft.Lines.Count - 1 do
HashListLeft[I]:= Integer(HashString(SynDiffEditLeft.Lines[I],
actIgnoreCase.Checked, actIgnoreWhiteSpace.Checked));
end;
if bRight then
begin
SetLength(HashListRight, SynDiffEditRight.Lines.Count);
for I := 0 to SynDiffEditRight.Lines.Count - 1 do
HashListRight[I]:= Integer(HashString(SynDiffEditRight.Lines[I],
actIgnoreCase.Checked, actIgnoreWhiteSpace.Checked));
end;
actStartCompare.Enabled := (Length(HashListLeft) > 0) and (Length(HashListRight) > 0);
actCopyLeftToRight.Enabled := actStartCompare.Enabled;
actCopyRightToLeft.Enabled := actStartCompare.Enabled;
end;
procedure TfrmDiffer.SetColors(cAdded, cDeleted, cModified: TColor);
begin
with SynDiffEditLeft do
begin
Colors.Added:= cAdded;
Colors.Deleted:= cDeleted;
Colors.Modified:= cModified;
end;
with SynDiffEditRight do
begin
Colors.Added:= cAdded;
Colors.Deleted:= cDeleted;
Colors.Modified:= cModified;
end;
end;
procedure TfrmDiffer.ChooseEncoding(SynDiffEdit: TSynDiffEdit);
begin
if SynDiffEdit = SynDiffEditLeft then
begin
ChooseEncoding(miEncodingLeft, SynDiffEdit.Encoding);
ChooseEncoding(pmEncodingLeft.Items, SynDiffEdit.Encoding);
end
else
begin
ChooseEncoding(miEncodingRight, SynDiffEdit.Encoding);
ChooseEncoding(pmEncodingRight.Items, SynDiffEdit.Encoding);
end;
end;
procedure TfrmDiffer.ChooseEncoding(MenuItem: TMenuItem; Encoding: String);
var
I: Integer;
begin
Encoding:= NormalizeEncoding(Encoding);
for I:= 0 to MenuItem.Count - 1 do
if SameText(NormalizeEncoding(MenuItem.Items[I].Caption), Encoding) then
MenuItem.Items[I].Checked:= True;
end;
procedure TfrmDiffer.FillEncodingMenu(TheOwner: TMenuItem;
MenuHandler: TNotifyEvent; GroupIndex: LongInt);
var
I: Integer;
mi: TMenuItem;
begin
for I:= 0 to EncodingList.Count - 1 do
begin
mi:= TMenuItem.Create(TheOwner);
mi.Caption:= EncodingList[I];
mi.RadioItem:= True;
mi.GroupIndex:= GroupIndex;
mi.OnClick:= MenuHandler;
TheOwner.Add(mi);
end;
end;
procedure TfrmDiffer.LoadFromFile(SynDiffEdit: TSynDiffEdit; const FileName: String);
var
AText: String;
fsFileStream: TFileStreamUAC;
begin
try
fsFileStream:= TFileStreamUAC.Create(FileName, fmOpenRead or fmShareDenyNone);
try
SetLength(AText, fsFileStream.Size);
fsFileStream.Read(Pointer(AText)^, Length(AText));
if Length(SynDiffEdit.Encoding) = 0 then
begin
SynDiffEdit.Encoding:= DetectEncoding(AText);
ChooseEncoding(SynDiffEdit);
end;
with SynDiffEdit do
begin
if (Encoding = EncodingUTF16LE) or (Encoding = EncodingUTF16BE) then
begin
AText:= Copy(AText, 3, MaxInt); // Skip BOM
end;
AText:= ConvertEncoding(AText, Encoding, EncodingUTF8);
end;
SynDiffEdit.Lines.Text:= AText;
// Determine line break style
SynDiffEdit.Lines.TextLineBreakStyle := GuessLineBreakStyle(AText);
finally
FreeAndNil(fsFileStream);
end;
except
on E: Exception do
begin
E.Message:= E.Message + LineEnding + FileName;
if FShowIdentical then raise;
msgError(E.Message);
end;
end;
end;
procedure TfrmDiffer.SaveToFile(SynDiffEdit: TSynDiffEdit; const FileName: String);
var
AText: String;
AMode: LongWord;
begin
AText := EmptyStr;
if (SynDiffEdit.Encoding = EncodingUTF16LE) then
AText := UTF16LEBOM
else if (SynDiffEdit.Encoding = EncodingUTF16BE) then begin
AText := UTF16BEBOM
end;
with TStringListEx.Create do
try
Assign(SynDiffEdit.Lines);
// remove fake lines
RemoveFake;
// restore encoding
AText+= ConvertEncoding(Text, EncodingUTF8, SynDiffEdit.Encoding);
finally
Free;
end;
// save to file
try
if not FileExistsUAC(FileName) then
AMode:= fmCreate
else begin
AMode:= fmOpenWrite or fmShareDenyWrite;
end;
with TFileStreamUAC.Create(FileName, AMode) do
try
WriteBuffer(Pointer(AText)^, Length(AText));
if (AMode <> fmCreate) then Size:= Position;
finally
Free;
end;
SynDiffEdit.Modified:= False; // needed for the undo stack
except
on E: Exception do
msgError(rsMsgErrSaveFile + ' ' + FileName + LineEnding + E.Message);
end;
end;
procedure TfrmDiffer.OpenFileLeft(const FileName: String);
begin
PushPop(FElevate);
try
if not FileExistsUAC(FileName) then Exit;
if actBinaryCompare.Checked then
begin
BinaryDiffList.Clear;
BinaryViewerLeft.FileName:= FileName
end
else begin
Clear(True, False);
LoadFromFile(SynDiffEditLeft, FileName);
BuildHashList(True, False);
SynDiffEditLeft.Repaint;
end;
finally
PushPop(FElevate);
end;
end;
procedure TfrmDiffer.OpenFileRight(const FileName: String);
begin
PushPop(FElevate);
try
if not FileExistsUAC(FileName) then Exit;
if actBinaryCompare.Checked then
begin
BinaryDiffList.Clear;
BinaryViewerRight.FileName:= FileName
end
else begin
Clear(False, True);
LoadFromFile(SynDiffEditRight, FileName);
BuildHashList(False, True);
SynDiffEditRight.Repaint;
end;
finally
PushPop(FElevate);
end;
end;
procedure TfrmDiffer.SetEncodingLeft(Sender: TObject);
begin
SynDiffEditLeft.Encoding:= (Sender as TMenuItem).Caption;
ChooseEncoding(miEncodingLeft, SynDiffEditLeft.Encoding);
ChooseEncoding(pmEncodingLeft.Items, SynDiffEditLeft.Encoding);
actReload.Execute;
end;
procedure TfrmDiffer.SetEncodingRight(Sender: TObject);
begin
SynDiffEditRight.Encoding:= (Sender as TMenuItem).Caption;
ChooseEncoding(miEncodingRight, SynDiffEditRight.Encoding);
ChooseEncoding(pmEncodingRight.Items, SynDiffEditRight.Encoding);
actReload.Execute;
end;
procedure TfrmDiffer.SynDiffEditEnter(Sender: TObject);
begin
SynDiffEditActive:= (Sender as TSynDiffEdit);
end;
procedure TfrmDiffer.ShowFirstDifference(Data: PtrInt);
begin
cm_FirstDifference([]);
end;
procedure TfrmDiffer.SynDiffEditLeftStatusChange(Sender: TObject;
Changes: TSynStatusChanges);
begin
if (actKeepScrolling.Checked) and (ScrollLock = 0) and
((scTopLine in Changes) or (scLeftChar in Changes)) then
try
Inc(ScrollLock);
while (SynDiffEditRight.PaintLock <> 0) do Sleep(1);
SynDiffEditRight.TopLine:= SynDiffEditLeft.TopLine;
SynDiffEditRight.LeftChar:= SynDiffEditLeft.LeftChar;
finally
Dec(ScrollLock);
end;
end;
procedure TfrmDiffer.SynDiffEditRightStatusChange(Sender: TObject;
Changes: TSynStatusChanges);
begin
if (actKeepScrolling.Checked) and (ScrollLock = 0) and
((scTopLine in Changes) or (scLeftChar in Changes)) then
try
Inc(ScrollLock);
while (SynDiffEditLeft.PaintLock <> 0) do Sleep(1);
SynDiffEditLeft.TopLine:= SynDiffEditRight.TopLine;
SynDiffEditLeft.LeftChar:= SynDiffEditRight.LeftChar;
finally
Dec(ScrollLock);
end;
end;
initialization
TFormCommands.RegisterCommandsForm(TfrmDiffer, HotkeysCategory, @rsHotkeyCategoryDiffer);
end.