feat: convert all save/open dialogs to the new custom one

* TOpenDialog => TExtFileOpenDialog
* TSaveDialog => TExtFileSaveDialog
* show encodings and linebreaks only when the caller sets data for these
* show selected path from tree in label at top
* support DefaultExt string
* support OnTypeChange event
* disallow changing tree folder for ofNoChangeDir
* catch EInvalidPath in SetInitialDir
* show hidden folders in tree
* enable sorting in file listing

Refs #2268
This commit is contained in:
Ansgar Becker
2025-11-28 10:17:23 +01:00
parent 91de2fc30d
commit 4a8c53c4e0
9 changed files with 379 additions and 316 deletions

View File

@@ -1,221 +1,220 @@
unit bineditor;
{$mode delphi}{$H+}
interface
uses
Classes, Graphics, Forms, Controls, StdCtrls, laz.VirtualTrees,
ComCtrls, Dialogs, SysUtils, extra_controls, LCLType;
{$I const.inc}
type
TfrmBinEditor = class(TExtForm)
memoText: TMemo;
tlbStandard: TToolBar;
btnWrap: TToolButton;
btnLoadBinary: TToolButton;
btnApply: TToolButton;
btnCancel: TToolButton;
lblTextLength: TLabel;
procedure btnApplyClick(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure btnLoadBinaryClick(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);
private
{ Private declarations }
FModified: Boolean;
FStopping: Boolean;
procedure SetModified(NewVal: Boolean);
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;
end;
implementation
uses apphelpers, main;
{$R *.lfm}
function TfrmBinEditor.GetText: String;
var
Ansi: AnsiString;
begin
// Convert hex to binary string before returning
Ansi := '';
SetLength(Ansi, memoText.GetTextLen div 2);
HexToBin(PChar(memoText.Text), PAnsiChar(Ansi), Length(Ansi));
Result := String(Ansi);
end;
procedure TfrmBinEditor.SetText(text: String);
begin
// Skip '0x'.
memoText.Text := Copy(text, 3);
end;
procedure TfrmBinEditor.SetTitleText(Title: String);
begin
// Add column name to window title bar
if Title <> '' then
Caption := Title + ' - ' + Caption;
end;
procedure TfrmBinEditor.SetMaxLength(len: integer);
begin
// Input: Length in bytes.
memoText.MaxLength := len * 2;
end;
procedure TfrmBinEditor.SetFont(font: TFont);
begin
memoText.Font.Name := font.Name;
memoText.Font.Size := font.Size;
end;
procedure TfrmBinEditor.FormCreate(Sender: TObject);
begin
HasSizeGrip := True;
Width := AppSettings.ReadInt(asMemoEditorWidth);
Height := AppSettings.ReadInt(asMemoEditorHeight);
end;
procedure TfrmBinEditor.FormDestroy(Sender: TObject);
begin
AppSettings.WriteInt(asMemoEditorWidth, Width);
AppSettings.WriteInt(asMemoEditorHeight, Height);
AppSettings.WriteBool(asMemoEditorWrap, btnWrap.Down);
end;
procedure TfrmBinEditor.FormShow(Sender: TObject);
begin
// Restore form dimensions
if AppSettings.ReadBool(asMemoEditorWrap) then
btnWrap.Click;
// Fix label position:
lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2;
memoText.SelectAll;
memoText.SetFocus;
memoTextChange(Sender);
Modified := False;
end;
procedure TfrmBinEditor.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 TfrmBinEditor.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 TfrmBinEditor.btnLoadBinaryClick(Sender: TObject);
var
d: TOpenDialog;
begin
d := TOpenDialog.Create(Self);
d.Filter := _('All files')+' (*.*)|*.*';
d.FilterIndex := 0;
if d.Execute then try
Screen.Cursor := crHourglass;
memoText.Text := BinToWideHex(ReadBinaryFile(d.FileName, memoText.MaxLength));
finally
Screen.Cursor := crDefault;
end;
d.Free;
end;
procedure TfrmBinEditor.btnCancelClick(Sender: TObject);
begin
if FStopping then
Exit;
FStopping := True;
TCustomVirtualStringTree(Owner).CancelEditNode;
end;
procedure TfrmBinEditor.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 TfrmBinEditor.btnApplyClick(Sender: TObject);
begin
FStopping := True;
TCustomVirtualStringTree(Owner).EndEditNode;
end;
procedure TfrmBinEditor.memoTextChange(Sender: TObject);
begin
lblTextLength.Caption := FormatNumber(Length(memoText.Text) / 2) + ' bytes.';
if memoText.MaxLength > 0 then
lblTextLength.Caption := lblTextLength.Caption + ' (Max: '+FormatNumber(memoText.MaxLength / 2)+')';
Modified := True;
end;
procedure TfrmBinEditor.SetModified(NewVal: Boolean);
begin
if FModified <> NewVal then begin
FModified := NewVal;
btnApply.Enabled := FModified;
end;
end;
end.
unit bineditor;
{$mode delphi}{$H+}
interface
uses
Classes, Graphics, Forms, Controls, StdCtrls, laz.VirtualTrees,
ComCtrls, Dialogs, SysUtils, extra_controls, LCLType, extfiledialog;
{$I const.inc}
type
TfrmBinEditor = class(TExtForm)
memoText: TMemo;
tlbStandard: TToolBar;
btnWrap: TToolButton;
btnLoadBinary: TToolButton;
btnApply: TToolButton;
btnCancel: TToolButton;
lblTextLength: TLabel;
procedure btnApplyClick(Sender: TObject);
procedure btnCancelClick(Sender: TObject);
procedure btnLoadBinaryClick(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);
private
{ Private declarations }
FModified: Boolean;
FStopping: Boolean;
procedure SetModified(NewVal: Boolean);
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;
end;
implementation
uses apphelpers, main;
{$R *.lfm}
function TfrmBinEditor.GetText: String;
var
Ansi: AnsiString;
begin
// Convert hex to binary string before returning
Ansi := '';
SetLength(Ansi, memoText.GetTextLen div 2);
HexToBin(PChar(memoText.Text), PAnsiChar(Ansi), Length(Ansi));
Result := String(Ansi);
end;
procedure TfrmBinEditor.SetText(text: String);
begin
// Skip '0x'.
memoText.Text := Copy(text, 3);
end;
procedure TfrmBinEditor.SetTitleText(Title: String);
begin
// Add column name to window title bar
if Title <> '' then
Caption := Title + ' - ' + Caption;
end;
procedure TfrmBinEditor.SetMaxLength(len: integer);
begin
// Input: Length in bytes.
memoText.MaxLength := len * 2;
end;
procedure TfrmBinEditor.SetFont(font: TFont);
begin
memoText.Font.Name := font.Name;
memoText.Font.Size := font.Size;
end;
procedure TfrmBinEditor.FormCreate(Sender: TObject);
begin
HasSizeGrip := True;
Width := AppSettings.ReadInt(asMemoEditorWidth);
Height := AppSettings.ReadInt(asMemoEditorHeight);
end;
procedure TfrmBinEditor.FormDestroy(Sender: TObject);
begin
AppSettings.WriteInt(asMemoEditorWidth, Width);
AppSettings.WriteInt(asMemoEditorHeight, Height);
AppSettings.WriteBool(asMemoEditorWrap, btnWrap.Down);
end;
procedure TfrmBinEditor.FormShow(Sender: TObject);
begin
// Restore form dimensions
if AppSettings.ReadBool(asMemoEditorWrap) then
btnWrap.Click;
// Fix label position:
lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2;
memoText.SelectAll;
memoText.SetFocus;
memoTextChange(Sender);
Modified := False;
end;
procedure TfrmBinEditor.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 TfrmBinEditor.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 TfrmBinEditor.btnLoadBinaryClick(Sender: TObject);
var
d: TExtFileOpenDialog;
begin
d := TExtFileOpenDialog.Create(Self);
d.AddFileType('*.*', _('All files'));
if d.Execute then try
Screen.Cursor := crHourglass;
memoText.Text := BinToWideHex(ReadBinaryFile(d.FileName, memoText.MaxLength));
finally
Screen.Cursor := crDefault;
end;
d.Free;
end;
procedure TfrmBinEditor.btnCancelClick(Sender: TObject);
begin
if FStopping then
Exit;
FStopping := True;
TCustomVirtualStringTree(Owner).CancelEditNode;
end;
procedure TfrmBinEditor.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 TfrmBinEditor.btnApplyClick(Sender: TObject);
begin
FStopping := True;
TCustomVirtualStringTree(Owner).EndEditNode;
end;
procedure TfrmBinEditor.memoTextChange(Sender: TObject);
begin
lblTextLength.Caption := FormatNumber(Length(memoText.Text) / 2) + ' bytes.';
if memoText.MaxLength > 0 then
lblTextLength.Caption := lblTextLength.Caption + ' (Max: '+FormatNumber(memoText.MaxLength / 2)+')';
Modified := True;
end;
procedure TfrmBinEditor.SetModified(NewVal: Boolean);
begin
if FModified <> NewVal then begin
FModified := NewVal;
btnApply.Enabled := FModified;
end;
end;
end.

View File

@@ -13,7 +13,7 @@ uses
SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls,
laz.VirtualTrees, Menus, Graphics, extra_controls, lazaruscompat,
dbconnection, RegExpr, Types, FileUtil,
Math, ActnList, ComboEx, EditBtn, Buttons, ColorBox;
Math, ActnList, ComboEx, EditBtn, Buttons, ColorBox, extfiledialog;
type
@@ -1720,7 +1720,7 @@ end;
procedure Tconnform.PickFile(Sender: TObject);
var
Selector: TOpenDialog;
Selector: TExtFileOpenDialog;
Edit: TEditButton;
i: Integer;
Control: TControl;
@@ -1728,18 +1728,21 @@ var
begin
// Select startup SQL file, SSL file or whatever button clicked
Edit := Sender as TEditButton;
Selector := TOpenDialog.Create(Self);
Selector := TExtFileOpenDialog.Create(Self);
if Edit = editHost then begin
Selector.Filter := 'SQLite databases ('+FILEFILTER_SQLITEDB+')|'+FILEFILTER_SQLITEDB+'|'+_('All files')+' (*.*)|*.*';
Selector.AddFileType(FILEFILTER_SQLITEDB, 'SQLite databases');
Selector.Options := Selector.Options - [ofFileMustExist];
Selector.Options := Selector.Options + [ofAllowMultiSelect];
Selector.DefaultExt := FILEEXT_SQLITEDB;
end else if (Edit = editStartupScript) or (Edit = editLogFilePath) then
Selector.Filter := _('SQL files')+' (*.sql)|*.sql|'+_('All files')+' (*.*)|*.*'
else if Edit = editSSHPrivateKey then
Selector.Filter := _('All files')+' (*.*)|*.*'
else
Selector.Filter := _('Privacy Enhanced Mail certificates')+' (*.pem)|*.pem|'+_('Certificates')+' (*.crt)|*.crt|'+_('All files')+' (*.*)|*.*';
Selector.AddFileType('*.sql', _('SQL files'))
else if Edit = editSSHPrivateKey then begin
end
else begin
Selector.AddFileType('*.pem', _('Privacy Enhanced Mail certificates'));
Selector.AddFileType('*.crt', _('Certificates'));
end;
Selector.AddFileType('*.*', _('All files'));
// Find relevant label and set open dialog's title
for i:=0 to Edit.Parent.ControlCount - 1 do begin
Control := Edit.Parent.Controls[i];
@@ -1750,8 +1753,6 @@ begin
end;
// Set initial directory to the one from the edit's file
Selector.InitialDir := ExtractFilePath(Edit.Text);
//if Selector.InitialDir.IsEmpty then
// Selector.InitialDir := TPath.GetPathRoot(Application.ExeName);
if Selector.Execute then begin
FileNames := TStringList.Create;
FileNames.Assign(Selector.Files);

View File

@@ -7,7 +7,8 @@ interface
uses
SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Menus, ComCtrls, laz.VirtualTrees, SynExportHTML,
extra_controls, dbstructures, lazaruscompat, RegExpr, StrUtils, comboex, EditBtn, Buttons, LCLIntf;
extra_controls, dbstructures, lazaruscompat, RegExpr, StrUtils, comboex, EditBtn, Buttons, LCLIntf,
extfiledialog;
type
TGridExportFormat = (
@@ -390,21 +391,20 @@ end;
procedure TfrmExportGrid.editFilenameRightButtonClick(Sender: TObject);
var
Dialog: TSaveDialog;
Dialog: TExtFileSaveDialog;
ef: TGridExportFormat;
Filename: String;
begin
// Select file target
Dialog := TSaveDialog.Create(Self);
Dialog := TExtFileSaveDialog.Create(Self);
Filename := GetOutputFilename(editFilename.Text, MainForm.ActiveDbObj);
Dialog.InitialDir := ExtractFilePath(Filename);
Dialog.FileName := GetFileNameWithoutExtension(Filename);
Dialog.Filter := '';
for ef:=Low(TGridExportFormat) to High(TGridExportFormat) do
Dialog.Filter := Dialog.Filter + FormatToDescription[ef] + ' (*.'+FormatToFileExtension[ef]+')|*.'+FormatToFileExtension[ef]+'|';
Dialog.Filter := Dialog.Filter + _('All files')+' (*.*)|*.*';
Dialog.AddFileType('*.'+FormatToFileExtension[ef], FormatToDescription[ef]);
Dialog.AddFileType('*.*', _('All files'));
Dialog.OnTypeChange := SaveDialogTypeChange;
Dialog.FilterIndex := comboFormat.ItemIndex+1;
Dialog.FilterIndex := comboFormat.ItemIndex;
Dialog.OnTypeChange(Dialog);
if Dialog.Execute then begin
editFilename.Text := Dialog.FileName;
@@ -558,13 +558,13 @@ end;
procedure TfrmExportGrid.SaveDialogTypeChange(Sender: TObject);
var
Dialog: TSaveDialog;
Dialog: TExtFileSaveDialog;
ef: TGridExportFormat;
begin
// Set default file-extension of saved file and options on the dialog to show
Dialog := Sender as TSaveDialog;
Dialog := Sender as TExtFileSaveDialog;
for ef:=Low(TGridExportFormat) to High(TGridExportFormat) do begin
if Dialog.FilterIndex = Integer(ef)+1 then
if Dialog.FilterIndex = Integer(ef) then
Dialog.DefaultExt := FormatToFileExtension[ef];
end;
end;

View File

@@ -165,38 +165,53 @@ object frmExtFileDialog: TfrmExtFileDialog
end
end
object ShellTreeView: TShellTreeView
AnchorSideTop.Control = lblPath
AnchorSideTop.Side = asrBottom
Left = 10
Height = 446
Top = 10
Height = 416
Top = 40
Width = 261
Align = alLeft
BorderSpacing.Left = 10
BorderSpacing.Top = 10
HideSelection = False
ReadOnly = False
TabOrder = 0
Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw]
ObjectTypes = [otFolders, otHidden]
ShellListView = ShellListView
OnChange = ShellTreeViewChange
OnChanging = ShellTreeViewChanging
end
object splitterMain: TSplitter
Left = 271
Height = 456
Top = 0
Height = 416
Top = 40
Width = 6
end
object ShellListView: TShellListView
AnchorSideTop.Control = lblPath
AnchorSideTop.Side = asrBottom
Left = 277
Height = 446
Top = 10
Height = 416
Top = 40
Width = 585
Align = alClient
BorderSpacing.Top = 10
BorderSpacing.Right = 10
Color = clDefault
SortType = stText
TabOrder = 1
ShellTreeView = ShellTreeView
OnClick = ShellListViewClick
OnDblClick = ShellListViewDblClick
OnSelectItem = ShellListViewSelectItem
end
object lblPath: TLabel
Left = 10
Height = 20
Top = 10
Width = 852
Align = alTop
BorderSpacing.Around = 10
Caption = 'lblPath'
end
end

View File

@@ -19,6 +19,7 @@ type
comboEncoding: TComboBox;
comboFileType: TComboBox;
editFilename: TEdit;
lblPath: TLabel;
lblLinebreaks: TLabel;
lblEncoding: TLabel;
lblFilename: TLabel;
@@ -37,21 +38,28 @@ type
procedure ShellListViewDblClick(Sender: TObject);
procedure ShellListViewSelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
procedure ShellTreeViewChange(Sender: TObject; Node: TTreeNode);
procedure ShellTreeViewChanging(Sender: TObject; Node: TTreeNode;
var AllowChange: Boolean);
private
FInitialDir: String;
FFilterNames: TStringList;
FFilterMasks: TStringList;
FFilterIndex: Integer;
FDefaultExt: String;
FEncodings: TStringList;
FEncodingIndex: Integer;
FLineBreakIndex: TLineBreaks;
FOptions: TOpenOptions;
FFiles: TStringList;
FOnTypeChange: TNotifyEvent;
procedure SetTitle(AValue: String);
function GetFileName: String;
procedure SetFileName(const AValue: String);
procedure SetInitialDir(const AValue: String);
procedure SetFilterIndex(AValue: Integer);
public
property OnTypeChange: TNotifyEvent read FOnTypeChange write FOnTypeChange;
property Title: String write SetTitle;
function Execute: Boolean;
procedure AddFileType(FileMask, DisplayName: String);
@@ -61,18 +69,19 @@ type
property DefaultExt: String read FDefaultExt write FDefaultExt;
property Options: TOpenOptions read FOptions write FOptions;
property Files: TStringList read FFiles;
property FilterIndex: Integer read FFilterIndex write SetFilterIndex;
end;
// File-open-dialog with encoding selector
TExtFileOpenDialog = class(TfrmExtFileDialog)
procedure FormCreate(Sender: TObject); overload;
procedure FormShow(Sender: TObject); overload;
public
property Encodings: TStringList read FEncodings write FEncodings;
property EncodingIndex: Integer read FEncodingIndex write FEncodingIndex;
end;
TExtFileSaveDialog = class(TfrmExtFileDialog)
procedure FormCreate(Sender: TObject); overload;
procedure FormShow(Sender: TObject); overload;
public
property LineBreakIndex: TLineBreaks read FLineBreakIndex write FLineBreakIndex;
end;
@@ -100,20 +109,15 @@ begin
raise Exception.CreateFmt('Constructor of base class %s called. Use one of its descendants instead.', [ClassName]);
FFilterNames := TStringList.Create;
FFilterMasks := TStringList.Create;
FFilterIndex := 0;
FDefaultExt := '';
FEncodings := TStringList.Create;
{$IFDEF LINUX}
FLineBreakIndex := lbsUnix;
{$ENDIF}
{$IFDEF WINDOWS}
FLineBreakIndex := lbsWindows;
{$ENDIF}
{$IFDEF DARWIN}
FLineBreakIndex := lbsMac;
{$ENDIF}
FLineBreakIndex := lbsNone;
FFiles := TStringList.Create;
comboFileType.Items.Clear;
editFilename.Text := '';
comboLineBreaks.Items.Clear;
FOnTypeChange := nil;
end;
procedure TfrmExtFileDialog.FormDestroy(Sender: TObject);
@@ -130,17 +134,15 @@ var
LineBreakIndexInt: Integer;
begin
ShellListView.MultiSelect := ofAllowMultiSelect in FOptions;
ShellTreeView.Enabled := not (ofNoChangeDir in FOptions);
// Todo: support ofFileMustExist and convert usages of TOpenDialog and TSaveDialog
if FInitialDir.IsEmpty then begin
if not PreviousDir.IsEmpty then
SetInitialDir(PreviousDir)
else
SetInitialDir(GetUserDir);
end;
// Todo: support ofFileMustExist
if not FInitialDir.IsEmpty then
SetInitialDir(FInitialDir)
else if not PreviousDir.IsEmpty then
SetInitialDir(PreviousDir)
else
SetInitialDir(GetUserDir);
comboFileType.ItemIndex := 0;
comboFileType.OnChange(Sender);
SetFilterIndex(FFilterIndex);
comboEncoding.Items.AddStrings(FEncodings, True);
if (FEncodingIndex >=0) and (FEncodingIndex < comboEncoding.Items.Count) then
@@ -158,11 +160,14 @@ procedure TfrmExtFileDialog.comboFileTypeChange(Sender: TObject);
var
FileMask: String;
begin
FFilterIndex := comboFileType.ItemIndex;
if (comboFileType.ItemIndex >= 0) and (FFilterMasks.Count > comboFileType.ItemIndex) then
FileMask := FFilterMasks[comboFileType.ItemIndex]
else
FileMask := '*.*';
ShellListView.Mask := FileMask;
if Assigned(FOnTypeChange) then
FOnTypeChange(Self);
end;
procedure TfrmExtFileDialog.comboLineBreaksChange(Sender: TObject);
@@ -226,6 +231,18 @@ begin
end;
end;
procedure TfrmExtFileDialog.ShellTreeViewChange(Sender: TObject; Node: TTreeNode
);
begin
lblPath.Caption := ShellTreeView.Path;
end;
procedure TfrmExtFileDialog.ShellTreeViewChanging(Sender: TObject;
Node: TTreeNode; var AllowChange: Boolean);
begin
AllowChange := not (ofNoChangeDir in FOptions);
end;
procedure TfrmExtFileDialog.SetTitle(AValue: String);
begin
Caption := AValue;
@@ -233,10 +250,13 @@ end;
function TfrmExtFileDialog.GetFileName: String;
begin
if ShellListView.Selected <> nil then
if (editFilename.Text <> '') and (ShellTreeView.Selected <> nil) then begin
Result := ShellTreeView.Path + editFilename.Text;
if IsEmpty(ExtractFileExt(Result)) and (not FDefaultExt.IsEmpty) then
Result := Result + '.' + FDefaultExt;
end
else if ShellListView.Selected <> nil then
Result := ShellListView.GetPathFromItem(ShellListView.Selected)
else if (editFilename.Text <> '') and (ShellTreeView.Selected <> nil) then
Result := ShellTreeView.Path + editFilename.Text
else
Result := '';
end;
@@ -246,35 +266,58 @@ var
fn: String;
begin
fn := ExpandFileName(AValue);
ShellTreeView.Path := ExtractFilePath(fn);
SetInitialDir(ExtractFilePath(fn));
editFilename.Text := ExtractFileName(fn);
ShellListView.Selected := ShellListView.FindCaption(0, fn, false, true, true);
end;
procedure TfrmExtFileDialog.SetInitialDir(const AValue: String);
begin
ShellTreeView.Path := AValue;
FInitialDir := AValue;
try
ShellTreeView.Path := FInitialDir;
except
on E:EInvalidPath do begin
ErrorDialog(E.Message);
// In case, re-enable changing directory in tree
Exclude(FOptions, ofNoChangeDir);
end;
end;
end;
procedure TfrmExtFileDialog.SetFilterIndex(AValue: Integer);
begin
if (AValue >= 0) and (AValue < comboFileType.Items.Count) then begin
comboFileType.ItemIndex := AValue;
comboFileTypeChange(Self);
end;
end;
{ TExtFileOpenDialog }
procedure TExtFileOpenDialog.FormCreate(Sender: TObject);
procedure TExtFileOpenDialog.FormShow(Sender: TObject);
var
EncodingVisible: Boolean;
begin
inherited;
lblEncoding.Visible := True;
comboEncoding.Visible := True;
EncodingVisible := comboEncoding.Items.Count > 0;
lblEncoding.Visible := EncodingVisible;
comboEncoding.Visible := EncodingVisible;
end;
{ TExtFileSaveDialog }
procedure TExtFileSaveDialog.FormCreate(Sender: TObject);
procedure TExtFileSaveDialog.FormShow(Sender: TObject);
var
LinebreaksVisible: Boolean;
begin
inherited;
lblLinebreaks.Visible := True;
comboLineBreaks.Visible := True;
LinebreaksVisible := FLineBreakIndex in [lbsWindows, lbsUnix, lbsMac];
lblLinebreaks.Visible := LinebreaksVisible;
comboLineBreaks.Visible := LinebreaksVisible;
end;
end.

View File

@@ -12,7 +12,6 @@ object frmInsertFiles: TfrmInsertFiles
Constraints.MinWidth = 250
DesignTimePPI = 120
Position = poOwnerFormCenter
LCLVersion = '4.2.0.0'
OnCreate = FormCreate
OnDestroy = FormDestroy
OnShow = FormShow
@@ -153,7 +152,7 @@ object frmInsertFiles: TfrmInsertFiles
Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus]
Position = 2
Text = 'Value'
Width = 386
Width = 382
end>
Header.Height = 32
Header.Images = MainForm.ImageListMain
@@ -238,7 +237,7 @@ object frmInsertFiles: TfrmInsertFiles
item
Position = 0
Text = 'Filename'
Width = 423
Width = 419
end
item
CheckBox = True
@@ -318,10 +317,4 @@ object frmInsertFiles: TfrmInsertFiles
end
end
end
object OpenDialog: TOpenDialog
Filter = 'All files (*.*)|*.*|Common images (*.jpg, *.gif, *.bmp, *.png)|*.jpg;*.gif;*.bmp;*.png'
Options = [ofHideReadOnly, ofAllowMultiSelect, ofFileMustExist, ofEnableSizing]
Left = 10
Top = 570
end
end

View File

@@ -7,7 +7,7 @@ interface
uses
SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls,
Math, Graphics, ComCtrls, LCLType, extra_controls, lazaruscompat,
dbconnection, dbstructures, laz.VirtualTrees, RegExpr, apphelpers;
dbconnection, dbstructures, laz.VirtualTrees, RegExpr, apphelpers, extfiledialog;
type
TColInfo = class
@@ -30,7 +30,6 @@ type
TfrmInsertFiles = class(TExtForm)
btnInsert: TButton;
btnCancel: TButton;
OpenDialog: TOpenDialog;
grpSelectObject: TGroupBox;
lblTable: TLabel;
comboDBs: TComboBox;
@@ -93,6 +92,7 @@ type
private
FConnection: TDBConnection;
FMaxFileSize: Int64;
FOpenDialog: TExtFileOpenDialog;
public
{ Public declarations }
//procedure AcceptFiles( var msg : TMessage ); message WM_DROPFILES;
@@ -124,6 +124,10 @@ begin
FixVT(ListColumns);
Width := AppSettings.ReadInt(asFileImportWindowWidth);
Height := AppSettings.ReadInt(asFileImportWindowHeight);
FOpenDialog := TExtFileOpenDialog.Create(Self);
FOpenDialog.Options := FOpenDialog.Options + [ofAllowMultiSelect];
FOpenDialog.AddFileType('*.*', _('All files'));
FOpenDialog.AddFileType('*.jpg;*.gif;*.bmp;*.png', _('Common images'));
end;
@@ -397,12 +401,12 @@ var
i: Integer;
begin
// Add file(s) to list
if OpenDialog.Execute then begin
if FOpenDialog.Execute then begin
Screen.Cursor := crHourglass;
ListFiles.BeginUpdate;
try
for i:=0 to OpenDialog.Files.Count-1 do
AddFile(OpenDialog.Files[i]);
for i:=0 to FOpenDialog.Files.Count-1 do
AddFile(FOpenDialog.Files[i]);
finally
ListFiles.EndUpdate;
end;

