diff --git a/heidisql.lpi b/heidisql.lpi
index b6ac62e9..773e4b92 100644
--- a/heidisql.lpi
+++ b/heidisql.lpi
@@ -250,6 +250,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/heidisql.lpr b/heidisql.lpr
index d247c413..9e933dc6 100644
--- a/heidisql.lpr
+++ b/heidisql.lpr
@@ -19,8 +19,8 @@ uses
dbstructures.sqlite, change_password, loginform, data_sorting, extra_controls,
column_selection, loaddata, csv_detector, createdatabase, editvar, copytable,
exportgrid, usermanager, selectdbobject, reformatter, searchreplace,
- connections, jsonregistry, sqlhelp, updatecheck, insertfiles {, printlist (EnablePrint not defined) }
- ;
+ connections, jsonregistry, sqlhelp, updatecheck, insertfiles, texteditor,
+ customize_highlighter;
{$R *.res}
{.$R resources.rc}
diff --git a/source/customize_highlighter.lfm b/source/customize_highlighter.lfm
new file mode 100644
index 00000000..e27049cb
--- /dev/null
+++ b/source/customize_highlighter.lfm
@@ -0,0 +1,147 @@
+object frmCustomizeHighlighter: TfrmCustomizeHighlighter
+ Left = 0
+ Height = 311
+ Top = 0
+ Width = 551
+ BorderStyle = bsDialog
+ Caption = 'Customize highlighter'
+ ClientHeight = 311
+ ClientWidth = 551
+ Color = clBtnFace
+ DesignTimePPI = 120
+ Font.Color = clWindowText
+ Font.Height = -15
+ Font.Name = 'Segoe UI'
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ OnShow = FormShow
+ Position = poOwnerFormCenter
+ object lblBackground: TLabel
+ Left = 199
+ Height = 20
+ Top = 46
+ Width = 82
+ Caption = 'Background:'
+ end
+ object lblForeground: TLabel
+ Left = 199
+ Height = 20
+ Top = 81
+ Width = 80
+ Caption = 'Foreground:'
+ end
+ object lblStyle: TLabel
+ Left = 199
+ Height = 20
+ Top = 112
+ Width = 35
+ Caption = 'Style:'
+ end
+ object comboHighlighter: TComboBox
+ Left = 10
+ Height = 28
+ Top = 10
+ Width = 181
+ ItemHeight = 20
+ Sorted = True
+ Style = csDropDownList
+ TabOrder = 0
+ OnSelect = comboHighlighterSelect
+ end
+ object listboxAttributes: TListBox
+ Left = 10
+ Height = 216
+ Top = 46
+ Width = 181
+ ItemHeight = 0
+ TabOrder = 1
+ OnClick = listboxAttributesClick
+ end
+ object chkBold: TCheckBox
+ Left = 346
+ Height = 24
+ Top = 112
+ Width = 195
+ Anchors = [akTop, akLeft, akRight]
+ Caption = 'Bold'
+ TabOrder = 4
+ OnClick = Modified
+ end
+ object chkItalic: TCheckBox
+ Left = 346
+ Height = 24
+ Top = 141
+ Width = 195
+ Anchors = [akTop, akLeft, akRight]
+ Caption = 'Italic'
+ TabOrder = 5
+ OnClick = Modified
+ end
+ object btnCancel: TButton
+ Left = 346
+ Height = 31
+ Top = 270
+ Width = 94
+ Anchors = [akRight, akBottom]
+ Cancel = True
+ Caption = 'Cancel'
+ ModalResult = 2
+ TabOrder = 7
+ end
+ object btnOK: TButton
+ Left = 245
+ Height = 31
+ Top = 270
+ Width = 94
+ Anchors = [akRight, akBottom]
+ Caption = 'OK'
+ Default = True
+ ModalResult = 1
+ TabOrder = 6
+ OnClick = SaveSettings
+ end
+ object editBackground: TEditButton
+ Left = 346
+ Height = 28
+ Top = 42
+ Width = 195
+ Anchors = [akTop, akLeft, akRight]
+ ButtonHint = 'Color picker'
+ ButtonWidth = 29
+ Images = MainForm.ImageListIcons8
+ ImageIndex = 33
+ MaxLength = 0
+ NumGlyphs = 1
+ OnButtonClick = editColorRightButtonClick
+ OnExit = Modified
+ PasswordChar = #0
+ TabOrder = 2
+ end
+ object editForeground: TEditButton
+ Left = 346
+ Height = 28
+ Top = 78
+ Width = 195
+ Anchors = [akTop, akLeft, akRight]
+ ButtonHint = 'Color picker'
+ ButtonWidth = 29
+ Images = MainForm.ImageListIcons8
+ ImageIndex = 33
+ MaxLength = 0
+ NumGlyphs = 1
+ OnButtonClick = editColorRightButtonClick
+ OnExit = Modified
+ PasswordChar = #0
+ TabOrder = 3
+ end
+ object btnApply: TButton
+ Left = 447
+ Height = 31
+ Top = 270
+ Width = 94
+ Anchors = [akRight, akBottom]
+ Caption = 'Apply'
+ TabOrder = 8
+ OnClick = SaveSettings
+ end
+end
diff --git a/source/customize_highlighter.pas b/source/customize_highlighter.pas
new file mode 100644
index 00000000..adab9c88
--- /dev/null
+++ b/source/customize_highlighter.pas
@@ -0,0 +1,198 @@
+unit customize_highlighter;
+
+{$mode delphi}{$H+}
+
+interface
+
+uses
+ SysUtils, Variants, Classes, Graphics, EditBtn,
+ Controls, Forms, Dialogs, StdCtrls, ExtCtrls, GraphUtil, Math,
+ StrUtils, SynEditHighlighter, apphelpers, extra_controls;
+
+type
+ TfrmCustomizeHighlighter = class(TExtForm)
+ comboHighlighter: TComboBox;
+ listboxAttributes: TListBox;
+ lblBackground: TLabel;
+ lblForeground: TLabel;
+ lblStyle: TLabel;
+ chkBold: TCheckBox;
+ chkItalic: TCheckBox;
+ btnCancel: TButton;
+ btnOK: TButton;
+ editBackground: TEditButton;
+ editForeground: TEditButton;
+ btnApply: TButton;
+ procedure listboxAttributesClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure comboHighlighterSelect(Sender: TObject);
+ procedure SaveSettings(Sender: TObject);
+ procedure editColorRightButtonClick(Sender: TObject);
+ procedure Modified(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure FormShow(Sender: TObject);
+ private
+ { Private-Deklarationen }
+ FHighlighter: TSynCustomHighlighter;
+ FAttr: TSynHighlighterAttributes;
+ FOnChange: TNotifyEvent;
+ procedure SetFriendlyLanguageName(FriendlyLanguageName: String);
+ function GetFriendlyLanguageName: String;
+ public
+ { Public-Deklarationen }
+ property FriendlyLanguageName: String read GetFriendlyLanguageName write SetFriendlyLanguageName;
+ property OnChange: TNotifyEvent read FOnChange write FOnChange;
+ end;
+
+
+implementation
+
+uses main;
+
+{$R *.lfm}
+
+procedure TfrmCustomizeHighlighter.SaveSettings(Sender: TObject);
+begin
+ // Save highlighter settings
+ FHighlighter.SaveToFile(AppSettings.DirnameHighlighters + FHighlighter.LanguageName + '.ini');
+ if Assigned(FOnChange) then
+ FOnChange(Self);
+end;
+
+procedure TfrmCustomizeHighlighter.Modified(Sender: TObject);
+begin
+ // Apply modification to current attribute
+ // Silence exception caused by invalid color strings
+ FAttr.Background := StringToColorDef(editBackground.Text, clNone);
+ FAttr.Foreground := StringToColorDef(editForeground.Text, clNone);
+ if chkBold.Checked then
+ FAttr.Style := FAttr.Style + [fsBold]
+ else
+ FAttr.Style := FAttr.Style - [fsBold];
+ if chkItalic.Checked then
+ FAttr.Style := FAttr.Style + [fsItalic]
+ else
+ FAttr.Style := FAttr.Style - [fsItalic];
+end;
+
+procedure TfrmCustomizeHighlighter.comboHighlighterSelect(Sender: TObject);
+var
+ i: Integer;
+ Highlighters: TSynHighlighterList;
+ h: TSynCustomHighlighterClass;
+begin
+ // Highlighter selected
+ listboxAttributes.Clear;
+ if Assigned(FHighlighter) then
+ FHighlighter.Free;
+ Highlighters := SynEditHighlighter.GetPlaceableHighlighters;
+ for i:=0 to Highlighters.Count-1 do begin
+ if Highlighters[i].GetLanguageName = comboHighlighter.Text then begin
+ FHighlighter := Highlighters[i].Create(Self);
+ Break;
+ end;
+ end;
+ FHighlighter.LoadFromFile(AppSettings.DirnameHighlighters + FHighlighter.GetLanguageName + '.ini');
+ for i:=0 to FHighlighter.AttrCount-1 do begin
+ listboxAttributes.Items.Add(FHighlighter.Attribute[i].Name);
+ end;
+end;
+
+procedure TfrmCustomizeHighlighter.editColorRightButtonClick(
+ Sender: TObject);
+var
+ Dialog: TColorDialog;
+ Edit: TEditButton;
+begin
+ // Color picker
+ Edit := Sender as TEditButton;
+ Dialog := TColorDialog.Create(Self);
+ //Dialog.Options := [cdFullOpen, cdAnyColor];
+ Dialog.Color := StringToColorDef(Edit.Text, clNone);
+ if Dialog.Execute then begin
+ Edit.Text := ColorToString(Dialog.Color);
+ end;
+ Dialog.Free;
+ Modified(Sender);
+end;
+
+procedure TfrmCustomizeHighlighter.FormCreate(Sender: TObject);
+var
+ Highlighters: TSynHighlighterList;
+ i: Integer;
+begin
+ // Form created
+ FHighlighter := nil;
+ FAttr := nil;
+ FOnChange := nil;
+ Highlighters := SynEditHighlighter.GetPlaceableHighlighters;
+ for i:=0 to Highlighters.Count-1 do begin
+ comboHighlighter.Items.Add(Highlighters[i].GetLanguageName);
+ end;
+end;
+
+procedure TfrmCustomizeHighlighter.FormDestroy(Sender: TObject);
+begin
+ // Form destroyed
+ if Assigned(FHighlighter) then
+ FHighlighter.Free;
+ // causes an exception when closing:
+ //if Assigned(FAttr) then
+ // FAttr.Free;
+end;
+
+procedure TfrmCustomizeHighlighter.FormShow(Sender: TObject);
+begin
+ // Ensure controls are disabled as long as no attribute is selected
+ listboxAttributes.OnClick(Sender);
+end;
+
+procedure TfrmCustomizeHighlighter.listboxAttributesClick(Sender: TObject);
+var
+ i: Integer;
+ AttrSelected: Boolean;
+begin
+ // Attribute selected
+ FAttr := nil;
+ if listboxAttributes.ItemIndex > -1 then begin
+ for i:=0 to FHighlighter.AttrCount-1 do begin
+ if listboxAttributes.Items[listboxAttributes.ItemIndex] = FHighlighter.Attribute[i].Name then begin
+ FAttr := FHighlighter.Attribute[i];
+ end;
+ end;
+ end;
+ // Enable/disable controls
+ AttrSelected := FAttr <> nil;
+ editBackground.Enabled := AttrSelected;
+ editForeground.Enabled := AttrSelected;
+ chkBold.Enabled := AttrSelected;
+ chkItalic.Enabled := AttrSelected;
+ // Overtake values
+ if AttrSelected then begin
+ editBackground.Text := IfThen(FAttr.Background <> clNone, ColorToString(FAttr.Background), '');
+ editForeground.Text := IfThen(FAttr.Foreground <> clNone, ColorToString(FAttr.Foreground), '');
+ chkBold.Checked := fsBold in FAttr.Style;
+ chkItalic.Checked := fsItalic in FAttr.Style;
+ end
+ else begin
+ editBackground.Text := '';
+ editForeground.Text := '';
+ chkBold.Checked := False;
+ chkItalic.Checked := False;
+ end;
+end;
+
+procedure TfrmCustomizeHighlighter.SetFriendlyLanguageName(FriendlyLanguageName: String);
+begin
+ // Set current highlighter by its language name
+ comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(FriendlyLanguageName);
+ comboHighlighter.OnSelect(comboHighlighter);
+end;
+
+function TfrmCustomizeHighlighter.GetFriendlyLanguageName: String;
+begin
+ Result := FHighlighter.GetLanguageName;
+end;
+
+
+end.
diff --git a/source/main.pas b/source/main.pas
index eb74cd66..b2d864d0 100644
--- a/source/main.pas
+++ b/source/main.pas
@@ -1418,7 +1418,7 @@ implementation
uses
FileInfo, winpeimagereader, elfreader, machoreader, About, data_sorting, column_selection, loaddata, editvar,
copytable, csv_detector, exportgrid, usermanager, selectdbobject, reformatter, connections, sqlhelp, updatecheck,
- insertfiles;
+ insertfiles, texteditor;
{$R *.lfm}
@@ -12995,9 +12995,9 @@ begin
end;
if (not Assigned(Result)) and QueryTabs.HasActiveTab then
Result := QueryTabs.ActiveMemo;
- //if (not Assigned(Result)) and (Screen.ActiveForm is TfrmTextEditor) then begin
- // Result := TfrmTextEditor(Screen.ActiveForm).MemoText;
- //end;
+ if (not Assigned(Result)) and (Screen.ActiveForm is TfrmTextEditor) then begin
+ Result := TfrmTextEditor(Screen.ActiveForm).MemoText;
+ end;
end;
diff --git a/source/searchreplace.pas b/source/searchreplace.pas
index e8158309..7e5e989c 100644
--- a/source/searchreplace.pas
+++ b/source/searchreplace.pas
@@ -8,7 +8,7 @@ uses
SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls,
ExtCtrls, SynEdit, SynEditTypes, laz.VirtualTrees, RegExpr,
SynEditRegexSearch, SynEditMiscClasses, SynEditSearch, extra_controls,
- Menus{, texteditor};
+ Menus, texteditor;
type
TfrmSearchReplace = class(TExtForm)
@@ -123,7 +123,7 @@ begin
AnySynMemo := MainForm.ActiveSynMemo(True);
if Assigned(AnySynMemo) then begin
IsEditorWritable := not AnySynMemo.ReadOnly; // Support views and procedure editors
- IsGridTextEditor := False; //GetParentForm(AnySynMemo) is TfrmTextEditor; // Support grid text editor, read-only or not
+ IsGridTextEditor := GetParentForm(AnySynMemo) is TfrmTextEditor; // Support grid text editor, read-only or not
if IsEditorWritable or IsGridTextEditor then
UsedSynMemo := AnySynMemo;
end;
diff --git a/source/texteditor.lfm b/source/texteditor.lfm
new file mode 100644
index 00000000..a360024c
--- /dev/null
+++ b/source/texteditor.lfm
@@ -0,0 +1,316 @@
+object frmTextEditor: TfrmTextEditor
+ Left = 0
+ Height = 191
+ Top = 0
+ Width = 602
+ Caption = 'Text editor'
+ ClientHeight = 191
+ ClientWidth = 602
+ Color = clBtnFace
+ Constraints.MinHeight = 125
+ Constraints.MinWidth = 375
+ DesignTimePPI = 120
+ OnClose = FormClose
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ OnShow = FormShow
+ Position = poMainFormCenter
+ LCLVersion = '3.8.0.0'
+ object Panel1: TPanel
+ Left = 0
+ Height = 28
+ Top = 125
+ Width = 472
+ Align = alBottom
+ BevelOuter = bvNone
+ Caption = 'Panel1'
+ ClientHeight = 28
+ ClientWidth = 472
+ ParentBackground = False
+ TabOrder = 0
+ object lblTextLength: TLabel
+ Left = 409
+ Height = 16
+ Top = 3
+ Width = 76
+ Align = alLeft
+ Caption = 'lblTextLength'
+ Layout = tlCenter
+ ParentBidiMode = False
+ end
+ object tlbStandard: TToolBar
+ Left = 0
+ Height = 22
+ Top = 0
+ Width = 261
+ Align = alLeft
+ AutoSize = True
+ Caption = 'tlbStandard'
+ ParentShowHint = False
+ ShowHint = True
+ TabOrder = 0
+ Wrapable = False
+ object btnWrap: TToolButton
+ Left = 0
+ Hint = 'Wrap long lines'
+ Top = 0
+ Caption = 'Wrap long lines'
+ ImageIndex = 62
+ OnClick = btnWrapClick
+ end
+ object btnLinebreaks: TToolButton
+ Left = 29
+ Top = 0
+ Caption = 'Linebreaks'
+ DropdownMenu = popupLinebreaks
+ ImageIndex = 123
+ Style = tbsDropDown
+ end
+ object btnLoadText: TToolButton
+ Left = 81
+ Hint = 'Load textfile'
+ Top = 0
+ Caption = 'Load textfile'
+ ImageIndex = 52
+ OnClick = btnLoadTextClick
+ end
+ object btnCancel: TToolButton
+ Left = 110
+ Hint = 'Cancel'
+ Top = 0
+ Caption = 'Cancel'
+ ImageIndex = 26
+ OnClick = btnCancelClick
+ end
+ object btnApply: TToolButton
+ Left = 139
+ Hint = 'Apply changes'
+ Top = 0
+ Caption = 'Apply changes'
+ ImageIndex = 55
+ OnClick = btnApplyClick
+ end
+ object btnSeparator1: TToolButton
+ Left = 168
+ Top = 0
+ Width = 10
+ Caption = 'btnSeparator1'
+ ImageIndex = 60
+ Style = tbsSeparator
+ end
+ object btnSearchFind: TToolButton
+ Left = 178
+ Top = 0
+ Action = MainForm.actQueryFind
+ end
+ object btnSearchFindNext: TToolButton
+ Left = 206
+ Top = 0
+ Action = MainForm.actQueryFindAgain
+ end
+ object btnSearchReplace: TToolButton
+ Left = 235
+ Top = 0
+ Action = MainForm.actQueryReplace
+ end
+ object ToolButton1: TToolButton
+ Left = 264
+ Top = 0
+ Width = 10
+ Caption = 'ToolButton1'
+ ImageIndex = 60
+ Style = tbsSeparator
+ end
+ object btnCustomizeHighlighter: TToolButton
+ Left = 274
+ Top = 0
+ Caption = 'Customize highlighter'
+ DropdownMenu = popupHighlighter
+ ImageIndex = 39
+ OnClick = btnCustomizeHighlighterClick
+ Style = tbsDropDown
+ end
+ end
+ object comboHighlighter: TComboBox
+ Left = 261
+ Height = 22
+ Top = 0
+ Width = 181
+ Align = alLeft
+ ItemHeight = 0
+ Sorted = True
+ Style = csDropDownList
+ TabOrder = 1
+ OnSelect = comboHighlighterSelect
+ end
+ end
+ inline MemoText: TSynEdit
+ Left = 0
+ Height = 131
+ Top = 0
+ Width = 482
+ Align = alClient
+ Font.Color = clWindowText
+ Font.Height = -16
+ Font.Name = 'Courier New'
+ Font.Pitch = fpFixed
+ Font.Quality = fqNonAntialiased
+ ParentColor = False
+ ParentFont = False
+ PopupMenu = popupEditor
+ TabOrder = 1
+ OnClick = MemoTextClick
+ OnKeyDown = MemoTextKeyDown
+ Gutter.Width = 72
+ Gutter.MouseActions = <>
+ RightGutter.Width = 0
+ RightGutter.MouseActions = <>
+ Keystrokes = <>
+ MouseActions = <>
+ MouseTextActions = <>
+ MouseSelActions = <>
+ Lines.Strings = (
+ 'MemoText'
+ )
+ Options = [eoAutoIndent, eoGroupUndo, eoShowScrollHint, eoSmartTabs, eoTabIndent, eoTabsToSpaces, eoDragDropEditing]
+ MouseOptions = [emDragDropEditing]
+ VisibleSpecialChars = [vscSpace, vscTabAtLast]
+ RightEdge = 0
+ SelectedColor.BackPriority = 50
+ SelectedColor.ForePriority = 50
+ SelectedColor.FramePriority = 50
+ SelectedColor.BoldPriority = 50
+ SelectedColor.ItalicPriority = 50
+ SelectedColor.UnderlinePriority = 50
+ SelectedColor.StrikeOutPriority = 50
+ BracketHighlightStyle = sbhsBoth
+ BracketMatchColor.Background = clNone
+ BracketMatchColor.Foreground = clNone
+ BracketMatchColor.Style = [fsBold]
+ FoldedCodeColor.Background = clNone
+ FoldedCodeColor.Foreground = clGray
+ FoldedCodeColor.FrameColor = clGray
+ MouseLinkColor.Background = clNone
+ MouseLinkColor.Foreground = clBlue
+ LineHighlightColor.Background = clNone
+ LineHighlightColor.Foreground = clNone
+ OnChange = MemoTextChange
+ inline SynLeftGutterPartList1: TSynGutterPartList
+ object SynGutterMarks1: TSynGutterMarks
+ Width = 30
+ MouseActions = <>
+ end
+ object SynGutterLineNumber1: TSynGutterLineNumber
+ Width = 21
+ MouseActions = <>
+ MarkupInfo.Background = clBtnFace
+ MarkupInfo.Foreground = clNone
+ DigitCount = 2
+ ShowOnlyLineNumbersMultiplesOf = 1
+ ZeroStart = False
+ LeadingZeros = False
+ end
+ object SynGutterChanges1: TSynGutterChanges
+ Width = 5
+ MouseActions = <>
+ ModifiedColor = 59900
+ SavedColor = clGreen
+ end
+ object SynGutterSeparator1: TSynGutterSeparator
+ Width = 3
+ MouseActions = <>
+ MarkupInfo.Background = clWhite
+ MarkupInfo.Foreground = clGray
+ end
+ object SynGutterCodeFolding1: TSynGutterCodeFolding
+ Width = 13
+ MouseActions = <>
+ MarkupInfo.Background = clNone
+ MarkupInfo.Foreground = clGray
+ MouseActionsExpanded = <>
+ MouseActionsCollapsed = <>
+ end
+ end
+ end
+ object popupLinebreaks: TPopupMenu
+ Left = 10
+ Top = 20
+ object menuWindowsLB: TMenuItem
+ Caption = 'Windows linebreaks'
+ ImageIndex = 123
+ OnClick = SelectLinebreaks
+ end
+ object menuUnixLB: TMenuItem
+ Caption = 'UNIX linebreaks'
+ ImageIndex = 125
+ OnClick = SelectLinebreaks
+ end
+ object menuMacLB: TMenuItem
+ Caption = 'Mac OS linebreaks'
+ ImageIndex = 124
+ OnClick = SelectLinebreaks
+ end
+ object menuWideLB: TMenuItem
+ Caption = 'Unicode linebreaks'
+ ImageIndex = 68
+ OnClick = SelectLinebreaks
+ end
+ object menuMixedLB: TMenuItem
+ Caption = 'Mixed linebreaks'
+ ImageIndex = 122
+ OnClick = SelectLinebreaks
+ end
+ end
+ object TimerMemoChange: TTimer
+ Interval = 200
+ OnTimer = TimerMemoChangeTimer
+ Left = 150
+ Top = 20
+ end
+ object popupEditor: TPopupMenu
+ Left = 300
+ Top = 20
+ object Selectall1: TMenuItem
+ Action = MainForm.actSelectAll
+ end
+ object Copy1: TMenuItem
+ Action = MainForm.actCopy
+ end
+ object Paste1: TMenuItem
+ Action = MainForm.actPaste
+ end
+ object Undo1: TMenuItem
+ Action = MainForm.actUndo
+ end
+ object N1: TMenuItem
+ Caption = '-'
+ end
+ object Findtext1: TMenuItem
+ Action = MainForm.actQueryFind
+ end
+ object Findorreplaceagain1: TMenuItem
+ Action = MainForm.actQueryFindAgain
+ end
+ object Replacetext1: TMenuItem
+ Action = MainForm.actQueryReplace
+ end
+ end
+ object popupHighlighter: TPopupMenu
+ Left = 440
+ Top = 40
+ object menuCustomizeHighlighter: TMenuItem
+ Caption = 'Customize highlighter'
+ ImageIndex = 39
+ OnClick = btnCustomizeHighlighterClick
+ end
+ object menuFormatCodeOnce: TMenuItem
+ Caption = 'Format code once'
+ OnClick = menuFormatCodeOnceClick
+ end
+ object menuAlwaysFormatCode: TMenuItem
+ AutoCheck = True
+ Caption = 'Always format code'
+ OnClick = menuAlwaysFormatCodeClick
+ end
+ end
+end
diff --git a/source/texteditor.pas b/source/texteditor.pas
new file mode 100644
index 00000000..4718d10f
--- /dev/null
+++ b/source/texteditor.pas
@@ -0,0 +1,539 @@
+unit texteditor;
+
+interface
+
+uses
+ Classes, Graphics, Forms, Controls, StdCtrls, laz.VirtualTrees,
+ ComCtrls, ToolWin, Dialogs, SysUtils, Menus, ExtDlgs, LCLType,
+ apphelpers, ActnList, extra_controls,
+ ExtCtrls, dbconnection, SynEdit, SynEditHighlighter, customize_highlighter,
+ reformatter,
+
+ SynHighlighterBat,
+ SynHighlighterCpp, SynHighlighterCss,
+ SynHighlighterHashEntries, SynHighlighterHtml,
+ SynHighlighterIni, SynHighlighterJScript,
+ SynHighlighterJava,
+ SynHighlighterPHP, SynHighlighterPas, SynHighlighterPerl,
+ SynHighlighterPython,
+ SynHighlighterSQL,
+ SynHighlighterTeX, SynHighlighterUNIXShellScript,
+ SynHighlighterVB,
+ SynHighlighterXML
+ ;
+
+{$I const.inc}
+
+type
+ TfrmTextEditor = class(TExtForm)
+ Panel1: TPanel;
+ 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;
+ btnSearchFind: TToolButton;
+ btnSearchReplace: TToolButton;
+ btnSearchFindNext: TToolButton;
+ btnSeparator1: TToolButton;
+ TimerMemoChange: TTimer;
+ comboHighlighter: TComboBox;
+ MemoText: TSynEdit;
+ popupEditor: TPopupMenu;
+ Copy1: TMenuItem;
+ Paste1: TMenuItem;
+ Selectall1: TMenuItem;
+ Undo1: TMenuItem;
+ Findtext1: TMenuItem;
+ Findorreplaceagain1: TMenuItem;
+ Replacetext1: TMenuItem;
+ N1: TMenuItem;
+ ToolButton1: TToolButton;
+ btnCustomizeHighlighter: TToolButton;
+ popupHighlighter: TPopupMenu;
+ menuCustomizeHighlighter: TMenuItem;
+ menuFormatCodeOnce: TMenuItem;
+ menuAlwaysFormatCode: 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 MemoTextClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure SelectLinebreaks(Sender: TObject);
+ procedure TimerMemoChangeTimer(Sender: TObject);
+ procedure comboHighlighterSelect(Sender: TObject);
+ procedure btnCustomizeHighlighterClick(Sender: TObject);
+ procedure menuFormatCodeOnceClick(Sender: TObject);
+ procedure menuAlwaysFormatCodeClick(Sender: TObject);
+ private
+ { Private declarations }
+ FModified: Boolean;
+ FClosingByApplyButton: Boolean;
+ FClosingByCancelButton: Boolean;
+ FDetectedLineBreaks,
+ FSelectedLineBreaks: TLineBreaks;
+ FMaxLength: Integer;
+ FTableColumn: TTableColumn;
+ FHighlighter: TSynCustomHighlighter;
+ FHighlighterFormatters: TStringList;
+ procedure SetModified(NewVal: Boolean);
+ procedure CustomizeHighlighterChanged(Sender: TObject);
+ public
+ function GetText: String;
+ procedure SetText(text: String);
+ procedure SetTitleText(Title: String);
+ procedure SetMaxLength(len: integer);
+ procedure SetFont(font: TFont);
+ property Modified: Boolean read FModified write SetModified;
+ property TableColumn: TTableColumn read FTableColumn write FTableColumn;
+ end;
+
+
+implementation
+
+uses main;
+
+{$R *.lfm}
+
+
+function TfrmTextEditor.GetText: String;
+var
+ LB: String;
+begin
+ Result := MemoText.Text;
+ // Convert linebreaks back to selected
+ LB := GetLineBreak(FSelectedLineBreaks);
+ if LB <> CRLF then
+ Result := StringReplace(Result, CRLF, LB, [rfReplaceAll]);
+end;
+
+
+procedure TfrmTextEditor.SetText(text: String);
+var
+ Detected, Item: TMenuItem;
+begin
+ // Apply text string, and detect type of line breaks in it
+ FDetectedLineBreaks := ScanLineBreaks(text);
+ Detected := nil;
+ if FDetectedLineBreaks = lbsNone then
+ FDetectedLineBreaks := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle));
+ for Item in popupLinebreaks.Items do begin
+ if Item.Tag = Integer(FDetectedLineBreaks) then begin
+ Detected := Item;
+ end;
+ end;
+ if Assigned(Detected) then
+ SelectLineBreaks(Detected);
+ if (Length(text) > SIZE_MB) then begin
+ MainForm.LogSQL(_('Auto-disabling wordwrap for large text'));
+ btnWrap.Enabled := False;
+ end else begin
+ btnWrap.Enabled := True;
+ end;
+
+ MemoText.Text := text;
+ MemoText.SelectAll;
+ Modified := False;
+end;
+
+
+procedure TfrmTextEditor.SetTitleText(Title: String);
+begin
+ // Add column name to window title bar
+ if Title <> '' then
+ Caption := Title + ' - ' + Caption;
+end;
+
+
+procedure TfrmTextEditor.TimerMemoChangeTimer(Sender: TObject);
+var
+ MaxLen, CursorPos: String;
+begin
+ // Timer based onchange handler, so we don't scan the whole text on every typed character
+ TimerMemoChange.Enabled := False;
+ if FMaxLength = 0 then
+ MaxLen := '?'
+ else
+ MaxLen := FormatNumber(FMaxLength);
+ CursorPos := FormatNumber(MemoText.CaretY) + ':' + FormatNumber(MemoText.CaretX);
+ lblTextLength.Caption := f_('%s characters (max: %s), %s lines, cursor at %s', [FormatNumber(MemoText.GetTextLen), MaxLen, FormatNumber(MemoText.Lines.Count), CursorPos]);
+ if MemoText.ReadOnly then
+ lblTextLength.Caption := lblTextLength.Caption + ', read-only';
+end;
+
+
+procedure TfrmTextEditor.btnCustomizeHighlighterClick(Sender: TObject);
+var
+ Dialog: TfrmCustomizeHighlighter;
+begin
+ // let user customize highlighter colors
+ Dialog := TfrmCustomizeHighlighter.Create(Self);
+ Dialog.FriendlyLanguageName := MemoText.Highlighter.GetLanguageName;
+ Dialog.OnChange := CustomizeHighlighterChanged;
+ Dialog.ShowModal;
+ Dialog.Free;
+end;
+
+procedure TfrmTextEditor.CustomizeHighlighterChanged(Sender: TObject);
+var
+ Dialog: TfrmCustomizeHighlighter;
+begin
+ Dialog := Sender as TfrmCustomizeHighlighter;
+ comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(Dialog.FriendlyLanguageName);
+ comboHighlighter.OnSelect(comboHighlighter);
+end;
+
+procedure TfrmTextEditor.SelectLinebreaks(Sender: TObject);
+var
+ Selected, Item: TMenuItem;
+begin
+ Selected := Sender as TMenuItem;
+ menuWindowsLB.Caption := _('Windows linebreaks');
+ menuUnixLB.Caption := _('UNIX linebreaks');
+ menuMacLB.Caption := _('Mac OS linebreaks');
+ menuWideLB.Caption := _('Unicode linebreaks');
+ menuMixedLB.Caption := _('Mixed linebreaks');
+ for Item in popupLinebreaks.Items do begin
+ if Item.Tag = Integer(FDetectedLineBreaks) then begin
+ Item.Caption := Item.Caption + ' (' + _('detected') + ')';
+ end;
+ end;
+
+ Selected.Default := True;
+ btnLineBreaks.Hint := Selected.Caption;
+ btnLineBreaks.ImageIndex := Selected.ImageIndex;
+ FSelectedLineBreaks := TLineBreaks(Selected.Tag);
+ Modified := True;
+end;
+
+
+procedure TfrmTextEditor.SetMaxLength(len: integer);
+begin
+ // Input: Length in number of bytes.
+ FMaxLength := len;
+end;
+
+procedure TfrmTextEditor.SetFont(font: TFont);
+begin
+ MemoText.Font.Name := font.Name;
+ MemoText.Font.Size := font.Size;
+end;
+
+procedure TfrmTextEditor.FormCreate(Sender: TObject);
+var
+ Highlighters: TSynHighlighterList;
+ i: Integer;
+begin
+ HasSizeGrip := True;
+ FClosingByApplyButton := False;
+ // Assign linebreak values to their menu item tags, to write less code later
+ menuWindowsLB.Tag := Integer(lbsWindows);
+ menuUnixLB.Tag := Integer(lbsUnix);
+ menuMacLB.Tag := Integer(lbsMac);
+ menuWideLB.Tag := Integer(lbsWide);
+ menuMixedLB.Tag := Integer(lbsMixed);
+
+ Highlighters := SynEditHighlighter.GetPlaceableHighlighters;
+ for i:=0 to Highlighters.Count-1 do begin
+ comboHighlighter.Items.Add(Highlighters[i].GetLanguageName);
+ end;
+
+ FTableColumn := nil;
+
+ // Fix label position:
+ lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2;
+
+ // Define highlighters for which we have a reformatter
+ FHighlighterFormatters := TStringList.Create;
+ //FHighlighterFormatters.Add(TSynJSONSyn.ClassName);
+ FHighlighterFormatters.Add(TSynSQLSyn.ClassName);
+ FHighlighterFormatters.Add(TSynXMLSyn.ClassName);
+
+ MemoText.OnMouseWheel := MainForm.AnySynMemoMouseWheel;
+ //MemoText.OnPaintTransient := MainForm.SynMemoQuery.OnPaintTransient;
+ if AppSettings.ReadBool(asMemoEditorMaximized) then
+ WindowState := wsMaximized;
+end;
+
+
+procedure TfrmTextEditor.FormDestroy(Sender: TObject);
+begin
+ if WindowState <> wsMaximized then begin
+ AppSettings.WriteIntDpiAware(asMemoEditorWidth, Self, Width);
+ AppSettings.WriteIntDpiAware(asMemoEditorHeight, Self, Height);
+ end;
+ AppSettings.WriteBool(asMemoEditorMaximized, WindowState=wsMaximized);
+ if btnWrap.Enabled then begin
+ AppSettings.WriteBool(asMemoEditorWrap, btnWrap.Down);
+ end;
+ if Assigned(FTableColumn) and (comboHighlighter.Text <> AppSettings.GetDefaultString(asMemoEditorHighlighter)) then begin
+ AppSettings.SessionPath := MainForm.GetRegKeyTable;
+ AppSettings.WriteString(asMemoEditorHighlighter, comboHighlighter.Text, FTableColumn.Name);
+ end;
+end;
+
+
+procedure TfrmTextEditor.FormShow(Sender: TObject);
+var
+ HighlighterName: String;
+begin
+ // Restore form dimensions
+ if WindowState <> wsMaximized then begin
+ Width := AppSettings.ReadIntDpiAware(asMemoEditorWidth, Self);
+ Height := AppSettings.ReadIntDpiAware(asMemoEditorHeight, Self);
+ end;
+
+ if AppSettings.ReadBool(asMemoEditorWrap) and btnWrap.Enabled then begin
+ btnWrap.Click;
+ end;
+ menuAlwaysFormatCode.Checked := AppSettings.ReadBool(asMemoEditorAlwaysFormatCode);
+
+ // Select previously used highlighter
+ HighlighterName := AppSettings.GetDefaultString(asMemoEditorHighlighter);
+ if Assigned(FTableColumn) then begin
+ AppSettings.SessionPath := MainForm.GetRegKeyTable;
+ HighlighterName := AppSettings.ReadString(asMemoEditorHighlighter, FTableColumn.Name, HighlighterName);
+ end;
+
+ if MemoText.ReadOnly then begin
+ MemoText.Color := clBtnFace;
+ end;
+
+ comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(HighlighterName);
+ comboHighlighter.OnSelect(comboHighlighter);
+ // Trigger change event, which is not fired when text is empty. See #132.
+ TimerMemoChangeTimer(Self);
+ MemoText.SetFocus;
+end;
+
+
+procedure TfrmTextEditor.MemoTextKeyDown(Sender: TObject; var Key: Word; Shift:
+ TShiftState);
+begin
+ TimerMemoChange.Enabled := False;
+ TimerMemoChange.Enabled := True;
+ case Key of
+ // Cancel active dialog by Escape
+ VK_ESCAPE: begin
+ btnCancelClick(Sender);
+ end;
+ // 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.MemoTextClick(Sender: TObject);
+begin
+ TimerMemoChange.Enabled := False;
+ TimerMemoChange.Enabled := True;
+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 begin
+ MemoText.ScrollBars := ssVertical;
+ //MemoText.WordWrap := True;
+ end else begin
+ MemoText.ScrollBars := ssBoth;
+ //MemoText.WordWrap := False;
+ end;
+ btnWrap.Down := MemoText.ScrollBars = ssVertical;
+ Modified := WasModified;
+ Screen.Cursor := crDefault;
+end;
+
+
+procedure TfrmTextEditor.comboHighlighterSelect(Sender: TObject);
+var
+ Highlighters: TSynHighlighterList;
+ i: Integer;
+ SelStart, SelLength: Integer;
+begin
+ // Code highlighter selected
+ SelStart := MemoText.SelStart;
+ SelLength := MemoText.SelEnd - MemoText.SelStart;
+ MemoText.Highlighter := nil;
+ FHighlighter.Free;
+ Highlighters := SynEditHighlighter.GetPlaceableHighlighters;
+ for i:=0 to Highlighters.Count-1 do begin
+ if comboHighlighter.Text = Highlighters[i].GetLanguageName then begin
+ FHighlighter := Highlighters[i].Create(Self);
+ MemoText.Highlighter := FHighlighter;
+ Break;
+ end;
+ end;
+ // In case the combobox is empty:
+ if MemoText.Highlighter = nil then begin
+ FHighlighter := TSynSQLSyn.Create(Self);
+ MemoText.Highlighter := FHighlighter;
+ end;
+
+ menuFormatCodeOnce.Enabled := FHighlighterFormatters.IndexOf(FHighlighter.ClassName) > -1;
+ if menuAlwaysFormatCode.Checked and menuFormatCodeOnce.Enabled then begin
+ menuFormatCodeOnce.OnClick(Sender);
+ SelStart := 0;
+ SelLength := 0;
+ end;
+
+ // Load custom highlighter settings from ini file, if exists:
+ MemoText.Highlighter.LoadFromFile(AppSettings.DirnameHighlighters + MemoText.Highlighter.LanguageName + '.ini');
+
+ MemoText.SelStart := SelStart;
+ MemoText.SelEnd := SelStart + SelLength;
+end;
+
+procedure TfrmTextEditor.btnLoadTextClick(Sender: TObject);
+var
+ d: TExtFileOpenDialog;
+begin
+ AppSettings.ResetPath;
+ d := TExtFileOpenDialog.Create(Self);
+ d.AddFileType('*.txt', _('Text files'));
+ d.AddFileType('*.*', _('All files'));
+ d.Encodings.Assign(MainForm.FileEncodings);
+ d.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name);
+ if d.Execute then try
+ Screen.Cursor := crHourglass;
+ MemoText.Text := ReadTextFile(d.FileName, MainForm.GetEncodingByName(d.Encodings[d.EncodingIndex]));
+ if (FMaxLength > 0) and (Length(MemoText.Text) > FMaxLength) then
+ MemoText.Text := copy(MemoText.Text, 0, FMaxLength);
+ AppSettings.WriteInt(asFileDialogEncoding, d.EncodingIndex, Self.Name);
+ finally
+ Screen.Cursor := crDefault;
+ end;
+ d.Free;
+end;
+
+
+procedure TfrmTextEditor.btnCancelClick(Sender: TObject);
+begin
+ FClosingByCancelButton := True;
+ Close;
+end;
+
+
+procedure TfrmTextEditor.menuAlwaysFormatCodeClick(Sender: TObject);
+begin
+ // Change setting for "always reformat"
+ AppSettings.WriteBool(asMemoEditorAlwaysFormatCode, menuAlwaysFormatCode.Checked);
+ if menuAlwaysFormatCode.Checked and menuFormatCodeOnce.Enabled then begin
+ menuFormatCodeOnce.OnClick(Sender);
+ end;
+end;
+
+
+procedure TfrmTextEditor.menuFormatCodeOnceClick(Sender: TObject);
+//var
+ //JsonTmp: TJSONValue;
+ //Xml: TXmlVerySimple;
+ //XmlTmp: IXMLDocument;
+begin
+ // Reformat code if possible
+ try
+ {if FHighlighter is TSynJSONSyn then begin
+ JsonTmp := TJSONObject.ParseJSONValue(MemoText.Text);
+ MemoText.Text := JsonTmp.Format;
+ JsonTmp.Free;
+ MemoText.SelStart := 0;
+ MemoText.SelLength := 0;
+ end
+ else} if FHighlighter is TSynSQLSyn then begin
+ // Prefer old internal formatter here, so the user does not run into request limits
+ frmReformatter := TfrmReformatter.Create(Self);
+ MemoText.Text := frmReformatter.FormatSqlInternal(MemoText.Text);
+ MemoText.SelStart := 0;
+ MemoText.SelEnd := 0;
+ frmReformatter.Free;
+ end
+ {else if FHighlighter is TSynXMLSyn then begin
+ XmlTmp := TXMLDocument.Create(nil);
+ XmlTmp.LoadFromXML(MemoText.Text);
+ MemoText.BeginUpdate;
+ MemoText.Text := XMLDoc.FormatXMLData(MemoText.Text);
+ MemoText.EndUpdate;
+ Xml := TXmlVerySimple.Create;
+ //Xml.Options := [doNodeAutoIndent, doParseProcessingInstr, doCaseInsensitive, doWriteBOM, doSimplifyTextNodes];
+ Xml.Clear;
+ Xml.Text := MemoText.Lines.Text.Trim;
+ MemoText.BeginUpdate;
+ MemoText.Lines.Text := Xml.Text;
+ MemoText.EndUpdate;
+ Xml.Free;
+ MemoText.SelStart := 0;
+ MemoText.SelLength := 0;
+ end}
+ else begin
+ Beep;
+ end;
+ except
+ on E:Exception do begin
+ Beep;
+ MainForm.LogSQL(f_('Error in code formatting: %s', [E.Message]));
+ end;
+ end;
+end;
+
+
+procedure TfrmTextEditor.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ if Modified then begin
+ if FClosingByCancelButton then
+ ModalResult := mrCancel
+ else if FClosingByApplyButton then
+ ModalResult := mrYes
+ else
+ ModalResult := MessageDialog(_('Apply modifications?'), mtConfirmation, [mbYes, mbNo]);
+ end
+ else
+ ModalResult := mrCancel;
+end;
+
+
+procedure TfrmTextEditor.btnApplyClick(Sender: TObject);
+begin
+ FClosingByApplyButton := True;
+ Close;
+end;
+
+
+procedure TfrmTextEditor.MemoTextChange(Sender: TObject);
+begin
+ Modified := True;
+ TimerMemoChange.Enabled := False;
+ TimerMemoChange.Enabled := True;
+end;
+
+
+procedure TfrmTextEditor.SetModified(NewVal: Boolean);
+begin
+ // Enables or disables "apply" button, and resets SynEdit's modification marker in its gutter
+ if FModified <> NewVal then begin
+ FModified := NewVal;
+ if not FModified then
+ MemoText.Modified := False;
+ btnApply.Enabled := FModified;
+ end;
+end;
+
+
+end.