From 56b783d8292b0acb72d45e1a2aed6546cb71fcbe Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Wed, 26 Nov 2025 12:55:28 +0100 Subject: [PATCH] fix: add encoding selector to file-open dialog Refs #2268 --- source/extfiledialog.lfm | 54 ++++++++++++++++++++++++++++++---------- source/extfiledialog.pas | 41 +++++++++++++++++++++++++++--- source/loaddata.pas | 12 ++++++++- source/main.pas | 27 ++++++++++++++------ source/texteditor.pas | 2 +- 5 files changed, 109 insertions(+), 27 deletions(-) diff --git a/source/extfiledialog.lfm b/source/extfiledialog.lfm index 7d89307c..1c70c7e0 100644 --- a/source/extfiledialog.lfm +++ b/source/extfiledialog.lfm @@ -28,12 +28,11 @@ object frmExtFileDialog: TfrmExtFileDialog AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = pnlBottom AnchorSideRight.Control = comboFileType - Left = 77 + Left = 73 Height = 28 Top = 0 - Width = 505 + Width = 549 Anchors = [akTop, akLeft, akRight] - BorderSpacing.Left = 10 BorderSpacing.Right = 10 TabOrder = 0 Text = 'editFilename' @@ -45,18 +44,19 @@ object frmExtFileDialog: TfrmExtFileDialog Left = 0 Height = 20 Top = 4 - Width = 67 - Caption = 'File name:' + Width = 63 + BorderSpacing.Right = 10 + Caption = 'Filename:' end object comboFileType: TComboBox AnchorSideLeft.Control = btnOk AnchorSideTop.Control = pnlBottom AnchorSideRight.Control = pnlBottom AnchorSideRight.Side = asrBottom - Left = 592 + Left = 632 Height = 28 Top = 0 - Width = 260 + Width = 220 Anchors = [akTop, akLeft, akRight] BorderSpacing.Bottom = 10 ItemHeight = 20 @@ -74,14 +74,15 @@ object frmExtFileDialog: TfrmExtFileDialog AnchorSideRight.Control = btnCancel AnchorSideBottom.Control = pnlBottom AnchorSideBottom.Side = asrBottom - Left = 592 + Left = 632 Height = 30 Top = 38 - Width = 125 + Width = 105 Anchors = [akTop, akRight, akBottom] + AutoSize = True BorderSpacing.Right = 10 Caption = 'OK' - Constraints.MinWidth = 125 + Constraints.MinWidth = 105 Default = True ModalResult = 1 TabOrder = 2 @@ -91,18 +92,45 @@ object frmExtFileDialog: TfrmExtFileDialog AnchorSideTop.Side = asrBottom AnchorSideRight.Control = pnlBottom AnchorSideRight.Side = asrBottom - Left = 727 + Left = 747 Height = 30 Top = 38 - Width = 125 + Width = 105 Anchors = [akTop, akRight] AutoSize = True Cancel = True Caption = 'Cancel' - Constraints.MinWidth = 125 + Constraints.MinWidth = 105 ModalResult = 2 TabOrder = 3 end + object comboEncoding: TComboBox + AnchorSideTop.Control = comboFileType + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnOk + Left = 402 + Height = 28 + Top = 38 + Width = 220 + Anchors = [akTop, akRight] + BorderSpacing.Right = 10 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 4 + OnChange = comboEncodingChange + end + object lblEncoding: TLabel + AnchorSideTop.Control = comboEncoding + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = comboEncoding + Left = 327 + Height = 20 + Top = 42 + Width = 65 + Anchors = [akTop, akRight] + BorderSpacing.Right = 10 + Caption = 'Encoding:' + end end object ShellTreeView: TShellTreeView Left = 10 diff --git a/source/extfiledialog.pas b/source/extfiledialog.pas index a8728d8e..5e28520e 100644 --- a/source/extfiledialog.pas +++ b/source/extfiledialog.pas @@ -6,22 +6,25 @@ interface uses Classes, SysUtils, LCLType, Forms, Controls, Graphics, Dialogs, - ExtCtrls, StdCtrls, ShellCtrls, ComCtrls, apphelpers; + ExtCtrls, StdCtrls, ShellCtrls, ComCtrls, apphelpers, extra_controls; type { TfrmExtFileDialog } - TfrmExtFileDialog = class(TForm) + TfrmExtFileDialog = class(TExtForm) btnCancel: TButton; btnOk: TButton; + comboEncoding: TComboBox; comboFileType: TComboBox; editFilename: TEdit; + lblEncoding: TLabel; lblFilename: TLabel; pnlBottom: TPanel; ShellListView: TShellListView; ShellTreeView: TShellTreeView; splitterMain: TSplitter; + procedure comboEncodingChange(Sender: TObject); procedure comboFileTypeChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); @@ -57,13 +60,16 @@ type end; // File-open-dialog with encoding selector - TExtFileOpenDialog = class(TfrmExtFileDialog); + TExtFileOpenDialog = class(TfrmExtFileDialog) + procedure FormCreate(Sender: TObject); overload; + end; implementation {$R *.lfm} + function TfrmExtFileDialog.Execute: Boolean; begin Result := ShowModal = mrOK; @@ -78,12 +84,16 @@ end; procedure TfrmExtFileDialog.FormCreate(Sender: TObject); begin + if ClassType = TfrmExtFileDialog then + raise Exception.CreateFmt('Constructor of base class %s called. Use one of its descendants instead.', [ClassName]); FFilterNames := TStringList.Create; FFilterMasks := TStringList.Create; FEncodings := TStringList.Create; FFiles := TStringList.Create; comboFileType.Items.Clear; editFilename.Text := ''; + lblEncoding.Enabled := False; + comboEncoding.Enabled := False; end; procedure TfrmExtFileDialog.FormDestroy(Sender: TObject); @@ -106,8 +116,13 @@ begin else SetInitialDir(GetUserDir); end; + comboFileType.ItemIndex := 0; comboFileType.OnChange(Sender); + + comboEncoding.Items.AddStrings(FEncodings, True); + if (FEncodingIndex >=0) and (FEncodingIndex < comboEncoding.Items.Count) then + comboEncoding.ItemIndex := FEncodingIndex; end; procedure TfrmExtFileDialog.comboFileTypeChange(Sender: TObject); @@ -121,6 +136,11 @@ begin ShellListView.Mask := FileMask; end; +procedure TfrmExtFileDialog.comboEncodingChange(Sender: TObject); +begin + FEncodingIndex := comboEncoding.ItemIndex; +end; + procedure TfrmExtFileDialog.ShellListViewClick(Sender: TObject); begin if ShellListView.Selected <> nil then @@ -131,7 +151,8 @@ end; procedure TfrmExtFileDialog.ShellListViewDblClick(Sender: TObject); begin - ModalResult := mrOK; + if ShellListView.Selected <> nil then + ModalResult := mrOK; end; procedure TfrmExtFileDialog.ShellListViewSelectItem(Sender: TObject; @@ -170,5 +191,17 @@ begin ShellTreeView.Path := AValue; end; + + +{ TExtFileOpenDialog } + +procedure TExtFileOpenDialog.FormCreate(Sender: TObject); +begin + inherited; + lblEncoding.Enabled := True; + comboEncoding.Enabled := True; +end; + + end. diff --git a/source/loaddata.pas b/source/loaddata.pas index 0f448b92..11de96b9 100644 --- a/source/loaddata.pas +++ b/source/loaddata.pas @@ -667,6 +667,7 @@ end; procedure Tloaddataform.btnOpenFileClick(Sender: TObject); var Dialog: TExtFileOpenDialog; + TestStream: TFileStream; begin AppSettings.ResetPath; Dialog := TExtFileOpenDialog.Create(Self); @@ -680,7 +681,16 @@ begin Dialog.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); if Dialog.Execute then begin editfilename.Text := Dialog.FileName; - FFileEncoding := TEncoding.UTF8; + FFileEncoding := Mainform.GetEncodingByName(Dialog.Encodings[Dialog.EncodingIndex]); + if FFileEncoding = nil then begin + MessageDialog(_('Auto detecting the encoding of a file is highly discouraged. You may experience data loss if the detection fails.') + + SLineBreak + SLineBreak + + _('To avoid this message select the correct encoding before pressing Open.'), + mtWarning, [mbOK]); + TestStream := TFileStream.Create(Dialog.Filename, fmOpenRead or fmShareDenyNone); + FFileEncoding := DetectEncoding(TestStream); + TestStream.Free; + end; grpParseMethod.OnClick(Sender); AppSettings.WriteInt(asFileDialogEncoding, Dialog.EncodingIndex, Self.Name); end; diff --git a/source/main.pas b/source/main.pas index 39e570ec..24138624 100644 --- a/source/main.pas +++ b/source/main.pas @@ -3943,7 +3943,7 @@ end; // Load SQL-file, make sure that SheetQuery is activated procedure TMainForm.actLoadSQLExecute(Sender: TObject); var - i: Integer; + i, ProceedResult: Integer; Dialog: TExtFileOpenDialog; Encoding: TEncoding; Tab: TQueryTab; @@ -3957,13 +3957,24 @@ begin Dialog.Encodings.Assign(FileEncodings); Dialog.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); if Dialog.Execute then begin - Encoding := TEncoding.UTF8; - if not RunQueryFiles(Dialog.Files, Encoding, Sender=actRunSQL) then begin - for i:=0 to Dialog.Files.Count-1 do begin - Tab := GetOrCreateEmptyQueryTab(False); - Tab.LoadContents(Dialog.Files[i], True, Encoding); - if i = Dialog.Files.Count-1 then - SetMainTab(Tab.TabSheet); + Encoding := GetEncodingByName(Dialog.Encodings[Dialog.EncodingIndex]); + if Encoding = nil then begin + ProceedResult := MessageDialog(_('Really auto-detect file encoding?') + SLineBreak + SLineBreak + + _('Auto detecting the encoding of a file is highly discouraged. You may experience data loss if the detection fails.') + SLineBreak + SLineBreak + + _('To avoid this message select the correct encoding before pressing Open.'), + mtConfirmation, [mbYes, mbCancel]); + end else begin + ProceedResult := mrYes; + end; + + if ProceedResult = mrYes then begin + if not RunQueryFiles(Dialog.Files, Encoding, Sender=actRunSQL) then begin + for i:=0 to Dialog.Files.Count-1 do begin + Tab := GetOrCreateEmptyQueryTab(False); + Tab.LoadContents(Dialog.Files[i], True, Encoding); + if i = Dialog.Files.Count-1 then + SetMainTab(Tab.TabSheet); + end; end; end; AppSettings.WriteInt(asFileDialogEncoding, Dialog.EncodingIndex, Self.Name); diff --git a/source/texteditor.pas b/source/texteditor.pas index cea2f003..589acaf3 100644 --- a/source/texteditor.pas +++ b/source/texteditor.pas @@ -421,7 +421,7 @@ begin d.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); if d.Execute then try Screen.Cursor := crHourglass; - MemoText.Text := ReadTextFile(d.FileName, TEncoding.UTF8); + 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);