View File

@@ -3130,13 +3130,14 @@ end;
procedure TMainForm.actExportSettingsExecute(Sender: TObject);
var
Dialog: TSaveDialog;
Dialog: TExtFileSaveDialog;
begin
// Export settings to .txt file
Dialog := TSaveDialog.Create(Self);
Dialog := TExtFileSaveDialog.Create(Self);
Dialog.Title := f_('Export %s settings to file ...', [APPNAME]);
Dialog.DefaultExt := 'txt';
Dialog.Filter := _('Text files')+' (*.txt)|*.txt|'+_('All files')+' (*.*)|*.*';
Dialog.AddFileType('*.txt', _('Text files'));
Dialog.AddFileType('*.*', _('All files'));
Dialog.Options := Dialog.Options + [ofOverwritePrompt];
if Dialog.Execute then try
AppSettings.ExportSettings(Dialog.FileName);
@@ -3151,12 +3152,13 @@ end;
procedure TMainForm.actImportSettingsExecute(Sender: TObject);
var
Dialog: TOpenDialog;
Dialog: TExtFileOpenDialog;
begin
// Import settings from .txt or .reg file
Dialog := TOpenDialog.Create(Self);
Dialog := TExtFileOpenDialog.Create(Self);
Dialog.Title := f_('Import %s settings from file ...', [APPNAME]);
Dialog.Filter := _('Text files')+' (*.txt)|*.txt|'+_('All files')+' (*.*)|*.*';
Dialog.AddFileType('*.txt', _('Text files'));
Dialog.AddFileType('*.*', _('All files'));
ImportSettingsDone := False;
if Dialog.Execute then try
if LowerCase(ExtractFileExt(Dialog.FileName)) = 'reg' then
@@ -3767,13 +3769,13 @@ var
Content: AnsiString;
FileStream: TFileStream;
StrLen: Integer;
Dialog: TSaveDialog;
Dialog: TExtFileSaveDialog;
begin
// Save BLOB to local file
Grid := ActiveGrid;
Results := GridResult(Grid);
Dialog := TSaveDialog.Create(Self);
Dialog.Filter := _('All files')+' (*.*)|*.*';
Dialog := TExtFileSaveDialog.Create(Self);
Dialog.AddFileType('*.*', _('All files'));
Dialog.FileName := Results.ColumnOrgNames[Grid.FocusedColumn-1];
if not (Results.DataType(Grid.FocusedColumn-1).Category in [dtcBinary, dtcSpatial]) then
Dialog.FileName := Dialog.FileName + '.txt';
@@ -5612,16 +5614,17 @@ end;
procedure TMainForm.actAttachDatabaseExecute(Sender: TObject);
var
Selector: TOpenDialog;
Selector: TExtFileOpenDialog;
OldFiles, NewFiles: TStringList;
i: Integer;
Conn: TDBConnection;
DbAlias: String;
begin
// Attach new or existing SQLite database file
Selector := TOpenDialog.Create(Self);
Selector := TExtFileOpenDialog.Create(Self);
//Selector.InitialDir := ?;
Selector.Filter := 'SQLite databases ('+FILEFILTER_SQLITEDB+')|'+FILEFILTER_SQLITEDB+'|'+_('All files')+' (*.*)|*.*';
Selector.AddFileType(FILEFILTER_SQLITEDB, 'SQLite databases');
Selector.AddFileType('*.*', _('All files'));
Selector.Options := Selector.Options - [ofFileMustExist];
Selector.Options := Selector.Options + [ofAllowMultiSelect];
Selector.DefaultExt := FILEEXT_SQLITEDB;

