📄 frmeditor.pas
字号:
{ TEditorFactory }
type
TEditorFactory = class(TInterfacedObject, IEditorFactory)
private
// IEditorFactory implementation
function CanCloseAll: boolean;
procedure CloseAll;
function CreateBorderless(AOwner: TForm): IEditor;
function CreateMDIChild(AOwner: TForm): IEditor;
function CreateTabSheet(AOwner: TPageControl): IEditor;
function GetEditorCount: integer;
function GetEditor(Index: integer): IEditor;
procedure RemoveEditor(AEditor: IEditor);
private
fEditors: TInterfaceList;
constructor Create;
destructor Destroy; override;
end;
constructor TEditorFactory.Create;
begin
inherited Create;
fEditors := TInterfaceList.Create;
end;
destructor TEditorFactory.Destroy;
begin
fEditors.Free;
inherited Destroy;
end;
function TEditorFactory.CanCloseAll: boolean;
var
i: integer;
LEditor: IEditor;
begin
i := fEditors.Count - 1;
while i >= 0 do begin
LEditor := IEditor(fEditors[i]);
if not LEditor.AskSaveChanges then begin
Result := FALSE;
exit;
end;
Dec(i);
end;
Result := TRUE;
end;
procedure TEditorFactory.CloseAll;
var
i: integer;
begin
i := fEditors.Count - 1;
while i >= 0 do begin
IEditor(fEditors[i]).Close;
Dec(i);
end;
end;
function TEditorFactory.CreateBorderless(AOwner: TForm): IEditor;
var
LForm: TEditorForm;
begin
LForm := TEditorForm.Create(AOwner);
with LForm do begin
fEditor := TEditor.Create(LForm);
Result := fEditor;
fKind := ekBorderless;
BorderStyle := bsNone;
Parent := AOwner;
Align := alClient;
Visible := TRUE;
end;
if Result <> nil then
fEditors.Add(Result);
end;
function TEditorFactory.CreateMDIChild(AOwner: TForm): IEditor;
var
LForm: TEditorForm;
begin
LForm := TEditorForm.Create(AOwner);
with LForm do begin
fEditor := TEditor.Create(LForm);
Result := fEditor;
fKind := ekMDIChild;
FormStyle := fsMDIChild;
end;
if Result <> nil then
fEditors.Add(Result);
end;
function TEditorFactory.CreateTabSheet(AOwner: TPageControl): IEditor;
var
Sheet: TTabSheet;
LForm: TEditorForm;
begin
Sheet := TEditorTabSheet.Create(AOwner);
try
Sheet.PageControl := AOwner;
LForm := TEditorForm.Create(Sheet);
with LForm do begin
fEditor := TEditor.Create(LForm);
Result := fEditor;
fKind := ekInTabsheet;
BorderStyle := bsNone;
Parent := Sheet;
Align := alClient;
Visible := TRUE;
AOwner.ActivePage := Sheet;
LForm.SetFocus;
end;
// fix for Delphi 4 (???)
LForm.Realign;
if Result <> nil then
fEditors.Add(Result);
except
Sheet.Free;
end;
end;
function TEditorFactory.GetEditorCount: integer;
begin
Result := fEditors.Count;
end;
function TEditorFactory.GetEditor(Index: integer): IEditor;
begin
Result := IEditor(fEditors[Index]);
end;
procedure TEditorFactory.RemoveEditor(AEditor: IEditor);
var
i: integer;
begin
i := fEditors.IndexOf(AEditor);
if i > -1 then
fEditors.Delete(i);
end;
{ TEditorForm }
procedure TEditorForm.FormActivate(Sender: TObject);
begin
DoAssignInterfacePointer(TRUE);
end;
procedure TEditorForm.FormDeactivate(Sender: TObject);
begin
DoAssignInterfacePointer(FALSE);
end;
procedure TEditorForm.FormShow(Sender: TObject);
begin
DoUpdateCaption;
end;
procedure TEditorForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if fKind = ekInTabSheet then begin
PostMessage(Parent.Handle, WM_DELETETHIS, 0, 0);
Action := caNone;
end else
Action := caFree;
end;
procedure TEditorForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
// need to prevent this from happening more than once (e.g. with MDI childs)
if not (csDestroying in ComponentState) then
CanClose := DoAskSaveChanges;
end;
procedure TEditorForm.FormDestroy(Sender: TObject);
var
LEditor: IEditor;
begin
LEditor := fEditor;
Assert(fEditor <> nil);
fEditor.fForm := nil;
Assert(GI_EditorFactory <> nil);
GI_EditorFactory.RemoveEditor(LEditor);
end;
procedure TEditorForm.SynEditorChange(Sender: TObject);
var
Empty: boolean;
i: integer;
begin
Assert(fEditor <> nil);
Empty := TRUE;
for i := SynEditor.Lines.Count - 1 downto 0 do
if SynEditor.Lines[i] <> '' then begin
Empty := FALSE;
break;
end;
fEditor.fIsEmpty := Empty;
end;
procedure TEditorForm.SynEditorEnter(Sender: TObject);
begin
DoAssignInterfacePointer(TRUE);
end;
procedure TEditorForm.SynEditorExit(Sender: TObject);
begin
DoAssignInterfacePointer(FALSE);
end;
procedure TEditorForm.SynEditorReplaceText(Sender: TObject; const ASearch,
AReplace: String; Line, Column: Integer; var Action: TSynReplaceAction);
var
APos: TPoint;
EditRect: TRect;
begin
if ASearch = AReplace then
Action := raSkip
else begin
APos := SynEditor.ClientToScreen(
SynEditor.RowColumnToPixels(
SynEditor.BufferToDisplayPos(
MakeBufferCoord(Column, Line) ) ) );
EditRect := ClientRect;
EditRect.TopLeft := ClientToScreen(EditRect.TopLeft);
EditRect.BottomRight := ClientToScreen(EditRect.BottomRight);
if ConfirmReplaceDialog = nil then
ConfirmReplaceDialog := TConfirmReplaceDialog.Create(Application);
ConfirmReplaceDialog.PrepareShow(EditRect, APos.X, APos.Y,
APos.Y + SynEditor.LineHeight, ASearch);
case ConfirmReplaceDialog.ShowModal of
mrYes: Action := raReplace;
mrYesToAll: Action := raReplaceAll;
mrNo: Action := raSkip;
else Action := raCancel;
end;
end;
end;
procedure TEditorForm.SynEditorStatusChange(Sender: TObject;
Changes: TSynStatusChanges);
begin
Assert(fEditor <> nil);
if Changes * [scAll, scSelection] <> [] then
fEditor.fHasSelection := SynEditor.SelAvail;
if Changes * [scAll, scSelection] <> [] then
fEditor.fIsReadOnly := SynEditor.ReadOnly;
if Changes * [scAll, scModified] <> [] then
fEditor.fModified := SynEditor.Modified;
end;
procedure TEditorForm.DoActivate;
var
Sheet: TTabSheet;
PCtrl: TPageControl;
begin
if FormStyle = fsMDIChild then
BringToFront
else if Parent is TTabSheet then begin
Sheet := TTabSheet(Parent);
PCtrl := Sheet.PageControl;
if PCtrl <> nil then
PCtrl.ActivePage := Sheet;
end;
end;
function TEditorForm.DoAskSaveChanges: boolean;
const
MBType = MB_YESNOCANCEL or MB_ICONQUESTION;
var
s: string;
begin
// this is necessary to prevent second confirmation when closing MDI childs
if SynEditor.Modified then begin
DoActivate;
MessageBeep(MB_ICONQUESTION);
Assert(fEditor <> nil);
s := Format(SAskSaveChanges, [ExtractFileName(fEditor.GetFileTitle)]);
case Application.MessageBox(PChar(s), PChar(Application.Title), MBType) of
IDYes: Result := DoSave;
IDNo: Result := TRUE;
else
Result := FALSE;
end;
end else
Result := TRUE;
end;
procedure TEditorForm.DoAssignInterfacePointer(AActive: boolean);
begin
if AActive then begin
GI_ActiveEditor := fEditor;
GI_EditCmds := fEditor;
GI_FileCmds := fEditor;
GI_SearchCmds := fEditor;
end else begin
if GI_ActiveEditor = IEditor(fEditor) then
GI_ActiveEditor := nil;
if GI_EditCmds = IEditCommands(fEditor) then
GI_EditCmds := nil;
if GI_FileCmds = IFileCommands(fEditor) then
GI_FileCmds := nil;
if GI_SearchCmds = ISearchCommands(fEditor) then
GI_SearchCmds := nil;
end;
end;
function TEditorForm.DoSave: boolean;
begin
Assert(fEditor <> nil);
if fEditor.fFileName <> '' then
Result := DoSaveFile
else
Result := DoSaveAs;
end;
function TEditorForm.DoSaveFile: boolean;
begin
Assert(fEditor <> nil);
try
SynEditor.Lines.SaveToFile(fEditor.fFileName);
SynEditor.Modified := FALSE;
Result := TRUE;
except
Application.HandleException(Self);
Result := FALSE;
end;
end;
function TEditorForm.DoSaveAs: boolean;
var
NewName: string;
begin
Assert(fEditor <> nil);
NewName := fEditor.fFileName;
if CommandsDataModule.GetSaveFileName(NewName, SynEditor.Highlighter) then
begin
fEditor.DoSetFileName(NewName);
DoUpdateCaption;
DoUpdateHighlighter;
Result := DoSaveFile;
end else
Result := FALSE;
end;
procedure TEditorForm.DoSearchReplaceText(AReplace: boolean;
ABackwards: boolean);
var
Options: TSynSearchOptions;
begin
if AReplace then
Options := [ssoPrompt, ssoReplace, ssoReplaceAll]
else
Options := [];
if ABackwards then
Include(Options, ssoBackwards);
if gbSearchCaseSensitive then
Include(Options, ssoMatchCase);
if not fSearchFromCaret then
Include(Options, ssoEntireScope);
if gbSearchSelectionOnly then
Include(Options, ssoSelectedOnly);
if gbSearchWholeWords then
Include(Options, ssoWholeWord);
if SynEditor.SearchReplace(gsSearchText, gsReplaceText, Options) = 0 then
begin
MessageBeep(MB_ICONASTERISK);
if ssoBackwards in Options then
SynEditor.BlockEnd := SynEditor.BlockBegin
else
SynEditor.BlockBegin := SynEditor.BlockEnd;
SynEditor.CaretXY := SynEditor.BlockBegin;
end;
if ConfirmReplaceDialog <> nil then
ConfirmReplaceDialog.Free;
end;
procedure TEditorForm.DoUpdateCaption;
begin
Assert(fEditor <> nil);
case fKind of
ekInTabsheet:
(Parent as TTabSheet).Caption := fEditor.GetFileTitle;
ekMDIChild:
Caption := fEditor.GetFileTitle + ' - ' + SEditorCaption;
end;
end;
procedure TEditorForm.DoUpdateHighlighter;
begin
Assert(fEditor <> nil);
if fEditor.fFileName <> '' then begin
SynEditor.Highlighter := CommandsDataModule.GetHighlighterForFile(
fEditor.fFileName);
end else
SynEditor.Highlighter := nil;
end;
procedure TEditorForm.ShowSearchReplaceDialog(AReplace: boolean);
var
dlg: TTextSearchDialog;
begin
if AReplace then
dlg := TTextReplaceDialog.Create(Self)
else
dlg := TTextSearchDialog.Create(Self);
with dlg do try
// assign search options
SearchBackwards := gbSearchBackwards;
SearchCaseSensitive := gbSearchCaseSensitive;
SearchFromCursor := gbSearchFromCaret;
SearchInSelectionOnly := gbSearchSelectionOnly;
// start with last search text
SearchText := gsSearchText;
if gbSearchTextAtCaret then begin
// if something is selected search for that text
if SynEditor.SelAvail and (SynEditor.BlockBegin.Line = SynEditor.BlockEnd.Line)
then
SearchText := SynEditor.SelText
else
SearchText := SynEditor.GetWordAtRowCol(SynEditor.CaretXY);
end;
SearchTextHistory := gsSearchTextHistory;
if AReplace then with dlg as TTextReplaceDialog do begin
ReplaceText := gsReplaceText;
ReplaceTextHistory := gsReplaceTextHistory;
end;
SearchWholeWords := gbSearchWholeWords;
if ShowModal = mrOK then begin
gbSearchBackwards := SearchBackwards;
gbSearchCaseSensitive := SearchCaseSensitive;
gbSearchFromCaret := SearchFromCursor;
gbSearchSelectionOnly := SearchInSelectionOnly;
gbSearchWholeWords := SearchWholeWords;
gsSearchText := SearchText;
gsSearchTextHistory := SearchTextHistory;
if AReplace then with dlg as TTextReplaceDialog do begin
gsReplaceText := ReplaceText;
gsReplaceTextHistory := ReplaceTextHistory;
end;
fSearchFromCaret := gbSearchFromCaret;
if gsSearchText <> '' then begin
DoSearchReplaceText(AReplace, gbSearchBackwards);
fSearchFromCaret := TRUE;
end;
end;
finally
dlg.Free;
end;
end;
initialization
GI_EditorFactory := TEditorFactory.Create;
finalization
GI_EditorFactory := nil;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -