Files
HeidiSQL/source/preferences.pas

1571 lines
54 KiB
ObjectPascal

unit preferences;
{$mode delphi}{$H+}
// -------------------------------------
// Preferences
// -------------------------------------
interface
uses
SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, SynEditHighlighter, SynHighlighterSQL,
SynEdit, laz.VirtualTrees, SynEditKeyCmds, ActnList, Menus,
dbstructures, RegExpr, EditBtn, LCLType, StrUtils,
extra_controls, reformatter, Buttons, ColorBox, LCLProc, LCLIntf, lazaruscompat, FileUtil,
vktable, generic_types;
type
TShortcutItemData = record
Action: TAction;
KeyStroke: TSynEditKeyStroke;
ShortCut1, ShortCut2: TShortCut;
end;
PShortcutItemData = ^TShortcutItemData;
{ TfrmPreferences }
TfrmPreferences = class(TExtForm)
chkShortcut2Shift: TCheckBox;
chkShortcut2Alt: TCheckBox;
chkShortcut2Control: TCheckBox;
chkShortcut1Shift: TCheckBox;
chkShortcut1Alt: TCheckBox;
chkShortcut1Control: TCheckBox;
comboShortcut1Key: TComboBox;
comboShortcut2Key: TComboBox;
editTerminal: TEditButton;
lblTerminal: TLabel;
pagecontrolMain: TPageControl;
tabMisc: TTabSheet;
btnCancel: TButton;
btnOK: TButton;
btnApply: TButton;
tabSQL: TTabSheet;
chkAutoReconnect: TCheckBox;
tabGridFormatting: TTabSheet;
lblDataFont: TLabel;
comboDataFontName: TComboBox;
editDataFontSize: TEdit;
lblDataFontHint: TLabel;
lblMaxColWidth: TLabel;
editMaxColWidth: TEdit;
chkRestoreLastDB: TCheckBox;
chkUpdatecheck: TCheckBox;
editUpdatecheckInterval: TEdit;
SynSQLSynSQLSample: TSynSQLSyn;
btnRestoreDefaults: TButton;
lblMaxTotalRows: TLabel;
editGridRowCountMax: TEdit;
chkDoStatistics: TCheckBox;
tabShortcuts: TTabSheet;
TreeShortcutItems: TLazVirtualStringTree;
lblShortcut1: TLabel;
lblShortcutHint: TLabel;
lblShortcut2: TLabel;
chkAllowMultiInstances: TCheckBox;
tabLogging: TTabSheet;
Label4: TLabel;
editLogLines: TEdit;
lblLogLinesHint: TLabel;
lblLogSnipHint: TLabel;
editLogSnip: TEdit;
lblLogSnip: TLabel;
chkLogToFile: TCheckBox;
editLogDir: TEditButton;
lblLogLevel: TLabel;
chkLogEventErrors: TCheckBox;
chkLogEventUserGeneratedSQL: TCheckBox;
chkLogEventSQL: TCheckBox;
chkLogEventInfo: TCheckBox;
chkLogEventDebug: TCheckBox;
editGridRowCountStep: TEdit;
lblGridRowsLinecount: TLabel;
editGridRowsLineCount: TEdit;
chkColorBars: TCheckBox;
comboSQLFontName: TComboBox;
lblFont: TLabel;
editSQLFontSize: TEdit;
lblSQLFontSizeUnit: TLabel;
chkCompletionProposal: TCheckBox;
chkTabsToSpaces: TCheckBox;
editSQLTabWidth: TEdit;
Label1: TLabel;
lblMaxQueryResults: TLabel;
editMaxQueryResults: TEdit;
lblGridTextColors: TLabel;
comboGridTextColors: TComboBox;
colorBoxGridTextColors: TColorBox;
lblNullBackground: TLabel;
cboxNullBackground: TColorBox;
lblMySQLBinaries: TLabel;
editMySQLBinaries: TEditButton;
lblLanguage: TLabel;
comboAppLanguage: TComboBox;
chkQueryHistory: TCheckBox;
cboxRowBackgroundOdd: TColorBox;
cboxRowBackgroundEven: TColorBox;
Label2: TLabel;
tabDataEditors: TTabSheet;
chkEditorBinary: TCheckBox;
chkEditorDatetime: TCheckBox;
chkPrefillDateTime: TCheckBox;
chkEditorEnum: TCheckBox;
chkEditorSet: TCheckBox;
chkReuseEditorConfiguration: TCheckBox;
chkForeignDropDown: TCheckBox;
chkLocalNumberFormat: TCheckBox;
lblSQLColElement: TLabel;
comboSQLColElement: TComboBox;
chkSQLBold: TCheckBox;
chkSQLItalic: TCheckBox;
lblSQLColBackground: TLabel;
lblSQLColForeground: TLabel;
cboxSQLColForeground: TColorBox;
cboxSQLColBackground: TColorBox;
SynMemoSQLSample: TSynEdit;
editCustomSnippetsDirectory: TEditButton;
lblCustomSnippetsDirectory: TLabel;
chkHintsOnResultTabs: TCheckBox;
lblLineBreakStyle: TLabel;
comboLineBreakStyle: TComboBox;
lblGUIFont: TLabel;
comboGUIFont: TComboBox;
editGUIFontSize: TEdit;
lblGUIFontSize: TLabel;
chkHorizontalScrollbar: TCheckBox;
editQueryHistoryKeepDays: TEdit;
lblQueryHistoryKeepDays: TLabel;
Label3: TLabel;
cboxRowHighlightSameText: TColorBox;
chkWheelZoom: TCheckBox;
chkAutoUppercase: TCheckBox;
lblTheme: TLabel;
comboTheme: TComboBox;
lblEditorColorsPreset: TLabel;
comboEditorColorsPreset: TComboBox;
comboGridTextColorsPreset: TComboBox;
lblIconPack: TLabel;
comboIconPack: TComboBox;
tabFiles: TTabSheet;
chkAskFileSave: TCheckBox;
chkRestoreTabs: TCheckBox;
chkLogEventScript: TCheckBox;
lblWebSearchBaseUrl: TLabel;
comboWebSearchBaseUrl: TComboBox;
chkThemePreview: TCheckBox;
chkCompletionProposalSearchOnMid: TCheckBox;
lblLongSortRowNum: TLabel;
editLongSortRowNum: TEdit;
chkLowercaseHex: TCheckBox;
chkTabCloseOnDoubleClick: TCheckBox;
lblRealTrailingZeros: TLabel;
editRealTrailingZeros: TEdit;
lblRealTrailingZerosHint: TLabel;
chkLogTimestamp: TCheckBox;
lblCompletionProposal: TLabel;
editCompletionProposalInterval: TEdit;
lblCompletionProposalIntervalUnit: TLabel;
chkColumnHeaderClick: TCheckBox;
chkIncrementalSearch: TCheckBox;
chkShowRowId: TCheckBox;
chkTabCloseOnMiddleClick: TCheckBox;
btnRemoveHotKey1: TSpeedButton;
btnRemoveHotKey2: TSpeedButton;
comboTabIconsGrayscaleMode: TComboBox;
Label5: TLabel;
lblReformatter: TLabel;
comboReformatter: TComboBox;
procedure editTerminalButtonClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure Modified(Sender: TObject);
procedure Apply(Sender: TObject);
procedure GetMonoFonts(const AList: TStrings);
procedure SQLFontChange(Sender: TObject);
procedure DataFontsChange(Sender: TObject);
procedure anyUpDownLimitChanging(Sender: TObject;
var AllowChange: Boolean);
procedure editLogDirRightButtonClick(Sender: TObject);
procedure chkLogToFileClick(Sender: TObject);
procedure chkUpdatecheckClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure comboSQLColElementChange(Sender: TObject);
procedure pagecontrolMainChanging(Sender: TObject;
var AllowChange: Boolean);
procedure pagecontrolMainChange(Sender: TObject);
procedure updownSQLFontSizeClick(Sender: TObject; Button: TUDBtnType);
procedure SynMemoSQLSampleClick(Sender: TObject);
procedure btnRestoreDefaultsClick(Sender: TObject);
procedure TreeShortcutItemsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
procedure TreeShortcutItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType; var CellText: String);
procedure TreeShortcutItemsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
procedure TreeShortcutItemsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
procedure TreeShortcutItemsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
procedure TreeShortcutItemsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
procedure TreeShortcutItemsFocusChanging(Sender: TBaseVirtualTree; OldNode,
NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
var Allowed: Boolean);
procedure comboGridTextColorsSelect(Sender: TObject);
procedure colorBoxGridTextColorsSelect(Sender: TObject);
procedure editMySQLBinariesRightButtonClick(Sender: TObject);
procedure editGridRowCountExit(Sender: TObject);
procedure editCustomSnippetsDirectoryRightButtonClick(Sender: TObject);
procedure comboGUIFontChange(Sender: TObject);
procedure chkQueryHistoryClick(Sender: TObject);
procedure comboEditorColorsPresetChange(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure comboGridTextColorsPresetSelect(Sender: TObject);
procedure chkCompletionProposalClick(Sender: TObject);
procedure btnRemoveHotKeyClick(Sender: TObject);
private
{ Private declarations }
FWasModified: Boolean;
FShortcutCategories: TStringList;
FAppColorScheme: TAppColorScheme;
FLanguages: TStringList;
FRestartOptionTouched: Boolean;
FRestartOptionApplied: Boolean;
procedure InitLanguages;
procedure SelectDirectory(Sender: TObject; NewFolderButton: Boolean);
function EnsureShortcutIsUnused(RequestShortcut: TShortCut): Boolean;
procedure ShowShortCut(Index: Integer);
public
{ Public declarations }
end;
var
frmPreferences: TfrmPreferences;
implementation
uses main, apphelpers, extfiledialog;
{$R *.lfm}
procedure TfrmPreferences.Modified(Sender: TObject);
begin
// Modified
btnApply.Enabled := True;
// Sending controls with a Tag property > 0 (normally 1) need an application restart
if (Sender is TComponent) and (TComponent(Sender).Tag <> 0) then begin
FRestartOptionTouched := True;
end;
end;
procedure TfrmPreferences.pagecontrolMainChanging(Sender: TObject;
var AllowChange: Boolean);
begin
// Remember modification state. First tab switch leads TEdit's with TUpDown
// to fire OnChange. Avoid enabling the buttons in that case.
FWasModified := btnApply.Enabled;
end;
procedure TfrmPreferences.pagecontrolMainChange(Sender: TObject);
begin
// See OnChanging procedure
btnApply.Enabled := FWasModified;
TExtForm.PageControlTabHighlight(pagecontrolMain);
end;
{**
Apply settings to registry and mainform
}
procedure TfrmPreferences.Apply(Sender: TObject);
var
CatNode, ItemNode: PVirtualNode;
Data: PShortcutItemData;
LangCode: String;
begin
Screen.Cursor := crHourGlass;
// Save values
AppSettings.WriteBool(asAutoReconnect, chkAutoReconnect.Checked);
AppSettings.WriteBool(asAllowMultipleInstances, chkAllowMultiInstances.Checked);
AppSettings.WriteBool(asRestoreLastUsedDB, chkRestoreLastDB.Checked);
AppSettings.WriteString(asFontName, comboSQLFontName.Text);
AppSettings.WriteInt(asFontSize, MakeInt(editSQLFontSize.Text));
AppSettings.WriteInt(asTabWidth, MakeInt(editSQLTabWidth.Text));
AppSettings.WriteInt(asLogsqlnum, MakeInt(editLogLines.Text));
AppSettings.WriteInt(asLogsqlwidth, MakeInt(editLogSnip.Text));
AppSettings.WriteString(asSessionLogsDirectory, editLogDir.Text);
AppSettings.WriteBool(asLogErrors, chkLogEventErrors.Checked);
AppSettings.WriteBool(asLogUserSQL, chkLogEventUserGeneratedSQL.Checked);
AppSettings.WriteBool(asLogSQL, chkLogEventSQL.Checked);
AppSettings.WriteBool(asLogScript, chkLogEventScript.Checked);
AppSettings.WriteBool(asLogInfos, chkLogEventInfo.Checked);
AppSettings.WriteBool(asLogDebug, chkLogEventDebug.Checked);
AppSettings.WriteBool(asQueryHistoryEnabled, chkQueryHistory.Checked);
AppSettings.WriteInt(asQueryHistoryKeepDays, MakeInt(editQueryHistoryKeepDays.Text));
AppSettings.WriteBool(asLogHorizontalScrollbar, chkHorizontalScrollbar.Checked);
AppSettings.WriteBool(asLogTimestamp, chkLogTimestamp.Checked);
FAppColorScheme.Apply;
AppColorSchemes.First.LoadFromSettings;
AppSettings.WriteInt(asMaxColWidth, MakeInt(editMaxColWidth.Text));
AppSettings.WriteInt(asDatagridRowsPerStep, StrToIntDef(editGridRowCountStep.Text, -1));
AppSettings.WriteInt(asDatagridMaximumRows, StrToIntDef(editGridRowCountMax.Text, -1));
AppSettings.WriteInt(asGridRowLineCount, MakeInt(editGridRowsLineCount.Text));
AppSettings.WriteString(asDataFontName, comboDataFontName.Text);
AppSettings.WriteInt(asDataFontSize, MakeInt(editDataFontSize.Text));
AppSettings.WriteBool(asLogToFile, chkLogToFile.Checked);
AppSettings.WriteBool(asUpdatecheck, chkUpdatecheck.Checked);
AppSettings.WriteInt(asUpdatecheckInterval, MakeInt(editUpdatecheckInterval.Text));
AppSettings.WriteBool(asDoUsageStatistics, chkDoStatistics.Checked);
AppSettings.WriteBool(asWheelZoom, chkWheelZoom.Checked);
AppSettings.WriteBool(asDisplayBars, chkColorBars.Checked);
AppSettings.WriteString(asMySQLBinaries, editMySQLBinaries.Text);
AppSettings.WriteString(asTerminal, editTerminal.Text);
if comboAppLanguage.ItemIndex > 0 then begin
// Get language code from the left text in the dropdown item text, up to the colon
LangCode := RegExprGetMatch('^(\w+)\b', comboAppLanguage.Text, 1);
end else begin
LangCode := '';
end;
AppSettings.WriteString(asAppLanguage, LangCode);
if comboGUIFont.ItemIndex = 0 then
AppSettings.WriteString(asGUIFontName, '')
else
AppSettings.WriteString(asGUIFontName, comboGUIFont.Text);
AppSettings.WriteInt(asGUIFontSize, MakeInt(editGUIFontSize.Text));
AppSettings.WriteInt(asThemeMode, comboTheme.ItemIndex);
AppSettings.WriteString(asIconPack, comboIconPack.Text);
AppSettings.WriteString(asWebSearchBaseUrl, comboWebSearchBaseUrl.Text);
AppSettings.WriteInt(asMaxQueryResults, MakeInt(editMaxQueryResults.Text));
AppSettings.WriteInt(asFieldNullBackground, cboxNullBackground.Selected);
AppSettings.WriteInt(asRowBackgroundEven, cboxRowBackgroundEven.Selected);
AppSettings.WriteInt(asRowBackgroundOdd, cboxRowBackgroundOdd.Selected);
AppSettings.WriteInt(asHightlightSameTextBackground, cboxRowHighlightSameText.Selected);
AppSettings.WriteInt(asRealTrailingZeros, MakeInt(editRealTrailingZeros.Text));
AppSettings.WriteInt(asQueryGridLongSortRowNum, MakeInt(editLongSortRowNum.Text));
AppSettings.WriteBool(asDataLocalNumberFormat, chkLocalNumberFormat.Checked);
AppSettings.WriteBool(asLowercaseHex, chkLowercaseHex.Checked);
AppSettings.WriteBool(asHintsOnResultTabs, chkHintsOnResultTabs.Checked);
AppSettings.WriteBool(asShowRowId, chkShowRowId.Checked);
// Editor Configuration
AppSettings.WriteBool(asFieldEditorBinary, chkEditorBinary.Checked);
AppSettings.WriteBool(asFieldEditorDatetime, chkEditorDatetime.Checked);
AppSettings.WriteBool(asFieldEditorDatetimePrefill, chkPrefillDatetime.Checked);
AppSettings.WriteBool(asFieldEditorEnum, chkEditorEnum.Checked);
AppSettings.WriteBool(asFieldEditorSet, chkEditorSet.Checked);
AppSettings.WriteBool(asColumnHeaderClick, chkColumnHeaderClick.Checked);
AppSettings.WriteBool(asReuseEditorConfiguration, chkReuseEditorConfiguration.Checked);
AppSettings.WriteBool(asForeignDropDown, chkForeignDropDown.Checked);
AppSettings.WriteBool(asIncrementalSearch, chkIncrementalSearch.Checked);
case comboLineBreakStyle.ItemIndex of
1: AppSettings.WriteInt(asLineBreakStyle, Integer(lbsUnix));
2: AppSettings.WriteInt(asLineBreakStyle, Integer(lbsMac));
else AppSettings.WriteInt(asLineBreakStyle, Integer(lbsWindows));
end;
AppSettings.WriteBool(asCompletionProposal, chkCompletionProposal.Checked);
AppSettings.WriteInt(asCompletionProposalInterval, MakeInt(editCompletionProposalInterval.Text));
AppSettings.WriteBool(asCompletionProposalSearchOnMid, chkCompletionProposalSearchOnMid.Checked);
AppSettings.WriteBool(asAutoUppercase, chkAutoUppercase.Checked);
AppSettings.WriteBool(asTabsToSpaces, chkTabsToSpaces.Checked);
// Shortcuts
TreeShortcutItems.FocusedNode := nil; // Triggers OnFocusCanging and applies current changes
CatNode := TreeShortcutItems.GetFirst;
while Assigned(CatNode) do begin
ItemNode := TreeShortcutItems.GetFirstChild(CatNode);
while Assigned(ItemNode) do begin
Data := TreeShortcutItems.GetNodeData(ItemNode);
// Save modified shortcuts
if Assigned(Data.KeyStroke) then begin
if Data.Shortcut1 <> Data.KeyStroke.ShortCut then
AppSettings.WriteInt(asActionShortcut1, Data.Shortcut1, EditorCommandToCodeString(Data.KeyStroke.Command));
if Data.Shortcut2 <> Data.KeyStroke.ShortCut2 then
AppSettings.WriteInt(asActionShortcut2, Data.Shortcut2, EditorCommandToCodeString(Data.KeyStroke.Command));
end else begin
if Data.Shortcut1 <> Data.Action.ShortCut then
AppSettings.WriteInt(asActionShortcut1, Data.Shortcut1, Data.Action.Name);
// Apply shortcut for this session
Data.Action.ShortCut := Data.Shortcut1;
end;
ItemNode := TreeShortcutItems.GetNextSibling(ItemNode);
end;
CatNode := TreeShortcutItems.GetNextSibling(CatNode);
end;
// Populate SynMemo settings to all instances
Mainform.SetupSynEditors;
// Files and tabs
AppSettings.WriteBool(asPromptSaveFileOnTabClose, chkAskFileSave.Checked);
AppSettings.WriteBool(asRestoreTabs, chkRestoreTabs.Checked);
AppSettings.WriteBool(asTabCloseOnDoubleClick, chkTabCloseOnDoubleClick.Checked);
AppSettings.WriteBool(asTabCloseOnMiddleClick, chkTabCloseOnMiddleClick.Checked);
AppSettings.WriteInt(asTabIconsGrayscaleMode, comboTabIconsGrayscaleMode.ItemIndex);
AppSettings.WriteInt(asReformatterNoDialog, comboReformatter.ItemIndex);
AppSettings.WriteString(asCustomSnippetsDirectory, editCustomSnippetsDirectory.Text);
// Set relevant properties in mainform
MainForm.ApplyFontToGrids;
MainForm.PrepareImageList;
//MainForm.SynCompletionProposal.TimerInterval := updownCompletionProposalInterval.Position;
Mainform.LogToFile := chkLogToFile.Checked;
MainForm.actLogHorizontalScrollbar.Checked := chkHorizontalScrollbar.Checked;
MainForm.actLogHorizontalScrollbar.OnExecute(MainForm.actLogHorizontalScrollbar);
Mainform.DataLocalNumberFormat := chkLocalNumberFormat.Checked;
Mainform.DataGrid.Repaint;
Mainform.QueryGrid.Repaint;
Mainform.ListTables.Invalidate;
Mainform.ListProcesses.Invalidate;
Mainform.ListCommandStats.Invalidate;
FRestartOptionApplied := FRestartOptionTouched;
// Settings have been applied, send a signal to the user
btnApply.Enabled := False;
Screen.Cursor := crDefault;
end;
// List monospace fonts
procedure TfrmPreferences.GetMonoFonts(const AList: TStrings);
const
TestChars = 'ilMW 0';
var
Bmp: TBitmap;
FName: string;
i: Integer;
w0, w: Integer;
IsMono: Boolean;
begin
AList.Clear;
Bmp := TBitmap.Create;
try
for FName in Screen.Fonts do begin
Bmp.Canvas.Font.Name := FName;
Bmp.Canvas.Font.Size := 10; // any reasonable size
w0 := Bmp.Canvas.TextWidth(TestChars[1]);
IsMono := True;
for i := 2 to Length(TestChars) do
begin
w := Bmp.Canvas.TextWidth(TestChars[i]);
if w <> w0 then
begin
IsMono := False;
Break;
end;
end;
if IsMono then
AList.Add(FName);
end;
finally
Bmp.Free;
end;
end;
procedure TfrmPreferences.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if FRestartOptionApplied then begin
MessageDialog(f_('You should restart %s to apply changed critical settings, and to prevent unexpected behaviour.', [APPNAME]),
mtInformation,
[mbOk]);
end;
MainForm.ActionList1.State := asNormal;
end;
procedure TfrmPreferences.FormCreate(Sender: TObject);
var
i: Integer;
dtc: TDBDatatypeCategoryIndex;
//Styles: TArray<String>;
ColorScheme: TAppColorScheme;
IconPack: String;
Reformatter: TfrmReformatter;
begin
Width := AppSettings.ReadInt(asPreferencesWindowWidth);
Height := AppSettings.ReadInt(asPreferencesWindowHeight);
// General tab
editTerminal.Enabled := {$IFDEF WINDOWS} False {$ELSE} True {$ENDIF};
lblTerminal.Enabled := editTerminal.Enabled;
InitLanguages;
comboAppLanguage.Items.AddStrings(FLanguages);
comboGUIFont.Items.Assign(Screen.Fonts);
comboGUIFont.Items.Insert(0, '<'+_('Default system font')+'>');
{$IFDEF WINDOWS}
comboTheme.Items.Add(_('Automatic, depending on system settings'));
comboTheme.Items.Add(_('Light'));
comboTheme.Items.Add(_('Dark'));
{$ELSE}
lblTheme.Enabled := False;
comboTheme.Items.Text := 'Themes are not supported in the Lazarus release';
comboTheme.Enabled := False;
{$ENDIF}
comboTheme.ItemIndex := 0;
// Populate icon pack dropdown from image collections on main form
comboIconPack.Items.Clear;
for i:=0 to MainForm.ComponentCount-1 do begin
if (MainForm.Components[i] is TImageList) and (MainForm.Components[i].Tag <> 0) then begin
IconPack := MainForm.Components[i].Name;
IconPack := StringReplace(IconPack, 'ImageList', '', [rfIgnoreCase]);
comboIconPack.Items.Add(IconPack);
end;
end;
// This is the color scheme we modify in-memory
FAppColorScheme := TAppColorScheme.Create;
FAppColorScheme.LoadFromSettings;
// Data
// Populate datatype categories pulldown
for dtc:=Low(TDBDatatypeCategoryIndex) to High(TDBDatatypeCategoryIndex) do
comboGridTextColors.Items.Add(DatatypeCategories[dtc].Name);
// SQL
GetMonoFonts(comboSQLFontName.Items);
SynMemoSQLSample.Text := 'SELECT DATE_SUB(NOW(), INTERVAL 1 DAY),' + sLineBreak +
CodeIndent + '''String literal'' AS lit' + sLineBreak +
'FROM tableA AS ta' + sLineBreak +
'WHERE `columnA` IS NULL;' + sLineBreak +
sLineBreak +
'-- A comment' + sLineBreak +
'# Old style comment' + sLineBreak +
'/* Multi line comment */' + sLineBreak +
sLineBreak +
'CREATE TABLE /*!32312 IF NOT EXISTS*/ tableB (' + sLineBreak +
CodeIndent + 'id INT,' + sLineBreak +
CodeIndent + 'name VARCHAR(30) DEFAULT "standard"' + sLineBreak +
')';
SynSQLSynSQLSample.TableNames.CommaText := 'tableA,tableB';
for i:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin
SynSQLSynSQLSample.Attribute[i].AssignColorAndStyle(FAppColorScheme.SynSqlSyn.Attribute[i]);
comboSQLColElement.Items.Add(SynSQLSynSQLSample.Attribute[i].Name);
end;
comboSQLColElement.Items.Add(_('Active line background'));
comboSQLColElement.Items.Add(_('Brace matching color'));
comboSQLColElement.ItemIndex := 0;
// Enumerate highlighter presets
for ColorScheme in AppColorSchemes do begin
comboEditorColorsPreset.Items.Add(_(ColorScheme.Name));
end;
// Grid formatting
// Add presets to combo box
comboGridTextColorsPreset.Clear;
for ColorScheme in AppColorSchemes do begin
comboGridTextColorsPreset.Items.Add(_(ColorScheme.Name));
end;
// Shortcuts
btnRemoveHotKey1.Enabled := False;
btnRemoveHotKey2.Enabled := False;
FShortcutCategories := TStringList.Create;
for i:=0 to Mainform.ActionList1.ActionCount-1 do begin
if FShortcutCategories.IndexOf(Mainform.ActionList1.Actions[i].Category) = -1 then
FShortcutCategories.Add(Mainform.ActionList1.Actions[i].Category);
end;
FShortcutCategories.Add(_('SQL editing'));
TreeShortcutItems.RootNodeCount := FShortcutCategories.Count;
comboLineBreakStyle.Items := Explode(',', _('Windows linebreaks')+','+_('UNIX linebreaks')+','+_('Mac OS linebreaks'));
GetVKNames(comboShortcut1Key.Items);
GetVKNames(comboShortcut2Key.Items);
comboReformatter.Items.Add(_('Always ask'));
Reformatter := TfrmReformatter.Create(Self);
comboReformatter.Items.AddStrings(Reformatter.grpReformatter.Items);
Reformatter.Free;
end;
procedure TfrmPreferences.FormShow(Sender: TObject);
var
LangCode, GUIFont: String;
i: Integer;
begin
Screen.Cursor := crHourGlass;
// Read and display values
chkAutoReconnect.Checked := AppSettings.ReadBool(asAutoReconnect);;
chkAllowMultiInstances.Checked := AppSettings.ReadBool(asAllowMultipleInstances);
chkRestoreLastDB.Checked := AppSettings.ReadBool(asRestoreLastUsedDB);
chkUpdatecheck.Checked := AppSettings.ReadBool(asUpdatecheck);
editUpdatecheckInterval.Text := AppSettings.ReadInt(asUpdatecheckInterval).ToString;
chkUpdatecheckClick(Sender);
chkDoStatistics.Checked := AppSettings.ReadBool(asDoUsageStatistics);
chkWheelZoom.Checked := AppSettings.ReadBool(asWheelZoom);
chkColorBars.Checked := AppSettings.ReadBool(asDisplayBars);
editMySQLBinaries.Text := AppSettings.ReadString(asMySQLBinaries);
editTerminal.Text := AppSettings.ReadString(asTerminal);
LangCode := AppSettings.ReadString(asAppLanguage);
for i:=0 to comboAppLanguage.Items.Count-1 do begin
if RegExprGetMatch('^(\w+)\b', comboAppLanguage.Items[i], 1) = LangCode then begin
comboAppLanguage.ItemIndex := i;
Break;
end;
end;
if comboAppLanguage.ItemIndex = -1 then
comboAppLanguage.ItemIndex := 0;
GUIFont := AppSettings.ReadString(asGUIFontName);
if GUIFont.IsEmpty then
comboGUIFont.ItemIndex := 0
else
comboGUIFont.ItemIndex := comboGUIFont.Items.IndexOf(GUIFont);
editGUIFontSize.Text := AppSettings.ReadInt(asGUIFontSize).ToString;
comboGUIFont.OnChange(comboGUIFont);
comboTheme.ItemIndex := AppSettings.ReadInt(asThemeMode);
comboIconPack.ItemIndex := comboIconPack.Items.IndexOf(AppSettings.ReadString(asIconPack));
comboWebSearchBaseUrl.Text := AppSettings.ReadString(asWebSearchBaseUrl);
// Logging
editLogLines.Text := AppSettings.ReadInt(asLogsqlnum).ToString;
editLogSnip.Text := AppSettings.ReadInt(asLogsqlwidth).ToString;
chkLogToFile.Checked := AppSettings.ReadBool(asLogToFile);
editLogDir.Text := AppSettings.ReadString(asSessionLogsDirectory);
chkLogEventErrors.Checked := AppSettings.ReadBool(asLogErrors);
chkLogEventUserGeneratedSQL.Checked := AppSettings.ReadBool(asLogUserSQL);
chkLogEventSQL.Checked := AppSettings.ReadBool(asLogSQL);
chkLogEventScript.Checked := AppSettings.ReadBool(asLogScript);
chkLogEventInfo.Checked := AppSettings.ReadBool(asLogInfos);
chkLogEventDebug.Checked := AppSettings.ReadBool(asLogDebug);
chkQueryHistory.Checked := AppSettings.ReadBool(asQueryHistoryEnabled);
editQueryHistoryKeepDays.Text := AppSettings.ReadInt(asQueryHistoryKeepDays).ToString;
chkHorizontalScrollbar.Checked := AppSettings.ReadBool(asLogHorizontalScrollbar);
chkLogTimestamp.Checked := AppSettings.ReadBool(asLogTimestamp);
// Default column width in grids:
editMaxColWidth.Text := AppSettings.ReadInt(asMaxColWidth).ToString;
editGridRowCountStep.Text := IntToStr(AppSettings.ReadInt(asDatagridRowsPerStep));
editGridRowCountMax.Text := IntToStr(AppSettings.ReadInt(asDatagridMaximumRows));
editGridRowsLineCount.Text := AppSettings.ReadInt(asGridRowLineCount).ToString;
// SQL:
Mainform.SetupSynEditor(SynMemoSQLSample);
comboSQLFontName.ItemIndex := comboSQLFontName.Items.IndexOf(SynMemoSQLSample.Font.Name);
editSQLFontSize.Text := SynMemoSQLSample.Font.Size.ToString;
editSQLTabWidth.Text := SynMemoSQLSample.TabWidth.ToString;
chkCompletionProposal.Checked := AppSettings.ReadBool(asCompletionProposal);
editCompletionProposalInterval.Text := AppSettings.ReadInt(asCompletionProposalInterval).ToString;
chkCompletionProposalSearchOnMid.Checked := AppSettings.ReadBool(asCompletionProposalSearchOnMid);
chkAutoUppercase.Checked := AppSettings.ReadBool(asAutoUppercase);
chkTabsToSpaces.Checked := AppSettings.ReadBool(asTabsToSpaces);
comboEditorColorsPreset.ItemIndex := 0;
comboSQLColElement.ItemIndex := 0;
comboSQLColElementChange(Sender);
// Grid formatting:
comboDataFontName.Items := Screen.Fonts;
comboDataFontName.ItemIndex := comboDataFontName.Items.IndexOf(AppSettings.ReadString(asDataFontName));
editDataFontSize.Text := AppSettings.ReadInt(asDataFontSize).ToString;
editMaxQueryResults.Text := AppSettings.ReadINt(asMaxQueryResults).ToString;
comboGridTextColorsPreset.ItemIndex := 0;
comboGridTextColors.ItemIndex := 0;
comboGridTextColorsSelect(comboGridTextColors);
cboxNullBackground.Selected := AppSettings.ReadInt(asFieldNullBackground);
cboxRowBackgroundEven.Selected := AppSettings.ReadInt(asRowBackgroundEven);
cboxRowBackgroundOdd.Selected := AppSettings.ReadInt(asRowBackgroundOdd);
cboxRowHighlightSameText.Selected := AppSettings.ReadInt(asHightlightSameTextBackground);
editRealTrailingZeros.Text := AppSettings.ReadInt(asRealTrailingZeros).ToString;
editLongSortRowNum.Text := AppSettings.ReadInt(asQueryGridLongSortRowNum).ToString;
chkLocalNumberFormat.Checked := AppSettings.ReadBool(asDataLocalNumberFormat);
chkLowercaseHex.Checked := AppSettings.ReadBool(asLowercaseHex);
chkHintsOnResultTabs.Checked := AppSettings.ReadBool(asHintsOnResultTabs);
chkShowRowId.Checked := AppSettings.ReadBool(asShowRowId);
// Editor Configuration
chkEditorBinary.Checked := AppSettings.ReadBool(asFieldEditorBinary);
chkEditorDatetime.Checked := AppSettings.ReadBool(asFieldEditorDatetime);
chkPrefillDateTime.Checked := AppSettings.ReadBool(asFieldEditorDatetimePrefill);
chkEditorEnum.Checked := AppSettings.ReadBool(asFieldEditorEnum);
chkEditorSet.Checked := AppSettings.ReadBool(asFieldEditorEnum);
chkColumnHeaderClick.Checked := AppSettings.ReadBool(asColumnHeaderClick);
chkReuseEditorConfiguration.Checked := AppSettings.ReadBool(asReuseEditorConfiguration);
chkForeignDropDown.Checked := AppSettings.ReadBool(asForeignDropDown);
chkIncrementalSearch.Checked := AppSettings.ReadBool(asIncrementalSearch);
case TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)) of
lbsNone, lbsWindows: comboLineBreakStyle.ItemIndex := 0;
lbsUnix: comboLineBreakStyle.ItemIndex := 1;
lbsMac: comboLineBreakStyle.ItemIndex := 2;
end;
// Shortcuts
TreeShortcutItems.ReinitChildren(nil, True);
SelectNode(TreeShortcutItems, nil);
// Files and tabs
chkAskFileSave.Checked := AppSettings.ReadBool(asPromptSaveFileOnTabClose);
chkRestoreTabs.Checked := AppSettings.ReadBool(asRestoreTabs);
chkTabCloseOnDoubleClick.Checked := AppSettings.ReadBool(asTabCloseOnDoubleClick);
chkTabCloseOnMiddleClick.Checked := AppSettings.ReadBool(asTabCloseOnMiddleClick);
comboTabIconsGrayscaleMode.ItemIndex := AppSettings.ReadInt(asTabIconsGrayscaleMode);
comboReformatter.ItemIndex := AppSettings.ReadInt(asReformatterNoDialog);
editCustomSnippetsDirectory.Text := AppSettings.ReadString(asCustomSnippetsDirectory);
// Disable global shortcuts
MainForm.ActionList1.State := asSuspended;
TExtForm.PageControlTabHighlight(pagecontrolMain);
FRestartOptionTouched := False;
btnApply.Enabled := False;
screen.Cursor := crdefault;
end;
procedure TfrmPreferences.FormDestroy(Sender: TObject);
begin
AppSettings.WriteInt(asPreferencesWindowWidth, ScaleFormToDesign(Width));
AppSettings.WriteInt(asPreferencesWindowHeight, ScaleFormToDesign(Height));
end;
procedure TfrmPreferences.editTerminalButtonClick(Sender: TObject);
var
Dialog: TExtFileOpenDialog;
begin
Dialog := TExtFileOpenDialog.Create(Self);
Dialog.AddFileType('*.*', _('All files'));
if Dialog.Execute then
editTerminal.Text := Dialog.FileName;
Dialog.Free;
end;
procedure TfrmPreferences.SQLFontChange(Sender: TObject);
var
AttriIdx: Integer;
Attri: TSynHighlighterAttributes;
Foreground, Background: TColor;
begin
if comboSQLFontName.ItemIndex > -1 then
SynMemoSQLSample.Font.Name := comboSQLFontName.Items[comboSQLFontName.ItemIndex];
SynMemoSQLSample.Font.Size := MakeInt(editSQLFontSize.Text);
SynMemoSQLSample.TabWidth := MakeInt(editSQLTabWidth.Text);
AttriIdx := comboSQLColElement.ItemIndex;
Foreground := cboxSQLColForeground.Selected;
Background := cboxSQLColBackground.Selected;
if AttriIdx = comboSQLColElement.Items.Count-1 then begin
FAppColorScheme.MatchingBraceForeground := Foreground;
FAppColorScheme.MatchingBraceBackground := Background;
end else if AttriIdx = comboSQLColElement.Items.Count-2 then begin
SynMemoSQLSample.LineHighlightColor.Background := Background;
FAppColorScheme.ActiveLineBackground := Background;
end else begin
Attri := SynSqlSynSQLSample.Attribute[AttriIdx];
Attri.Foreground := Foreground;
Attri.Background := Background;
if chkSQLBold.Checked then Attri.Style := Attri.Style + [fsBold]
else Attri.Style := Attri.Style - [fsBold];
if chkSQLItalic.Checked then Attri.Style := Attri.Style + [fsItalic]
else Attri.Style := Attri.Style - [fsItalic];
Attri := FAppColorScheme.SynSqlSyn.Attribute[AttriIdx];
Attri.Foreground := Foreground;
Attri.Background := Background;
end;
Modified(Sender);
end;
procedure TfrmPreferences.DataFontsChange(Sender: TObject);
begin
Modified(Sender);
end;
procedure TfrmPreferences.anyUpDownLimitChanging(Sender: TObject;
var AllowChange: Boolean);
begin
Modified(Sender);
end;
procedure TfrmPreferences.editGridRowCountExit(Sender: TObject);
var
Edit: TEdit;
begin
// Row count step and maximum shall never be "0", to avoid problems in
// data grids. See issue #3080.
Edit := Sender as TEdit;
if MakeInt(Edit.Text) <= 0 then
Edit.Text := '1';
end;
procedure TfrmPreferences.SelectDirectory(Sender: TObject; NewFolderButton: Boolean);
var
Browse: TSelectDirectoryDialog;
Edit: TEditButton;
begin
// Select folder for any option
Edit := Sender as TEditButton;
Browse := TSelectDirectoryDialog.Create(Self);
Browse.InitialDir := Edit.Text;
Browse.Title := _(Edit.TextHint);
//Browse.BrowseOptions := Browse.BrowseOptions + [bifNewDialogStyle];
//if not NewFolderButton then
// Browse.BrowseOptions := Browse.BrowseOptions + [bifNoNewFolderButton];
if Browse.Execute then begin
Edit.Text := Browse.FileName;
Modified(Sender);
end;
Browse.Free;
end;
procedure TfrmPreferences.editLogDirRightButtonClick(Sender: TObject);
begin
// Select folder for session logs
SelectDirectory(Sender, True);
end;
procedure TfrmPreferences.editMySQLBinariesRightButtonClick(Sender: TObject);
begin
// Select folder where MySQL binaries reside
SelectDirectory(Sender, False);
end;
procedure TfrmPreferences.editCustomSnippetsDirectoryRightButtonClick(Sender: TObject);
begin
// Set custom snippets directory
SelectDirectory(Sender, True);
end;
{**
Updatecheck checkbox was clicked
}
procedure TfrmPreferences.chkUpdatecheckClick(Sender: TObject);
begin
editUpdatecheckInterval.Enabled := chkUpdatecheck.Checked;
Modified(Sender);
end;
procedure TfrmPreferences.chkCompletionProposalClick(Sender: TObject);
var
Enable: Boolean;
begin
Enable := TCheckBox(Sender).Checked;
editCompletionProposalInterval.Enabled := Enable;
lblCompletionProposalIntervalUnit.Enabled := Enable;
chkCompletionProposalSearchOnMid.Enabled := Enable;
Modified(Sender);
end;
procedure TfrmPreferences.chkLogToFileClick(Sender: TObject);
begin
editLogDir.Enabled := TCheckBox(Sender).Checked;
Modified(Sender);
end;
procedure TfrmPreferences.chkQueryHistoryClick(Sender: TObject);
begin
editQueryHistoryKeepDays.Enabled := chkQueryHistory.Checked;
lblQueryHistoryKeepDays.Enabled := chkQueryHistory.Checked;
Modified(Sender);
end;
procedure TfrmPreferences.comboEditorColorsPresetChange(Sender: TObject);
var
j: Integer;
ColorScheme: TAppColorScheme;
begin
// Color preset selected
ColorScheme := AppColorSchemes[comboEditorColorsPreset.ItemIndex];
for j:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin
SynSQLSynSQLSample.Attribute[j].AssignColorAndStyle(ColorScheme.SynSqlSyn.Attribute[j]);
FAppColorScheme.SynSqlSyn.Attribute[j].AssignColorAndStyle(ColorScheme.SynSqlSyn.Attribute[j]);
end;
SynMemoSQLSample.LineHighlightColor.Background := ColorScheme.ActiveLineBackground;
SynMemoSQLSample.BracketMatchColor.Foreground := ColorScheme.MatchingBraceForeground;
SynMemoSQLSample.BracketMatchColor.Background := ColorScheme.MatchingBraceBackground;
FAppColorScheme.ActiveLineBackground := ColorScheme.ActiveLineBackground;
FAppColorScheme.MatchingBraceForeground := ColorScheme.MatchingBraceForeground;
FAppColorScheme.MatchingBraceBackground := ColorScheme.MatchingBraceBackground;
comboSQLColElementChange(comboSQLColElement);
Modified(Sender);
end;
procedure TfrmPreferences.comboGridTextColorsPresetSelect(Sender: TObject);
var
ColorScheme: TAppColorScheme;
dtc: TDBDatatypeCategoryIndex;
begin
// Grid colors preset selected
ColorScheme := AppColorSchemes[comboGridTextColorsPreset.ItemIndex];
for dtc:=Low(ColorScheme.GridTextColors) to High(ColorScheme.GridTextColors) do begin
FAppColorScheme.GridTextColors[dtc] := ColorScheme.GridTextColors[dtc];
end;
comboGridTextColorsSelect(comboGridTextColors);
if comboGridTextColorsPreset.ItemIndex > 0 then
Modified(Sender);
end;
procedure TfrmPreferences.comboGridTextColorsSelect(Sender: TObject);
begin
// Data type category selected
colorboxGridTextColors.Selected := FAppColorScheme.GridTextColors[TDBDatatypeCategoryIndex(comboGridTextColors.ItemIndex)];
end;
procedure TfrmPreferences.comboGUIFontChange(Sender: TObject);
var
UseCustomFont: Boolean;
begin
// System font selected
UseCustomFont := comboGUIFont.ItemIndex > 0;
editGUIFontSize.Enabled := UseCustomFont;
lblGUIFontSize.Enabled := UseCustomFont;
Modified(Sender);
end;
procedure TfrmPreferences.colorBoxGridTextColorsSelect(Sender: TObject);
begin
// Color selected
FAppColorScheme.GridTextColors[TDBDatatypeCategoryIndex(comboGridTextColors.ItemIndex)] := colorboxGridTextColors.Selected;
Modified(Sender);
end;
procedure TfrmPreferences.comboSQLColElementChange(Sender: TObject);
var
AttriIdx: Integer;
Attri: TSynHighlighterAttributes;
Foreground, Background: TColor;
begin
AttriIdx := comboSQLColElement.ItemIndex;
if AttriIdx = comboSQLColElement.Items.Count-1 then begin
Foreground := SynMemoSQLSample.BracketMatchColor.Foreground;
Background := SynMemoSQLSample.BracketMatchColor.Background;
chkSQLBold.Enabled := False;
chkSQLItalic.Enabled := False;
end else if AttriIdx = comboSQLColElement.Items.Count-2 then begin
Foreground := clNone;
Background := SynMemoSQLSample.LineHighlightColor.Background;
chkSQLBold.Enabled := False;
chkSQLItalic.Enabled := False;
end else begin
Attri := SynSqlSynSQLSample.Attribute[AttriIdx];
Foreground := Attri.Foreground;
Background := Attri.Background;
chkSQLBold.Enabled := True;
chkSQLItalic.Enabled := True;
chkSQLBold.OnClick := nil;
chkSQLItalic.OnClick := nil;
chkSQLBold.Checked := fsBold in Attri.Style;
chkSQLItalic.Checked := fsItalic in Attri.Style;
chkSQLBold.OnClick := SQLFontChange;
chkSQLItalic.OnClick := SQLFontChange;
end;
cboxSQLColForeground.Selected := Foreground;
cboxSQLColBackground.Selected := Background;
end;
procedure TfrmPreferences.updownSQLFontSizeClick(Sender: TObject;
Button: TUDBtnType);
begin
SQLFontChange(Sender);
end;
{**
Select attribute in pulldown by click into SynMemo
}
procedure TfrmPreferences.SynMemoSQLSampleClick(Sender: TObject);
var
Token: String;
Attri: TSynHighlighterAttributes;
AttriIdx: Integer;
sm: TSynEdit;
begin
sm := Sender as TSynEdit;
sm.GetHighlighterAttriAtRowCol(sm.CaretXY, Token, Attri);
if Attri = nil then
Exit;
AttriIdx := ComboSQLColElement.Items.IndexOf(Attri.Name);
if AttriIdx = -1 then
Exit;
ComboSQLColElement.ItemIndex := AttriIdx;
ComboSQLColElement.OnChange(Sender);
end;
procedure TfrmPreferences.btnRemoveHotKeyClick(Sender: TObject);
begin
// Clear shortcut controls, and let the OnFocusChanging event store the removed value.
if Sender = btnRemoveHotKey1 then begin
chkShortcut1Shift.Checked := False;
chkShortcut1Alt.Checked := False;
chkShortcut1Control.Checked := False;
comboShortcut1Key.ItemIndex := GetVKIndexByCode(VK_UNKNOWN);
end
else if Sender = btnRemoveHotKey2 then begin
chkShortcut2Shift.Checked := False;
chkShortcut2Alt.Checked := False;
chkShortcut2Control.Checked := False;
comboShortcut2Key.ItemIndex := GetVKIndexByCode(VK_UNKNOWN);
end
else
Beep;
end;
procedure TfrmPreferences.btnRestoreDefaultsClick(Sender: TObject);
var
ValueList: TStringlist;
i: Integer;
begin
// Restore defaults
if MessageDialog(_('Reset all preference options to default values?'),
_('This also applies to automatic settings, e.g. toolbar positions.'),
mtConfirmation, [mbOK, mbCancel]) = mrCancel then
Exit;
AppSettings.ResetPath;
ValueList := AppSettings.GetValueNames;
for i:=0 to ValueList.Count-1 do
AppSettings.DeleteValue(ValueList[i]);
FormShow(Sender);
end;
procedure TfrmPreferences.TreeShortcutItemsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex);
var
ShortcutFocused: Boolean;
Data: PShortcutItemData;
begin
// Shortcut item focus change in tree
ShortcutFocused := Assigned(Node) and (Sender.GetNodeLevel(Node) = 1);
lblShortcutHint.Enabled := ShortcutFocused;
lblShortcut1.Enabled := ShortcutFocused;
lblShortcut2.Enabled := ShortcutFocused;
chkShortcut1Shift.Enabled := lblShortcut1.Enabled;
chkShortcut1Alt.Enabled := lblShortcut1.Enabled;
chkShortcut1Control.Enabled := lblShortcut1.Enabled;
comboShortcut1Key.Enabled := lblShortcut1.Enabled;
btnRemoveHotKey1.Enabled := lblShortcut1.Enabled;
if ShortcutFocused then begin
Data := Sender.GetNodeData(Node);
lblShortcutHint.Caption := TreeShortcutItems.Text[Node, 0];
if Assigned(Data.Action) then begin
lblShortcut2.Enabled := False;
if MainForm.ActionList1DefaultHints[Data.Action.Index] <> '' then
lblShortcutHint.Caption := MainForm.ActionList1DefaultHints[Data.Action.Index];
end;
ShowShortCut(1);
ShowShortCut(2);
end;
chkShortcut2Shift.Enabled := lblShortcut2.Enabled;
chkShortcut2Alt.Enabled := lblShortcut2.Enabled;
chkShortcut2Control.Enabled := lblShortcut2.Enabled;
comboShortcut2Key.Enabled := lblShortcut2.Enabled;
btnRemoveHotKey2.Enabled := lblShortcut2.Enabled;
end;
procedure TfrmPreferences.ShowShortCut(Index: Integer);
var
Data: PShortcutItemData;
Key: Word;
Shift: TShiftState;
begin
Data := TreeShortcutItems.GetNodeData(TreeShortcutItems.FocusedNode);
case Index of
1: begin
ShortCutToKey(Data.ShortCut1, Key, Shift);
chkShortcut1Shift.Checked := ssShift in Shift;
chkShortcut1Alt.Checked := ssAlt in Shift;
chkShortcut1Control.Checked := ssCtrl in Shift;
comboShortcut1Key.ItemIndex := GetVKIndexByCode(Key);
end;
2: begin
ShortCutToKey(Data.ShortCut2, Key, Shift);
chkShortcut2Shift.Checked := ssShift in Shift;
chkShortcut2Alt.Checked := ssAlt in Shift;
chkShortcut2Control.Checked := ssCtrl in Shift;
comboShortcut2Key.ItemIndex := GetVKIndexByCode(Key);
end;
end;
end;
procedure TfrmPreferences.TreeShortcutItemsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
var
Data: PShortcutItemData;
begin
// Fetch icon number of shortcut item
if not (Kind in [ikNormal, ikSelected]) then Exit;
if Sender.GetNodeLevel(Node) = 1 then begin
Data := Sender.GetNodeData(Node);
if Assigned(Data.KeyStroke) then
ImageIndex := 114
else if Assigned(Data.Action) then
ImageIndex := Data.Action.ImageIndex;
end;
end;
procedure TfrmPreferences.TreeShortcutItemsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
begin
NodeDataSize := SizeOf(TShortcutItemData);
end;
procedure TfrmPreferences.TreeShortcutItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType; var CellText: String);
var
Data: PShortcutItemData;
i: Integer;
t: String;
begin
// Fetch text of shortcut item
case Sender.GetNodeLevel(Node) of
0: CellText := FShortcutCategories[Node.Index];
1: begin
Data := Sender.GetNodeData(Node);
if Assigned(Data.KeyStroke) then begin
t := EditorCommandToCodeString(Data.KeyStroke.Command);
t := Copy(t, 3, Length(t)-2);
// Insert spaces before uppercase chars
CellText := '';
for i:=1 to Length(t) do begin
if (i > 1) and (UpperCase(t[i]) = t[i]) then
CellText := CellText + ' ';
CellText := CellText + t[i];
end;
CellText := _(CellText);
end else if Assigned(Data.Action) then begin
CellText := StripHotkey(MainForm.ActionList1DefaultCaptions[Data.Action.Index]);
end;
end;
end;
end;
procedure TfrmPreferences.TreeShortcutItemsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
var ChildCount: Cardinal);
var
i: Integer;
Category: String;
begin
// First initialization of shortcut items
if Sender.GetNodeLevel(Node) = 0 then begin
ChildCount := 0;
if Integer(Node.Index) = FShortcutCategories.Count-1 then
ChildCount := Mainform.SynMemoQuery.Keystrokes.Count
else begin
Category := (Sender as TLazVirtualStringTree).Text[Node, 0];
for i:=0 to Mainform.ActionList1.ActionCount-1 do begin
if Mainform.ActionList1.Actions[i].Category = Category then
Inc(ChildCount);
end;
end;
end;
end;
procedure TfrmPreferences.TreeShortcutItemsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
var
Data: PShortcutItemData;
ItemIndex, i: Integer;
Category: String;
begin
if Sender.GetNodeLevel(Node) = 0 then
Include(InitialStates, ivsHasChildren);
Data := Sender.GetNodeData(Node);
if Sender.GetNodeLevel(Node) = 1 then begin
if Integer(Node.Parent.Index) = FShortcutCategories.Count-1 then begin
Data^.KeyStroke := Mainform.SynMemoQuery.Keystrokes[Node.Index];
Data^.Shortcut1 := Data.KeyStroke.ShortCut;
Data^.Shortcut2 := Data.KeyStroke.ShortCut2;
end else begin
ItemIndex := -1;
Category := (Sender as TLazVirtualStringTree).Text[Node.Parent, 0];
for i:=0 to Mainform.ActionList1.ActionCount-1 do begin
if Mainform.ActionList1.Actions[i].Category = Category then
Inc(ItemIndex);
if ItemIndex = Integer(Node.Index) then begin
Data^.Action := TAction(Mainform.ActionList1.Actions[i]);
Data^.Shortcut1 := Data.Action.ShortCut;
break;
end;
end;
end;
end;
end;
function TfrmPreferences.EnsureShortcutIsUnused(RequestShortcut: TShortCut): Boolean;
var
Node, NodeWantsIt: PVirtualNode;
Data: PShortcutItemData;
Tree: TLazVirtualStringTree;
MsgFormat, Msg: String;
begin
Result := True;
if RequestShortcut = 0 then
Exit;
MsgFormat := _('Keyboard shortcut [%s] is already assigned to "%s".') + sLineBreak + sLineBreak +
_('Remove it there and assign to "%s" instead?') + sLineBreak + sLineBreak +
_('Press ignore to keep both and ignore all conflicts.');
Tree := TreeShortcutItems;
NodeWantsIt := Tree.FocusedNode;
Node := GetNextNode(Tree, nil, False);
while Assigned(Node) do begin
if Tree.GetNodeLevel(Node) = 1 then begin
Data := Tree.GetNodeData(Node);
Msg := Format(MsgFormat, [
ShortCutToText(RequestShortcut),
Tree.Text[Node.Parent, 0] + ' > ' + StripHotkey(Tree.Text[Node, 0]),
Tree.Text[NodeWantsIt.Parent, 0] + ' > ' + StripHotkey(Tree.Text[NodeWantsIt, 0])
]);
if Node = NodeWantsIt then begin
// Ignore requesting node
end else begin
if Data.ShortCut1 = RequestShortcut then begin
case MessageDialog(Msg, mtConfirmation, [mbYes, mbNo, mbIgnore]) of
mrYes: Data.ShortCut1 := 0; // Unassign shortcut 1
mrNo: Result := False;
mrIgnore: Break; // Keep Result=True and exit loop, ignore further conflicts
end;
end;
if Data.ShortCut2 = RequestShortcut then begin
case MessageDialog(Msg, mtConfirmation, [mbYes, mbNo, mbIgnore]) of
mrYes: Data.ShortCut2 := 0; // Unassign shortcut 2
mrNo: Result := False;
mrIgnore: Break;
end;
end;
end;
end;
if Result = False then
Break;
Node := GetNextNode(Tree, Node, False);
end;
end;
procedure TfrmPreferences.TreeShortcutItemsFocusChanging(
Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn,
NewColumn: TColumnIndex; var Allowed: Boolean);
var
Data: PShortcutItemData;
NewShortCut: TShortCut;
Shift: TShiftState;
begin
// Check if shortcut 1 or 2 changed
if (not Assigned(OldNode)) or (TreeShortcutItems.GetNodeLevel(OldNode) = 0) then
Exit;
Data := TreeShortcutItems.GetNodeData(OldNode);
Allowed := True;
Shift := [];
if chkShortcut1Shift.Checked then Include(Shift, ssShift);
if chkShortcut1Alt.Checked then Include(Shift, ssAlt);
if chkShortcut1Control.Checked then Include(Shift, ssCtrl);
NewShortCut := KeyToShortCut(VKcodes[comboShortcut1Key.ItemIndex].Code, Shift);
if NewShortCut <> Data.ShortCut1 then begin
if EnsureShortcutIsUnused(NewShortCut) then begin
Data.ShortCut1 := NewShortCut;
Modified(Sender);
end
else
ShowShortCut(1);
end;
if chkShortcut2Shift.Enabled then begin
Shift := [];
if chkShortcut2Shift.Checked then Include(Shift, ssShift);
if chkShortcut2Alt.Checked then Include(Shift, ssAlt);
if chkShortcut2Control.Checked then Include(Shift, ssCtrl);
NewShortCut := KeyToShortCut(VKcodes[comboShortcut2Key.ItemIndex].Code, Shift);
if NewShortCut <> Data.ShortCut2 then begin
if EnsureShortcutIsUnused(NewShortCut) then begin
Data.ShortCut2 := NewShortCut;
Modified(Sender);
end
else
ShowShortCut(2);
end;
end;
end;
procedure TfrmPreferences.InitLanguages;
var
LangNames: String;
MoFilePath, LangCode: String;
AvailLangCodes: TStringList;
AvailMoFiles: TStringList;
i: Integer;
procedure AddLang(LangCode: String);
var
LangName: String;
rx: TRegExpr;
begin
rx := TRegExpr.Create;
rx.Expression := '\b'+QuoteRegExprMetaChars(LangCode)+'\:([^#]+)';
rx.ModifierI := True;
if rx.Exec(LangNames) then
LangName := rx.Match[1]
else
LangName := '';
rx.Free;
FLanguages.Add(LangCode + ': ' + LangName);
end;
begin
// Create list with present language code => language name
// List taken from dxgettext/languagecodes.pas
LangNames := 'aa:Afar#'+
'aa:Afar#'+
'ab:Abkhazian#'+
'ae:Avestan#'+
'af:Afrikaans#'+
'ak:Akan#'+
'am:Amharic#'+
'an:Aragonese#'+
'ar:Arabic#'+
'as:Assamese#'+
'av:Avaric#'+
'ay:Aymara#'+
'az:Azerbaijani#'+
'ba:Bashkir#'+
'be:Belarusian#'+
'bg:Bulgarian#'+
'bh:Bihari#'+
'bi:Bislama#'+
'bm:Bambara#'+
'bn:Bengali#'+
'bo:Tibetan#'+
'br:Breton#'+
'bs:Bosnian#'+
'ca:Catalan#'+
'ce:Chechen#'+
'ch:Chamorro#'+
'co:Corsican#'+
'cr:Cree#'+
'cs:Czech#'+
'cv:Chuvash#'+
'cy:Welsh#'+
'da:Danish#'+
'de:German#'+
'de_AT:Austrian German#'+
'de_CH:Swiss German#'+
'dv:Divehi#'+
'dz:Dzongkha#'+
'ee:Ewe#'+
'el:Greek#'+
'en:English#'+
'en_AU:Australian English#'+
'en_CA:Canadian English#'+
'en_GB:British English#'+
'en_US:American English#'+
'eo:Esperanto#'+
'es:Spanish#'+
'et:Estonian#'+
'eu:Basque#'+
'fa:Persian#'+
'ff:Fulah#'+
'fi:Finnish#'+
'fj:Fijian#'+
'fo:Faroese#'+
'fr:French#'+
'fr_BE:Walloon#'+
'fy:Frisian#'+
'ga:Irish#'+
'gd:Gaelic#'+
'gl:Gallegan#'+
'gn:Guarani#'+
'gu:Gujarati#'+
'gv:Manx#'+
'ha:Hausa#'+
'he:Hebrew#'+
'hi:Hindi#'+
'ho:Hiri Motu#'+
'hr:Croatian#'+
'hr_HR:Croatian#'+ // Added, exists on Transifex
'ht:Haitian#'+
'hu:Hungarian#'+
'hy:Armenian#'+
'hz:Herero#'+
'ia:Interlingua#'+
'id:Indonesian#'+
'ie:Interlingue#'+
'ig:Igbo#'+
'ii:Sichuan Yi#'+
'ik:Inupiaq#'+
'io:Ido#'+
'is:Icelandic#'+
'it:Italian#'+
'iu:Inuktitut#'+
'ja:Japanese#'+
'jv:Javanese#'+
'ka:Georgian#'+
'kg:Kongo#'+
'ki:Kikuyu#'+
'kj:Kuanyama#'+
'kk:Kazakh#'+
'kl:Greenlandic#'+
'km:Khmer#'+
'kn:Kannada#'+
'ko:Korean#'+
'kr:Kanuri#'+
'ks:Kashmiri#'+
'ku:Kurdish#'+
'kw:Cornish#'+
'kv:Komi#'+
'ky:Kirghiz#'+
'la:Latin#'+
'lb:Luxembourgish#'+
'lg:Ganda#'+
'li:Limburgan#'+
'ln:Lingala#'+
'lo:Lao#'+
'lt:Lithuanian#'+
'lu:Luba-Katanga#'+
'lv:Latvian#'+
'mg:Malagasy#'+
'mh:Marshallese#'+
'mi:Maori#'+
'mk:Macedonian#'+
'ml:Malayalam#'+
'mn:Mongolian#'+
'mo:Moldavian#'+
'mr:Marathi#'+
'ms:Malay#'+
'mt:Maltese#'+
'my:Burmese#'+
'na:Nauru#'+
'nb:Norwegian Bokmaal#'+
'nd:Ndebele, North#'+
'ne:Nepali#'+
'ng:Ndonga#'+
'nl:Dutch#'+
'nl_BE:Flemish#'+
'nn:Norwegian Nynorsk#'+
'no:Norwegian#'+
'nr:Ndebele, South#'+
'nv:Navajo#'+
'ny:Chichewa#'+
'oc:Occitan#'+
'oj:Ojibwa#'+
'om:Oromo#'+
'or:Oriya#'+
'os:Ossetian#'+
'pa:Panjabi#'+
'pi:Pali#'+
'pl:Polish#'+
'ps:Pushto#'+
'pt:Portuguese#'+
'pt_BR:Brazilian Portuguese#'+
'qu:Quechua#'+
'rm:Raeto-Romance#'+
'rn:Rundi#'+
'ro:Romanian#'+
'ru:Russian#'+
'rw:Kinyarwanda#'+
'sa:Sanskrit#'+
'sc:Sardinian#'+
'sd:Sindhi#'+
'se:Northern Sami#'+
'sg:Sango#'+
'si:Sinhalese#'+
'sk:Slovak#'+
'sl:Slovenian#'+
'sm:Samoan#'+
'sn:Shona#'+
'so:Somali#'+
'sq:Albanian#'+
'sr:Serbian#'+
'ss:Swati#'+
'st:Sotho, Southern#'+
'su:Sundanese#'+
'sv:Swedish#'+
'sw:Swahili#'+
'ta:Tamil#'+
'te:Telugu#'+
'tg:Tajik#'+
'th:Thai#'+
'ti:Tigrinya#'+
'tk:Turkmen#'+
'tl:Tagalog#'+
'tn:Tswana#'+
'to:Tonga#'+
'tr:Turkish#'+
'ts:Tsonga#'+
'tt:Tatar#'+
'tw:Twi#'+
'ty:Tahitian#'+
'ug:Uighur#'+
'uk:Ukrainian#'+
'ur:Urdu#'+
'uz:Uzbek#'+
've:Venda#'+
'vi:Vietnamese#'+
'vo:Volapuk#'+
'wa:Walloon#'+
'wo:Wolof#'+
'xh:Xhosa#'+
'yi:Yiddish#'+
'yo:Yoruba#'+
'za:Zhuang#'+
'zh:Chinese (Simplified)#'+ // Added, see #498
'zh_CN:Chinese (China)#'+
'zh_TW:Chinese (Traditional)#'+
'zu:Zulu#';
FLanguages := TStringList.Create;
AvailLangCodes := TStringList.Create;
AvailMoFiles := FindAllFiles(
ExtractFilePath(AppLanguageMoBasePath),
ExtractFileName(AppLanguageMoBasePath) + '*.mo',
False
);
for MoFilePath in AvailMoFiles do begin
LangCode := RegExprGetMatch('\.(\w+)\.\w+$', ExtractFileName(MoFilePath), 1);
if not LangCode.IsEmpty then
AvailLangCodes.Add(LangCode)
else
AvailLangCodes.Add('en'); // Default en file has just ".mo" extension, not ".en.mo"
end;
for i:=0 to AvailLangCodes.Count-1 do begin
AddLang(AvailLangCodes[i]);
end;
FLanguages.Sort;
FLanguages.Insert(0, '*** '+f_('Auto detect (%s)', [SysLanguage]));
if FLanguages.Count <= 1 then
FLanguages[0] := 'English only - no .mo files found in ' + ExtractFilePath(AppLanguageMoBasePath);
AvailMoFiles.Free;
AvailLangCodes.Free;
end;
end.