mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-12 18:47:41 +00:00
954 lines
28 KiB
ObjectPascal
954 lines
28 KiB
ObjectPascal
(*
|
|
Name: UframeTextEditor
|
|
Copyright: Copyright (C) SIL International.
|
|
Documentation:
|
|
Description:
|
|
Create Date: 23 Aug 2006
|
|
|
|
Modified Date: 23 Feb 2016
|
|
Authors: mcdurdin
|
|
Related Files:
|
|
Dependencies:
|
|
|
|
Bugs:
|
|
Todo:
|
|
Notes:
|
|
History: 23 Aug 2006 - mcdurdin - Initial version
|
|
14 Sep 2006 - mcdurdin - Add find and replace dialogs
|
|
14 Sep 2006 - mcdurdin - Add LoadFromStream and SaveToStream
|
|
14 Sep 2006 - mcdurdin - Add ConvertCharacter and GetWideCodes functions
|
|
28 Sep 2006 - mcdurdin - Add context help and character map lookup
|
|
06 Oct 2006 - mcdurdin - Only update help if form is visible
|
|
04 Dec 2006 - mcdurdin - Update help only when help form visible
|
|
12 Dec 2006 - mcdurdin - Add Print, Print Preview
|
|
04 Jan 2007 - mcdurdin - Add help support
|
|
25 Jan 2007 - mcdurdin - Delete dlgSave unused component
|
|
19 Mar 2007 - mcdurdin - I712 - Fix character map should follow selected character
|
|
30 May 2007 - mcdurdin - I781 - Search and Replace dialogs now support Unicode
|
|
19 Nov 2007 - mcdurdin - I1157 - const string parameters
|
|
14 Jun 2008 - mcdurdin - I1426 - Fixup script tag font
|
|
18 Mar 2011 - mcdurdin - I2794 - Fix memory leak
|
|
08 Jul 2011 - mcdurdin - I2971 - Branding Pack locale.xml not editing as UTF-8
|
|
18 May 2012 - mcdurdin - I3323 - V9.0 - Change from Plus-MemoU to Plus-Memo
|
|
08 Jun 2012 - mcdurdin - I3337 - V9.0 - Review of input/output for Unicode
|
|
06 Feb 2012 - mcdurdin - I3082 - Reload text file with specific encoding support, not marking as unmodified after reload
|
|
03 Nov 2012 - mcdurdin - I3502 - V9.0 - Merge of I3082 - Reload text file with specific encoding support
|
|
13 Dec 2012 - mcdurdin - I3637 - V9.0 - I3502 Fail - Reload as Format button is disabled in some contexts
|
|
01 Jan 2013 - mcdurdin - I3636 - V9.0 - File format dropdown shows wrong value
|
|
10 Jan 2014 - mcdurdin - I4021 - V9.0 - Redesign Keyboard Wizard to integrate V9 features
|
|
07 Feb 2014 - mcdurdin - I4034 - V9.0 - Restructure keyboard wizard for source views and features
|
|
27 Feb 2014 - mcdurdin - I4083 - V9.0 - When errors encountered in JSON layout file, locate the error in the source view
|
|
27 May 2015 - mcdurdin - I4616 - Developer crashes when saving or switching views due to locked files [CrashID:tike.exe_9.0.481.0_004587D3_EFOpenError]
|
|
27 May 2015 - mcdurdin - I4721 - V9.0 - Developer crashes if a file is in use and a reload is attempted
|
|
27 May 2015 - mcdurdin - I4499 - Developer crashes switching to source tab when line number is too high [CrashID:tike.exe_9.0.466.0_00698269_ERangeError]
|
|
27 May 2015 - mcdurdin - I4655 - Developer crashes when changing font settings and in code view for touch layout if not on first line [CrashID:tike.exe_9.0.487.0_0069BE51_ERangeError]
|
|
22 Jun 2015 - mcdurdin - I4765 - Double-click on message does not find source line since build 500
|
|
24 Jul 2015 - mcdurdin - I4797 - Convert to characters tool is inconsistent
|
|
03 Aug 2015 - mcdurdin - I4807 - Add Character Identifier to Keyman Developer
|
|
24 Aug 2015 - mcdurdin - I4870 - Editor does not always refresh immediately with new theming
|
|
06 Nov 2015 - mcdurdin - I4918 - Text editor is not refreshing correctly with new theme
|
|
23 Feb 2016 - mcdurdin - I4962 - Redraw not reliably working in text editor
|
|
*)
|
|
unit UframeTextEditor; // I3323 // I4797
|
|
|
|
interface
|
|
|
|
uses
|
|
System.Types,
|
|
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
|
|
Dialogs, Menus, ImgList,
|
|
MenuImgList, ExtCtrls,
|
|
|
|
{IFDEF USE_PLUSMEMO}
|
|
SyntaxHighlight,
|
|
PlusMemo,
|
|
PlusGutter,
|
|
ExtHilit,
|
|
HtmlHighlight,
|
|
pmprint,
|
|
PMSupport,
|
|
{ENDIF}
|
|
|
|
TextFileFormat, UfrmTike,
|
|
System.ImageList, KeymanDeveloperMemo,
|
|
Vcl.StdCtrls;
|
|
|
|
type
|
|
TParColourLineType = (pcltNone, pcltBreakpoint, pcltExecutionPoint, pcltError);
|
|
|
|
TframeTextEditor = class(TTIKEForm)
|
|
memo: TKeymanDeveloperMemo;
|
|
lstImages: TMenuImgList;
|
|
dlgFonts: TFontDialog;
|
|
dlgPrintSetup: TPrinterSetupDialog;
|
|
dlgFind: TFindDialog;
|
|
dlgReplace: TReplaceDialog;
|
|
lstImagesDisabled: TImageList;
|
|
tmrUpdateSelectedToken: TTimer;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure memoBeforeChange(Sender: TObject; var Txt: PWideChar);
|
|
procedure memoEnter(Sender: TObject);
|
|
procedure memoExit(Sender: TObject);
|
|
procedure memoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure memoChange(Sender: TObject);
|
|
procedure memoSelMove(Sender: TObject);
|
|
procedure memoMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure memoMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
procedure mnuPopupShowCharacterClick(Sender: TObject);
|
|
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
|
procedure dlgFindFind(Sender: TObject);
|
|
procedure dlgReplaceReplace(Sender: TObject);
|
|
procedure dlgReplaceFind(Sender: TObject);
|
|
procedure tmrUpdateSelectedTokenTimer(Sender: TObject);
|
|
procedure TntFormDestroy(Sender: TObject);
|
|
private
|
|
{$IFDEF USE_PLUSMEMO}
|
|
gutter: TPlusGutter;
|
|
SyntaxHighlighter: TSyntaxHighlighter;
|
|
pmPrinter: TPlusMemoPrinter;
|
|
highlighter: TExtHighlighter;
|
|
highlighterHTML: THtmlHighlighter;
|
|
{$ENDIF}
|
|
|
|
FLoading: Boolean;
|
|
FEditorFormat: TEditorFormat;
|
|
FOnChanged: TNotifyEvent;
|
|
FErrorPar: Integer;
|
|
FTextFileFormat: TTextFileFormat;
|
|
FindFound: Boolean;
|
|
procedure RefreshOptions;
|
|
function GetText: WideString;
|
|
procedure SetText(Value: WideString);
|
|
procedure SetEditorFormat(const Value: TEditorFormat);
|
|
procedure UpdateFontTags;
|
|
procedure Changed;
|
|
procedure UpdateState;
|
|
procedure ClearError;
|
|
procedure UpdateSelectedToken;
|
|
procedure SetCharFont(const Value: TFont);
|
|
procedure SetCodeFont(const Value: TFont);
|
|
function GetCharFont: TFont;
|
|
function GetCodeFont: TFont;
|
|
procedure SetTextFileFormat(const Value: TTextFileFormat);
|
|
function UpdateHelp(token: WideString): Boolean;
|
|
public
|
|
{ Public declarations }
|
|
procedure GetHelpTopic(var s: string); override;
|
|
procedure UpdateParColour(par: Integer; LineType: TParColourLineType);
|
|
procedure SetFocus; override;
|
|
|
|
procedure FindError(ln: Integer);
|
|
procedure FindErrorByOffset(offset: Integer); // I4083
|
|
function OffsetToLine(Offset: Integer): Integer; // I4083
|
|
|
|
function GetHelpToken: WideString;
|
|
|
|
procedure EditFind;
|
|
procedure EditFindNext;
|
|
procedure EditReplace;
|
|
|
|
procedure SyntaxColourChange;
|
|
|
|
function PrintFile(Header: WideString = ''): Boolean;
|
|
function PrintPreview(Header: WideString = ''): Boolean;
|
|
|
|
procedure LoadFromFile(AFileName: WideString); overload; // I4034
|
|
procedure LoadFromFile(AFileName: WideString; ATextFileFormat: TTextFileFormat); overload; // I4034
|
|
procedure SaveToFile(AFileName: WideString);
|
|
procedure LoadFromStream(AStream: TStream; ATextFileFormat: TTextFileFormat); overload; // I2964
|
|
procedure LoadFromStream(AStream: TStream); overload; // I2964
|
|
procedure SaveToStream(AStream: TStream);
|
|
|
|
property EditorText: WideString read GetText write SetText;
|
|
property EditorFormat: TEditorFormat read FEditorFormat write SetEditorFormat;
|
|
property OnChanged: TNotifyEvent read FOnChanged write FonChanged;
|
|
|
|
property CodeFont: TFont read GetCodeFont write SetCodeFont;
|
|
property CharFont: TFont read GetCharFont write SetCharFont;
|
|
property TextFileFormat: TTextFileFormat read FTextFileFormat write SetTextFileFormat;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
dmActionsTextEditor,
|
|
CharacterInfo,
|
|
CharMapDropTool,
|
|
keyboardparser,
|
|
KeymanDeveloperOptions,
|
|
kwhelp,
|
|
ErrorControlledRegistry,
|
|
RegistryKeys,
|
|
UfrmHelp,
|
|
UfrmMain,
|
|
Unicode,
|
|
utilstr;
|
|
|
|
{$R *.dfm}
|
|
|
|
{ TframeTextEditor }
|
|
|
|
procedure TframeTextEditor.RefreshOptions;
|
|
begin
|
|
memo.TabStops := FKeymanDeveloperOptions.IndentSize;
|
|
end;
|
|
|
|
procedure TframeTextEditor.Changed;
|
|
begin
|
|
memo.Update; // required due to bug in Delphi's TStyleHook which causes invalidated areas to be lost because // I4962
|
|
// WM_SETREDRAW is set on the window when the caption is changed, due to the {*} character being added
|
|
// to the caption. I4870 // I4918 undoes memo.Update for more performant painting
|
|
if Assigned(FOnChanged) then FOnChanged(Self);
|
|
UpdateState;
|
|
end;
|
|
|
|
procedure TframeTextEditor.FormCreate(Sender: TObject);
|
|
begin
|
|
inherited;
|
|
{$IFDEF USE_PLUSMEMO}
|
|
highlighter := TExtHighlighter.Create(Self);
|
|
highlighterHTML := THtmlHighlighter.Create(Self);
|
|
with highlighterHTML do
|
|
begin
|
|
Bracket.AltFont := False;
|
|
Bracket.Style := [fsBold];
|
|
Bracket.Background := -1;
|
|
Bracket.Foreground := clBlue;
|
|
Bracket.Cursor := crDefault;
|
|
DefaultText.AltFont := False;
|
|
DefaultText.Style := [];
|
|
DefaultText.Background := -1;
|
|
DefaultText.Foreground := clWindowText;
|
|
DefaultText.Cursor := crDefault;
|
|
HtmlKeyword.AltFont := False;
|
|
HtmlKeyword.Style := [fsBold];
|
|
HtmlKeyword.Background := -1;
|
|
HtmlKeyword.Foreground := clNavy;
|
|
HtmlKeyword.Cursor := crDefault;
|
|
HtmlTag.AltFont := False;
|
|
HtmlTag.Style := [fsItalic];
|
|
HtmlTag.Background := -1;
|
|
HtmlTag.Foreground := clGreen;
|
|
HtmlTag.Cursor := crDefault;
|
|
HtmlComment.AltFont := False;
|
|
HtmlComment.Style := [fsItalic];
|
|
HtmlComment.Background := -1;
|
|
HtmlComment.Foreground := clOlive;
|
|
HtmlComment.Cursor := crDefault;
|
|
HtmlAttribute.AltFont := False;
|
|
HtmlAttribute.Style := [];
|
|
HtmlAttribute.Background := -1;
|
|
HtmlAttribute.Foreground := clGreen;
|
|
HtmlAttribute.Cursor := crDefault;
|
|
HtmlAttributeValue.AltFont := False;
|
|
HtmlAttributeValue.Style := [];
|
|
HtmlAttributeValue.Background := -1;
|
|
HtmlAttributeValue.Foreground := clGray;
|
|
HtmlAttributeValue.Cursor := crDefault;
|
|
PerlScript.AltFont := False;
|
|
PerlScript.Style := [];
|
|
PerlScript.Background := -1;
|
|
PerlScript.Foreground := clTeal;
|
|
PerlScript.Cursor := crDefault;
|
|
ScriptTag.AltFont := False;
|
|
ScriptTag.Style := [fsBold];
|
|
ScriptTag.Background := clWindow;
|
|
ScriptTag.Foreground := clPurple;
|
|
ScriptTag.Cursor := crDefault;
|
|
ScriptContent.AltFont := True;
|
|
ScriptContent.Style := [];
|
|
ScriptContent.Background := -1;
|
|
ScriptContent.Foreground := clWindowText;
|
|
ScriptContent.Cursor := crDefault;
|
|
SpecialChars.AltFont := False;
|
|
SpecialChars.Style := [];
|
|
SpecialChars.Background := -1;
|
|
SpecialChars.Foreground := clFuchsia;
|
|
SpecialChars.Cursor := crDefault;
|
|
UnknownTag.AltFont := False;
|
|
UnknownTag.Style := [];
|
|
UnknownTag.Background := -1;
|
|
UnknownTag.Foreground := clRed;
|
|
UnknownTag.Cursor := crDefault;
|
|
XMLSyntax := False;
|
|
end;
|
|
|
|
memo.Highlighter := highlighter;
|
|
|
|
gutter := TPlusGutter.Create(Self);
|
|
gutter.Align := alLeft;
|
|
gutter.IgnoreLastLineIfEmpty := False;
|
|
gutter.PlusMemo := memo;
|
|
gutter.Parent := Self;
|
|
|
|
pmPrinter := TPlusMemoPrinter.Create(Self);
|
|
with pmPrinter do
|
|
begin
|
|
MemoToPrint := memo;
|
|
GutterWidth := 0.500000000000000000;
|
|
MarginLeft := 0.750000000000000000;
|
|
MarginRight := 0.500000000000000000;
|
|
MarginTop := 0.750000000000000000;
|
|
MarginBottom := 0.750000000000000000;
|
|
LineSpacing := -1.200000047683716000;
|
|
Footer := 'Page {p} of {P}';
|
|
HeaderYPos := 0.400000005960464400;
|
|
FooterYPos := 0.400000005960464400;
|
|
HeaderFont.Charset := ANSI_CHARSET;
|
|
HeaderFont.Color := clWindowText;
|
|
HeaderFont.Height := -13;
|
|
HeaderFont.Name := 'Arial';
|
|
HeaderFont.Style := [];
|
|
FooterFont.Charset := ANSI_CHARSET;
|
|
FooterFont.Color := clWindowText;
|
|
FooterFont.Height := -13;
|
|
FooterFont.Name := 'Arial';
|
|
FooterFont.Style := [];
|
|
NumbersFont.Charset := DEFAULT_CHARSET;
|
|
NumbersFont.Color := clWindowText;
|
|
NumbersFont.Height := -11;
|
|
NumbersFont.Name := 'Tahoma';
|
|
NumbersFont.Style := [];
|
|
PreviewTitle := 'Print preview';
|
|
PrintTitle := '{application}';
|
|
end;
|
|
|
|
SyntaxHighlighter := TSyntaxHighlighter.Create(Self);
|
|
SyntaxHighlighter.Apply(memo, highlighter);
|
|
{$ENDIF}
|
|
UpdateFontTags;
|
|
end;
|
|
|
|
type
|
|
TAccessWinControl = class(TWinControl);
|
|
|
|
procedure TframeTextEditor.FormKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
function ShiftStateToLParam(Shift: TShiftState): Integer;
|
|
const
|
|
AltMask = $20000000;
|
|
begin
|
|
if ssAlt in Shift then
|
|
Result := AltMask
|
|
else
|
|
Result := 0;
|
|
end;
|
|
var
|
|
msg: TWMKey;
|
|
begin
|
|
if (Owner is TCustomForm) and (Owner as TCustomForm).KeyPreview then
|
|
begin
|
|
msg.Msg := WM_KEYDOWN;
|
|
msg.CharCode := Key;
|
|
msg.KeyData := ShiftStateToLParam(Shift);
|
|
if TAccessWinControl(Owner).DoKeyDown(msg) then Key := 0;
|
|
end;
|
|
end;
|
|
|
|
function TframeTextEditor.GetCharFont: TFont;
|
|
begin
|
|
if FEditorFormat = efHTML
|
|
then Result := memo.Font // I1426 - script tags should be 'code' font
|
|
else Result := Memo.AltFont;
|
|
end;
|
|
|
|
function TframeTextEditor.GetCodeFont: TFont;
|
|
begin
|
|
if FEditorFormat = efHTML
|
|
then Result := Memo.AltFont // I1426 - script tags should be 'code' font
|
|
else Result := Memo.Font;
|
|
end;
|
|
|
|
function TframeTextEditor.GetText: WideString;
|
|
begin
|
|
Result := memo.Text;
|
|
end;
|
|
|
|
procedure TframeTextEditor.LoadFromFile(AFileName: WideString);
|
|
var
|
|
fs: TFileStream;
|
|
begin
|
|
FLoading := True;
|
|
try
|
|
if FileExists(AFileName) then
|
|
begin
|
|
fs := TFileStream.Create(AFileName, fmOpenRead);
|
|
try
|
|
LoadFromStream(fs);
|
|
finally
|
|
fs.Free;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TextFileFormat := tffUTF8;
|
|
memo.SetTextBuf('');
|
|
end;
|
|
memo.Modified := False;
|
|
finally
|
|
FLoading := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.LoadFromStream(AStream: TStream; ATextFileFormat: TTextFileFormat); // I2964
|
|
begin
|
|
FLoading := True;
|
|
try
|
|
TextFileFormat := ATextFileFormat;
|
|
|
|
memo.Lines.LoadFromStream(AStream, TextFileFormatToEncoding(TextFileFormat)); // I3637
|
|
memo.Modified := False; // I3082 // I3502
|
|
finally
|
|
FLoading := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.LoadFromFile(AFileName: WideString;
|
|
ATextFileFormat: TTextFileFormat); // I4034
|
|
var
|
|
fs: TFileStream;
|
|
begin
|
|
FLoading := True;
|
|
try
|
|
if FileExists(AFileName) then
|
|
begin
|
|
try
|
|
fs := TFileStream.Create(AFileName, fmOpenRead);
|
|
try
|
|
LoadFromStream(fs, ATextFileFormat);
|
|
finally
|
|
fs.Free;
|
|
end;
|
|
except
|
|
on E:EFOpenError do // I4616 // I4721
|
|
begin
|
|
ShowMessage(E.Message);
|
|
Exit;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TextFileFormat := ATextFileFormat;
|
|
memo.SetTextBuf('');
|
|
end;
|
|
memo.Modified := False;
|
|
finally
|
|
FLoading := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.LoadFromStream(AStream: TStream);
|
|
begin
|
|
FLoading := True;
|
|
try
|
|
memo.Lines.LoadFromStream(AStream); // prolog determines encoding // I3337
|
|
if memo.Encoding = TEncoding.UTF8 then // I3337 // I3636
|
|
TextFileFormat := tffUTF8
|
|
else if memo.Encoding = TEncoding.Unicode then // I3337 // I3636
|
|
TextFileFormat := tffUTF16
|
|
else
|
|
TextFileFormat := tffANSI;
|
|
memo.Modified := False;
|
|
finally
|
|
FLoading := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.SaveToFile(AFileName: WideString);
|
|
var
|
|
fs: TFileStream;
|
|
begin
|
|
fs := TFileStream.Create(AFileName, fmCreate);
|
|
with fs do
|
|
try
|
|
Self.SaveToStream(fs);
|
|
finally
|
|
Free;
|
|
end;
|
|
memo.Modified := False;
|
|
end;
|
|
|
|
|
|
procedure TframeTextEditor.SaveToStream(AStream: TStream);
|
|
begin
|
|
case FTextFileFormat of
|
|
tffANSI: memo.Lines.SaveToStream(AStream, TEncoding.Default); // I3337
|
|
tffUTF8: memo.Lines.SaveToStream(AStream, TEncoding.UTF8);
|
|
tffUTF16: memo.Lines.SaveToStream(AStream, TEncoding.Unicode);
|
|
end;
|
|
memo.Modified := False;
|
|
end;
|
|
|
|
procedure TframeTextEditor.memoBeforeChange(Sender: TObject; var Txt: PWideChar);
|
|
begin
|
|
ClearError;
|
|
end;
|
|
|
|
procedure TframeTextEditor.memoChange(Sender: TObject);
|
|
begin
|
|
if not FLoading then Changed;
|
|
end;
|
|
(*
|
|
with Source as TCharacterDragObject do
|
|
s := Text[cmimText];
|
|
{ if IsUnicode
|
|
then s := Format('U+%4.4X', [CharCode])
|
|
else s := Format('d%d', [CharCode]);}
|
|
|
|
memo.SelText := s;
|
|
|
|
Windows.SetFocus(memo.Handle);
|
|
|
|
Accept := (Source is TCharacterDragObject) and (X > 16) and (Y > 16);
|
|
if Accept then
|
|
begin
|
|
memo.SetCaretFromMouse(X - 16, Y - 16);
|
|
end;
|
|
*)
|
|
procedure TframeTextEditor.memoEnter(Sender: TObject);
|
|
begin
|
|
//frmKeymanDeveloper.RegisterToolbarClient(Self);
|
|
end;
|
|
|
|
procedure TframeTextEditor.memoExit(Sender: TObject);
|
|
begin
|
|
//frmKeymanDeveloper.UnregisterToolbarClient(Self);
|
|
end;
|
|
|
|
procedure TframeTextEditor.memoKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var
|
|
k: Integer;
|
|
pt: TPoint;
|
|
begin
|
|
if (Key=VK_Insert) and (Shift = []) then
|
|
begin
|
|
memo.Overwrite := not memo.Overwrite;
|
|
if memo.Overwrite
|
|
then frmKeymanDeveloper.barStatus.Panels[1].Text := 'Overwrite'
|
|
else frmKeymanDeveloper.barStatus.Panels[1].Text := 'Insert';
|
|
Key := 0;
|
|
end
|
|
else if (Key=VK_ESCAPE) and (Shift = []) then
|
|
begin
|
|
ClearError;
|
|
end
|
|
else if (Key=VK_APPS) and (Shift = []) then
|
|
begin
|
|
pt := memo.ClientToScreen(Point(memo.CaretX, memo.CaretY + memo.LineHeight));
|
|
modActionsTextEditor.mnuTextEditor.Popup(pt.X, pt.Y);
|
|
Key := 0;
|
|
end
|
|
else if (Key=VK_Tab) and (Shift = []) then
|
|
begin
|
|
if FKeymanDeveloperOptions.UseTabChar then Exit;
|
|
k := memo.TabStops-(memo.SelCol mod memo.TabStops);
|
|
if k = 0 then k := memo.TabStops;
|
|
memo.SelText := StringOfChar(' ', k);
|
|
Key := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.memoMouseDown(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
var
|
|
pt: TPoint;
|
|
begin
|
|
if Button = mbRight then
|
|
begin
|
|
// memo.Perform(WM_LBUTTONDOWN, 0, MAKELONG(X, Y));
|
|
// memo.Perform(WM_LBUTTONUP, 0, MAKELONG(X, Y));
|
|
pt := memo.ClientToScreen(Point(X,Y));
|
|
modActionsTextEditor.mnuTextEditor.Popup(pt.X, pt.Y);
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.memoMouseUp(Sender: TObject; Button: TMouseButton;
|
|
Shift: TShiftState; X, Y: Integer);
|
|
begin
|
|
UpdateState;
|
|
end;
|
|
|
|
procedure TframeTextEditor.memoSelMove(Sender: TObject);
|
|
begin
|
|
UpdateState;
|
|
end;
|
|
|
|
procedure TframeTextEditor.mnuPopupShowCharacterClick(Sender: TObject);
|
|
begin
|
|
//
|
|
end;
|
|
|
|
function TframeTextEditor.PrintFile(Header: WideString): Boolean;
|
|
begin
|
|
Result := False;
|
|
{$IFDEF USE_PLUSMEMO}
|
|
pmPrinter.Header := Header;
|
|
pmPrinter.Print;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TframeTextEditor.PrintPreview(Header: WideString): Boolean;
|
|
begin
|
|
{$IFDEF USE_PLUSMEMO}
|
|
pmPrinter.Header := Header;
|
|
pmPrinter.Preview;
|
|
{$ENDIF}
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TframeTextEditor.SetCharFont(const Value: TFont);
|
|
begin
|
|
if FEditorFormat = efHTML
|
|
then memo.Font := Value // I1426 - script tags should be 'code' font
|
|
else memo.AltFont := Value;
|
|
end;
|
|
|
|
procedure TframeTextEditor.SetCodeFont(const Value: TFont);
|
|
begin
|
|
if FEditorFormat = efHTML
|
|
then memo.AltFont := Value // I1426 - script tags should be 'code' font
|
|
else memo.Font := Value;
|
|
end;
|
|
|
|
procedure TframeTextEditor.SetEditorFormat(const Value: TEditorFormat);
|
|
begin
|
|
FEditorFormat := Value;
|
|
UpdateFontTags;
|
|
end;
|
|
|
|
procedure TframeTextEditor.SetFocus;
|
|
begin
|
|
memo.SetFocus;
|
|
end;
|
|
|
|
procedure TframeTextEditor.UpdateFontTags;
|
|
begin
|
|
{$IFDEF USE_PLUSMEMO}
|
|
case FEditorFormat of
|
|
efKMN: memo.Highlighter := highlighter;
|
|
efHTML: begin highlighterHTML.XMLSyntax := False; memo.Highlighter := highlighterHTML; end;
|
|
efXML: begin highlighterHTML.XMLSyntax := True; memo.Highlighter := highlighterHTML; end;
|
|
efText: memo.Highlighter := nil;
|
|
end;
|
|
memo.ApplyStartStopKeys := Assigned(memo.Highlighter);
|
|
memo.ApplyKeywords := Assigned(memo.Highlighter);
|
|
memo.ReApplyKeywords;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TframeTextEditor.SetText(Value: WideString);
|
|
var
|
|
SelLine: Integer;
|
|
SelCol: Integer;
|
|
begin
|
|
if memo.Text <> Value then // I4021
|
|
begin
|
|
FLoading := True;
|
|
try
|
|
SelLine := memo.SelLine;
|
|
SelCol := memo.SelCol;
|
|
memo.SetTextBuf(PWideChar(Value));
|
|
memo.Modified := False;
|
|
RefreshOptions;
|
|
if SelLine >= memo.Lines.Count then SelLine := memo.Lines.Count - 1; // I4499 // I4655
|
|
memo.SelLine := SelLine;
|
|
memo.SelCol := SelCol;
|
|
memo.ScrollInView;
|
|
finally
|
|
FLoading := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.SetTextFileFormat(const Value: TTextFileFormat);
|
|
begin
|
|
if FTextFileFormat <> Value then
|
|
begin
|
|
FTextFileFormat := Value;
|
|
if FTextFileFormat = tffANSI then
|
|
memo.Lines.Text := memo.Lines.Text;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.SyntaxColourChange;
|
|
begin
|
|
{$IFDEF USE_PLUSMEMO}
|
|
SyntaxHighlighter.Load;
|
|
SyntaxHighlighter.Apply(memo, highlighter);
|
|
memo.ReApplyKeywords;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TframeTextEditor.UpdateState;
|
|
begin
|
|
frmKeymanDeveloper.barStatus.Panels[0].Text := Format('Line %d, Col %d', [memo.SelLine+1, memo.SelCol+1]);
|
|
|
|
if memo.Focused then
|
|
UpdateSelectedToken;
|
|
//UpdateToolbarState;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
- Paragraph colour management and errors -
|
|
-------------------------------------------------------------------------------}
|
|
|
|
procedure TframeTextEditor.ClearError;
|
|
var
|
|
par: Integer;
|
|
begin
|
|
if FErrorPar > -1 then
|
|
begin
|
|
par := FErrorPar;
|
|
FErrorPar := -1;
|
|
UpdateParColour(par, pcltNone);
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.dlgFindFind(Sender: TObject);
|
|
begin
|
|
if not memo.FindTxt(dlgFind.FindText, frDown in dlgFind.Options,
|
|
frMatchCase in dlgFind.Options, frWholeWord in dlgFind.Options, True)
|
|
then ShowMessage(Format('Cannot find "%s"', [dlgFind.FindText]))
|
|
else memo.ScrollInView;
|
|
end;
|
|
|
|
procedure TframeTextEditor.dlgReplaceFind(Sender: TObject);
|
|
begin
|
|
if not memo.FindTxt(dlgReplace.FindText, frDown in dlgReplace.Options,
|
|
frMatchCase in dlgReplace.Options, frWholeWord in dlgReplace.Options, True) then
|
|
begin
|
|
ShowMessage(Format('Cannot find "%s"', [dlgReplace.FindText]));
|
|
FindFound := False;
|
|
end
|
|
else
|
|
begin
|
|
memo.SelLength := -Length(dlgReplace.FindText);
|
|
memo.ScrollInView;
|
|
FindFound := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.dlgReplaceReplace(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if frReplaceAll in dlgReplace.Options then
|
|
begin
|
|
memo.SelStart := 0; i := 0;
|
|
while memo.FindTxt(dlgReplace.FindText, frDown in dlgReplace.Options,
|
|
frMatchCase in dlgReplace.Options, frWholeWord in dlgReplace.Options, True) do
|
|
begin
|
|
memo.SelText := dlgReplace.ReplaceText;
|
|
Inc(i);
|
|
end;
|
|
ShowMessage(Format('Replaced %d occurrences of "%s" with "%s"',
|
|
[i, dlgReplace.FindText, dlgReplace.ReplaceText]));
|
|
FindFound := False;
|
|
end
|
|
else if frReplace in dlgReplace.Options then
|
|
begin
|
|
if not FindFound then
|
|
begin
|
|
dlgReplaceFind(dlgReplace);
|
|
Exit;
|
|
end;
|
|
if (memo.SelText = dlgReplace.FindText) then
|
|
begin
|
|
memo.SelText := dlgReplace.ReplaceText;
|
|
dlgReplaceFind(dlgReplace);
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.EditFind;
|
|
begin
|
|
if not memo.Focused then Exit;
|
|
dlgFind.Execute;
|
|
end;
|
|
|
|
procedure TframeTextEditor.EditFindNext;
|
|
begin
|
|
if not memo.Focused then Exit;
|
|
dlgFindFind(dlgFind);
|
|
end;
|
|
|
|
procedure TframeTextEditor.EditReplace;
|
|
begin
|
|
if not memo.Focused then Exit;
|
|
FindFound := False;
|
|
dlgReplace.Execute;
|
|
end;
|
|
|
|
procedure TframeTextEditor.FindError(ln: Integer);
|
|
begin
|
|
ClearError;
|
|
|
|
if (ln <= 0) or (ln >= memo.LineCount) then Exit; // I4765
|
|
|
|
memo.SelLine := ln;
|
|
memo.SelCol := 0;
|
|
memo.ScrollInView;
|
|
FErrorPar := ln;
|
|
|
|
UpdateParColour(FErrorPar, pcltError);
|
|
end;
|
|
|
|
function TframeTextEditor.OffsetToLine(Offset: Integer): Integer; // I4083
|
|
begin
|
|
Result := 0;
|
|
while (Result < memo.ParagraphCount) and (Offset > memo.PargrphOffset[Result]) do
|
|
Inc(Result);
|
|
end;
|
|
|
|
procedure TframeTextEditor.FindErrorByOffset(offset: Integer); // I4083
|
|
begin
|
|
ClearError;
|
|
|
|
if offset <= 0 then Exit;
|
|
|
|
memo.SelStart := offset;
|
|
memo.SelCol := 0;
|
|
memo.ScrollInView;
|
|
FErrorPar := memo.SelLine;
|
|
|
|
UpdateParColour(FErrorPar, pcltError);
|
|
end;
|
|
|
|
procedure TframeTextEditor.UpdateParColour(par: Integer; LineType: TParColourLineType);
|
|
{$IFDEF USE_PLUSMEMO}
|
|
var
|
|
FGColor, BGColor: TColor;
|
|
begin
|
|
if par < 0 then Exit;
|
|
case LineType of
|
|
pcltNone: begin FGColor := -1; BGColor := -1; end;
|
|
pcltBreakpoint: begin FGColor := clWhite; BGColor := clRed; end;
|
|
pcltExecutionPoint: begin FGColor := clWhite; BGColor := clBlue; end;
|
|
pcltError: begin FGColor := clWhite; BGColor := clMaroon; end;
|
|
else Exit;
|
|
end;
|
|
|
|
if (memo.ParagraphsBackground[par] <> BGColor) or (memo.ParagraphsForeground[par] <> FGColor) then
|
|
begin
|
|
memo.ParagraphsBackground[par] := BGColor;
|
|
memo.ParagraphsForeground[par] := FGColor;
|
|
end;
|
|
{$ELSE}
|
|
begin
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TframeTextEditor.GetHelpToken: WideString;
|
|
var
|
|
x, tx: Integer;
|
|
prevtoken: WideString;
|
|
begin
|
|
x := memo.SelCol+1;
|
|
|
|
if EditorFormat = efKMN
|
|
then Result := GetTokenAtCursor(memo.LinesArray[memo.SelLine], x, tx, prevtoken)
|
|
else Result := '';
|
|
|
|
if not IsValidHelpToken(Result) then
|
|
begin
|
|
Result := prevtoken;
|
|
if not IsValidHelpToken(Result) then Result := '';
|
|
end;
|
|
end;
|
|
|
|
procedure TframeTextEditor.GetHelpTopic(var s: string);
|
|
begin
|
|
if FEditorFormat <> efKMN then Exit;
|
|
|
|
s := memo.SelText;
|
|
if s = '' then
|
|
begin
|
|
{$IFDEF USE_PLUSMEMO}
|
|
memo.Delimiters := [#9, ' ', '.', ',', ';', ':', '=', '<', '>', '(', ')'];
|
|
{$ENDIF}
|
|
s := memo.CurrentWord;
|
|
end;
|
|
|
|
s := kwhelp.HelpKeyword(s);
|
|
end;
|
|
|
|
function TframeTextEditor.UpdateHelp(token: WideString): Boolean;
|
|
begin
|
|
Result := False;
|
|
if not IsValidHelpToken(token) then Exit;
|
|
if Assigned(frmHelp) and frmHelp.Showing then frmHelp.LoadHelp(token, 'KMN');
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TframeTextEditor.tmrUpdateSelectedTokenTimer(Sender: TObject);
|
|
var
|
|
prevtoken, token: WideString;
|
|
tx, x: Integer;
|
|
ch: WideString;
|
|
begin
|
|
tmrUpdateSelectedToken.Enabled := False;
|
|
|
|
x := memo.SelCol+1;
|
|
|
|
if EditorFormat = efKMN then // I4807
|
|
begin
|
|
if memo.SelLength < 0 then
|
|
Inc(x, memo.SelLength);
|
|
token := GetTokenAtCursor(memo.LinesArray[memo.SelLine], x, tx, prevtoken);
|
|
if (memo.SelText <> '') and (token <> '') then
|
|
begin
|
|
prevtoken := memo.SelText;
|
|
if (x > tx) and CharInSet(token[1], ['"', '''']) then
|
|
prevtoken := token[1] + prevtoken + token[1];
|
|
|
|
if not TKeyboardParser_Line.GetXStr(prevtoken, token) then
|
|
token := memo.SelText;
|
|
|
|
x := 1;
|
|
tx := 1;
|
|
end
|
|
else
|
|
token := GetTokenAtCursor(memo.LinesArray[memo.SelLine], x, tx, prevtoken);
|
|
end
|
|
else if memo.SelText <> '' then
|
|
begin
|
|
token := memo.SelText;
|
|
end
|
|
else
|
|
begin
|
|
ch := memo.GetTextPart(memo.SelStart-1, memo.SelStart);
|
|
if ch = '' then Exit;
|
|
|
|
if Uni_IsSurrogate2(ch[1]) then
|
|
ch := memo.GetTextPart(memo.SelStart-2, memo.SelStart)
|
|
else if Uni_IsSurrogate1(ch[1]) then
|
|
ch := memo.GetTextPart(memo.SelStart-1, memo.SelStart+1);
|
|
|
|
token := FormatUnicode(ch);
|
|
end;
|
|
|
|
UpdateCharacterMap(False, token, x, tx, memo.SelText <> ''); // I4807
|
|
if EditorFormat = efKMN then
|
|
if not UpdateHelp(token) then UpdateHelp(prevtoken);
|
|
end;
|
|
|
|
procedure TframeTextEditor.TntFormDestroy(Sender: TObject);
|
|
begin
|
|
inherited;
|
|
{$IFDEF USE_PLUSMEMO}
|
|
FreeAndNil(SyntaxHighlighter); // I2794
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TframeTextEditor.UpdateSelectedToken;
|
|
begin
|
|
tmrUpdateSelectedToken.Enabled := False;
|
|
tmrUpdateSelectedToken.Enabled := True;
|
|
end;
|
|
|
|
end.
|