View File

@@ -13,7 +13,7 @@ uses
SysUtils, Classes, Controls, Forms, StdCtrls, ComCtrls, Buttons, Dialogs,
laz.VirtualTrees, ExtCtrls, Graphics, RegExpr, Math, Generics.Collections, extra_controls,
dbconnection, apphelpers, lazaruscompat, Menus, DateUtils, Zipper, StrUtils,
SynEdit, ClipBrd, generic_types, fpjson, Variants, EditBtn, LazFileUtils, Types, LCLType;
SynEdit, ClipBrd, generic_types, fpjson, Variants, EditBtn, LazFileUtils, Types, LCLType, extfiledialog;
type
TToolMode = (tmMaintenance, tmFind, tmSQLExport, tmBulkTableEdit, tmGenerateData);
@@ -1675,17 +1675,22 @@ end;
procedure TfrmTableTools.btnExportOutputTargetSelectClick(Sender: TObject);
var
SaveDialog: TSaveDialog;
SaveDialog: TExtFileSaveDialog;
Browse: TSelectDirectoryDialog;
begin
if (comboExportOutputType.Text = OUTPUT_FILE) or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) then begin
// Select filename
SaveDialog := TSaveDialog.Create(Self);
SaveDialog.DefaultExt := 'sql';
if comboExportOutputType.Text = OUTPUT_FILE then
SaveDialog.Filter := _('SQL files')+' (*.sql)|*.sql|'+_('All files')+' (*.*)|*.*'
else
SaveDialog.Filter := _('ZIP files')+' (*.zip)|*.zip|'+_('All files')+' (*.*)|*.*';
SaveDialog := TExtFileSaveDialog.Create(Self);
SaveDialog.FileName := comboExportOutputTarget.Text;
if comboExportOutputType.Text = OUTPUT_FILE then begin
SaveDialog.AddFileType('*.sql', _('SQL files'));
SaveDialog.DefaultExt := 'sql';
end
else begin
SaveDialog.AddFileType('*.zip', _('ZIP files'));
SaveDialog.DefaultExt := 'zip';
end;
SaveDialog.AddFileType('*.*', _('All files'));
// Don't prompt here if file exists, but later when exporting starts. See issue #835
// SaveDialog.Options := SaveDialog.Options + [ofOverwritePrompt];
if SaveDialog.Execute then