Files
HeidiSQL/source/texteditor.pas

295 lines
8.3 KiB
ObjectPascal
Raw Blame History

unit texteditor;
interface
uses
Windows, Classes, Graphics, Forms, Controls, StdCtrls, VirtualTrees,
ComCtrls, ToolWin, Dialogs, SysUtils, Menus, ExtDlgs,
helpers;
{$I const.inc}
type
TfrmTextEditor = class(TForm)
memoText: TMemo;
tlbStandard: TToolBar;
btnWrap: TToolButton;
btnLoadText: TToolButton;
btnApply: TToolButton;
btnCancel: TToolButton;
lblTextLength: TLabel;
btnLinebreaks: TToolButton;
popupLinebreaks: TPopupMenu;
menuWindowsLB: TMenuItem;
menuUnixLB: TMenuItem;
menuMacLB: TMenuItem;
menuMixedLB: TMenuItem;
menuWideLB: TMenuItem;
procedure btnApplyClick(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure btnLoadTextClick(Sender: TObject);
procedure btnWrapClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure memoTextChange(Sender: TObject);
procedure memoTextKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure SelectLinebreaks(Sender: TObject);
private
{ Private declarations }
FModified: Boolean;
FStopping: Boolean;
DetectedLineBreaks,
SelectedLineBreaks: TLineBreaks;
procedure SetModified(NewVal: Boolean);
public
function GetText: String;
procedure SetText(text: String);
procedure SetMaxLength(len: integer);
procedure SetFont(font: TFont);
property Modified: Boolean read FModified write SetModified;
end;
implementation
uses main;
{$R *.dfm}
function TfrmTextEditor.GetText: String;
var
LB: String;
begin
Result := memoText.Text;
// Convert linebreaks back to selected
LB := '';
case SelectedLineBreaks of
lbsUnix: LB := LB_UNIX;
lbsMac: LB := LB_MAC;
lbsWide: LB := LB_WIDE;
end;
if LB <> '' then
Result := StringReplace(Result, CRLF, LB, [rfReplaceAll]);
end;
procedure TfrmTextEditor.SetText(text: String);
var
LB: String;
Detected: TMenuItem;
begin
DetectedLineBreaks := ScanLineBreaks(text);
case DetectedLineBreaks of
lbsWindows, lbsNone: Detected := menuWindowsLB;
lbsUnix: Detected := menuUnixLB;
lbsMac: Detected := menuMacLB;
lbsWide: Detected := menuWideLB;
lbsMixed: Detected := menuMixedLB;
else Detected := nil;
end;
if Assigned(Detected) then
SelectLineBreaks(Detected);
// Replace consistent linebreaks with CRLF so they're displayed properly
LB := '';
case DetectedLineBreaks of
lbsUnix: LB := LB_UNIX;
lbsMac: LB := LB_MAC;
lbsWide: LB := LB_WIDE;
end;
if LB <> '' then
text := StringReplace(text, LB, CRLF, [rfReplaceAll]);
if ScanNulChar(text) then begin
MessageDialog(SContainsNulCharGrid, mtInformation, [mbOK]);
text := RemoveNulChars(text);
end;
// TODO: Find out why the Delphi IDE insists hinting that this
// property is ANSI when it is in fact a WideString.
memoText.Text := text;
memoText.SelectAll;
Modified := False;
end;
procedure TfrmTextEditor.SelectLinebreaks(Sender: TObject);
var
Selected, Detected: TMenuItem;
begin
Selected := Sender as TMenuItem;
case DetectedLineBreaks of
lbsWindows, lbsNone: Detected := menuWindowsLB;
lbsUnix: Detected := menuUnixLB;
lbsMac: Detected := menuMacLB;
lbsWide: Detected := menuWideLB;
lbsMixed: Detected := menuMixedLB;
else Detected := nil;
end;
menuWindowsLB.Caption := 'Windows<77> linebreaks';
menuUnixLB.Caption := 'UNIX linebreaks';
menuMacLB.Caption := 'Mac OS linebreaks';
menuWideLB.Caption := 'Unicode linebreaks';
menuMixedLB.Caption := 'Mixed linebreaks';
Detected.Caption := Detected.Caption + ' (detected)';
Selected.Default := True;
btnLineBreaks.Hint := Selected.Caption;
btnLineBreaks.ImageIndex := Selected.ImageIndex;
if Selected = menuWindowsLB then SelectedLineBreaks := lbsWindows
else if Selected = menuUnixLB then SelectedLineBreaks := lbsUnix
else if Selected = menuMacLB then SelectedLineBreaks := lbsMac
else if Selected = menuWideLB then SelectedLineBreaks := lbsWide
else if Selected = menuMixedLB then SelectedLineBreaks := lbsMixed;
Modified := True;
end;
procedure TfrmTextEditor.SetMaxLength(len: integer);
begin
// Input: Length in number of bytes.
memoText.MaxLength := len;
end;
procedure TfrmTextEditor.SetFont(font: TFont);
begin
memoText.Font.Name := font.Name;
memoText.Font.Size := font.Size;
end;
procedure TfrmTextEditor.FormCreate(Sender: TObject);
begin
InheritFont(Font);
end;
procedure TfrmTextEditor.FormDestroy(Sender: TObject);
begin
OpenRegistry;
MainReg.WriteInteger( REGNAME_EDITOR_WIDTH, Width );
MainReg.WriteInteger( REGNAME_EDITOR_HEIGHT, Height );
MainReg.WriteBool(REGNAME_EDITOR_WORDWRAP, btnWrap.Down);
end;
procedure TfrmTextEditor.FormShow(Sender: TObject);
begin
// Restore form dimensions
Width := GetRegValue(REGNAME_EDITOR_WIDTH, DEFAULT_EDITOR_WIDTH);
Height := GetRegValue(REGNAME_EDITOR_HEIGHT, DEFAULT_EDITOR_HEIGHT);
if GetRegValue(REGNAME_EDITOR_WORDWRAP, btnWrap.Down) then
btnWrap.Click;
// Fix label position:
lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2;
SetWindowSizeGrip(Handle, True);
memoText.SetFocus;
end;
procedure TfrmTextEditor.memoTextKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
begin
case Key of
// Cancel by Escape
VK_ESCAPE: btnCancelClick(Sender);
// Apply changes and end editing by Ctrl + Enter
VK_RETURN: if ssCtrl in Shift then btnApplyClick(Sender);
Ord('a'), Ord('A'): if (ssCtrl in Shift) and (not (ssAlt in Shift)) then Mainform.actSelectAllExecute(Sender);
end;
end;
procedure TfrmTextEditor.btnWrapClick(Sender: TObject);
var
WasModified: Boolean;
begin
Screen.Cursor := crHourglass;
// Changing the scrollbars invoke the OnChange event. We avoid thinking the text was really modified.
WasModified := Modified;
if memoText.ScrollBars = ssBoth then
memoText.ScrollBars := ssVertical
else
memoText.ScrollBars := ssBoth;
TToolbutton(Sender).Down := memoText.ScrollBars = ssVertical;
Modified := WasModified;
Screen.Cursor := crDefault;
end;
procedure TfrmTextEditor.btnLoadTextClick(Sender: TObject);
var
d: TOpenTextFileDialog;
begin
d := TOpenTextFileDialog.Create(Self);
d.Filter := 'Textfiles (*.txt)|*.txt|All files (*.*)|*.*';
d.FilterIndex := 0;
d.Encodings.Assign(MainForm.FileEncodings);
d.EncodingIndex := 0;
if d.Execute then try
Screen.Cursor := crHourglass;
memoText.Text := ReadTextFile(d.FileName, MainForm.GetEncodingByName(d.Encodings[d.EncodingIndex]));
if (memoText.MaxLength > 0) and (Length(memoText.Text) > memoText.MaxLength) then
memoText.Text := copy(memoText.Text, 0, memoText.MaxLength);
finally
Screen.Cursor := crDefault;
end;
d.Free;
end;
procedure TfrmTextEditor.btnCancelClick(Sender: TObject);
begin
if FStopping then
Exit;
FStopping := True;
TCustomVirtualStringTree(Owner).CancelEditNode;
end;
procedure TfrmTextEditor.FormClose(Sender: TObject; var Action: TCloseAction);
var
DoPost: Boolean;
begin
if FStopping then
Exit;
FStopping := True;
if Modified then
DoPost := MessageDialog('Apply modifications?', mtConfirmation, [mbYes, mbNo]) = mrYes
else
DoPost := False;
if DoPost then
TCustomVirtualStringTree(Owner).EndEditNode
else
TCustomVirtualStringTree(Owner).CancelEditNode;
end;
procedure TfrmTextEditor.btnApplyClick(Sender: TObject);
begin
FStopping := True;
TCustomVirtualStringTree(Owner).EndEditNode;
end;
procedure TfrmTextEditor.memoTextChange(Sender: TObject);
begin
lblTextLength.Caption := FormatNumber(Length(memoText.Text)) + ' characters.';
if memoText.MaxLength > 0 then
lblTextLength.Caption := lblTextLength.Caption + ' (Max: '+FormatNumber(memoText.MaxLength)+')';
Modified := True;
end;
procedure TfrmTextEditor.SetModified(NewVal: Boolean);
begin
if FModified <> NewVal then begin
FModified := NewVal;
btnApply.Enabled := FModified;
end;
end;
end.