mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
960 lines
32 KiB
ObjectPascal
960 lines
32 KiB
ObjectPascal
unit connections;
|
|
|
|
|
|
// -------------------------------------
|
|
// Connections (start-window)
|
|
// -------------------------------------
|
|
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls,
|
|
VirtualTrees, Menus, Graphics, Generics.Collections,
|
|
dbconnection;
|
|
|
|
type
|
|
Tconnform = class(TForm)
|
|
btnCancel: TButton;
|
|
btnOpen: TButton;
|
|
btnSave: TButton;
|
|
ListSessions: TVirtualStringTree;
|
|
btnNew: TButton;
|
|
btnDelete: TButton;
|
|
popupSessions: TPopupMenu;
|
|
Save1: TMenuItem;
|
|
Delete1: TMenuItem;
|
|
Saveas1: TMenuItem;
|
|
TimerStatistics: TTimer;
|
|
PageControlDetails: TPageControl;
|
|
tabSettings: TTabSheet;
|
|
lblStartupScript: TLabel;
|
|
lblPort: TLabel;
|
|
lblPassword: TLabel;
|
|
lblHost: TLabel;
|
|
lblUsername: TLabel;
|
|
lblNetworkType: TLabel;
|
|
editStartupScript: TButtonedEdit;
|
|
chkCompressed: TCheckBox;
|
|
editPort: TEdit;
|
|
updownPort: TUpDown;
|
|
editPassword: TEdit;
|
|
editUsername: TEdit;
|
|
editHost: TEdit;
|
|
tabSSLOptions: TTabSheet;
|
|
lblSSLPrivateKey: TLabel;
|
|
lblSSLCACertificate: TLabel;
|
|
lblSSLCertificate: TLabel;
|
|
editSSLPrivateKey: TButtonedEdit;
|
|
editSSLCACertificate: TButtonedEdit;
|
|
editSSLCertificate: TButtonedEdit;
|
|
tabStatistics: TTabSheet;
|
|
lblLastConnectLeft: TLabel;
|
|
lblCounterLeft: TLabel;
|
|
lblCreatedLeft: TLabel;
|
|
lblCreatedRight: TLabel;
|
|
lblCounterRight: TLabel;
|
|
lblLastConnectRight: TLabel;
|
|
tabSSHtunnel: TTabSheet;
|
|
editSSHlocalport: TEdit;
|
|
editSSHUser: TEdit;
|
|
editSSHPassword: TEdit;
|
|
lblSSHLocalPort: TLabel;
|
|
lblSSHUser: TLabel;
|
|
lblSSHPassword: TLabel;
|
|
editSSHPlinkExe: TButtonedEdit;
|
|
lblSSHPlinkExe: TLabel;
|
|
comboNetType: TComboBox;
|
|
lblSSHhost: TLabel;
|
|
editSSHhost: TEdit;
|
|
editSSHport: TEdit;
|
|
editSSHPrivateKey: TButtonedEdit;
|
|
lblSSHkeyfile: TLabel;
|
|
lblDownloadPlink: TLabel;
|
|
comboDatabases: TComboBox;
|
|
lblDatabase: TLabel;
|
|
chkLoginPrompt: TCheckBox;
|
|
lblPlinkTimeout: TLabel;
|
|
editSSHTimeout: TEdit;
|
|
updownSSHTimeout: TUpDown;
|
|
chkWindowsAuth: TCheckBox;
|
|
splitterMain: TSplitter;
|
|
tabStart: TTabSheet;
|
|
lblHelp: TLabel;
|
|
chkWantSSL: TCheckBox;
|
|
btnImportSettings: TButton;
|
|
timerSettingsImport: TTimer;
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure btnOpenClick(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure btnSaveClick(Sender: TObject);
|
|
procedure btnSaveAsClick(Sender: TObject);
|
|
procedure btnNewClick(Sender: TObject);
|
|
procedure btnDeleteClick(Sender: TObject);
|
|
procedure Modification(Sender: TObject);
|
|
procedure ListSessionsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
|
Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
|
|
procedure ListSessionsFocusChanged(Sender: TBaseVirtualTree;
|
|
Node: PVirtualNode; Column: TColumnIndex);
|
|
procedure ListSessionsGetImageIndex(Sender: TBaseVirtualTree;
|
|
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
|
|
var Ghosted: Boolean; var ImageIndex: Integer);
|
|
procedure ListSessionsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
|
Column: TColumnIndex; NewText: String);
|
|
procedure ListSessionsFocusChanging(Sender: TBaseVirtualTree; OldNode,
|
|
NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
|
|
var Allowed: Boolean);
|
|
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure TimerStatisticsTimer(Sender: TObject);
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure ListSessionsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
|
|
out EditLink: IVTEditLink);
|
|
procedure PickFile(Sender: TObject);
|
|
procedure editSSHPlinkExeChange(Sender: TObject);
|
|
procedure editHostChange(Sender: TObject);
|
|
procedure lblDownloadPlinkClick(Sender: TObject);
|
|
procedure comboDatabasesDropDown(Sender: TObject);
|
|
procedure chkLoginPromptClick(Sender: TObject);
|
|
procedure ListSessionsInitNode(Sender: TBaseVirtualTree; ParentNode,
|
|
Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
|
|
procedure ListSessionsGetNodeDataSize(Sender: TBaseVirtualTree;
|
|
var NodeDataSize: Integer);
|
|
procedure comboNetTypeChange(Sender: TObject);
|
|
procedure splitterMainMoved(Sender: TObject);
|
|
procedure btnImportSettingsClick(Sender: TObject);
|
|
procedure timerSettingsImportTimer(Sender: TObject);
|
|
private
|
|
{ Private declarations }
|
|
FLoaded: Boolean;
|
|
FSessions: TObjectList<TConnectionParameters>;
|
|
FSessionModified, FOnlyPasswordModified, FSessionAdded: Boolean;
|
|
FServerVersion: String;
|
|
FSessionColor: TColor;
|
|
FSettingsImportWaitTime: Cardinal;
|
|
procedure SetSessions;
|
|
function SelectedSession: String;
|
|
function CurrentParams: TConnectionParameters;
|
|
procedure FinalizeModifications(var CanProceed: Boolean);
|
|
procedure SaveCurrentValues(Session: String; IsNew: Boolean);
|
|
procedure ValidateControls;
|
|
public
|
|
{ Public declarations }
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
uses Main, helpers, grideditlinks;
|
|
|
|
{$I const.inc}
|
|
|
|
{$R *.DFM}
|
|
|
|
|
|
procedure Tconnform.FormCreate(Sender: TObject);
|
|
var
|
|
LastActiveSession: String;
|
|
LastSessions: TStringList;
|
|
PSess: PConnectionParameters;
|
|
hSysMenu: THandle;
|
|
nt: TNetType;
|
|
Node: PVirtualNode;
|
|
Params: TConnectionParameters;
|
|
begin
|
|
// Fix GUI stuff
|
|
InheritFont(Font);
|
|
SetWindowSizeGrip(Handle, True);
|
|
Width := GetRegValue(REGNAME_SESSMNGR_WINWIDTH, Width);
|
|
Height := GetRegValue(REGNAME_SESSMNGR_WINHEIGHT, Height);
|
|
ListSessions.Width := GetRegValue(REGNAME_SESSMNGR_LISTWIDTH, ListSessions.Width);
|
|
splitterMain.OnMoved(Sender);
|
|
FixVT(ListSessions);
|
|
MainForm.RestoreListSetup(ListSessions);
|
|
ListSessions.OnCompareNodes := MainForm.AnyGridCompareNodes;
|
|
ListSessions.OnHeaderClick := MainForm.AnyGridHeaderClick;
|
|
ListSessions.OnHeaderDraggedOut := MainForm.AnyGridHeaderDraggedOut;
|
|
btnImportSettings.Caption := MainForm.actImportSettings.Caption;
|
|
FLoaded := False;
|
|
|
|
comboNetType.Clear;
|
|
Params := TConnectionParameters.Create;
|
|
for nt:=Low(nt) to High(nt) do
|
|
comboNetType.Items.Add(Params.NetTypeName(nt, True));
|
|
Params.Free;
|
|
|
|
FSessions := TObjectList<TConnectionParameters>.Create;
|
|
SetSessions;
|
|
|
|
// Focus last session
|
|
SelectNode(ListSessions, nil);
|
|
LastSessions := Explode(DELIM, GetRegValue(REGNAME_LASTSESSIONS, ''));
|
|
LastActiveSession := GetRegValue(REGNAME_LASTACTIVESESSION, '');
|
|
if (LastActiveSession = '') and (LastSessions.Count > 0) then
|
|
LastActiveSession := LastSessions[0];
|
|
Node := ListSessions.GetFirst;
|
|
while Assigned(Node) do begin
|
|
PSess := ListSessions.GetNodeData(Node);
|
|
if PSess.SessionName = LastActiveSession then
|
|
SelectNode(ListSessions, Node);
|
|
Node := ListSessions.GetNextSibling(Node);
|
|
end;
|
|
|
|
// Add own menu items to system menu
|
|
hSysMenu := GetSystemMenu(Handle, False);
|
|
AppendMenu(hSysMenu, MF_SEPARATOR, 0, #0);
|
|
AppendMenu(hSysMenu, MF_STRING, MSG_UPDATECHECK, PChar(Mainform.actUpdateCheck.Caption));
|
|
AppendMenu(hSysMenu, MF_STRING, MSG_PREFERENCES, PChar(Mainform.actPreferences.Caption));
|
|
AppendMenu(hSysMenu, MF_STRING, MSG_ABOUT, PChar(Mainform.actAboutBox.Caption));
|
|
end;
|
|
|
|
|
|
procedure Tconnform.SetSessions;
|
|
var
|
|
SessionNames: TStringList;
|
|
i: Integer;
|
|
Sess: TConnectionParameters;
|
|
begin
|
|
// Initialize session tree
|
|
SessionNames := TStringList.Create;
|
|
MainReg.OpenKey(RegPath + REGKEY_SESSIONS, True);
|
|
MainReg.GetKeyNames(SessionNames);
|
|
for i:=0 to SessionNames.Count-1 do begin
|
|
Sess := TConnectionParameters.ReadFromRegistry(SessionNames[i]);
|
|
FSessions.Add(Sess);
|
|
end;
|
|
ListSessions.RootNodeCount := FSessions.Count;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.FormDestroy(Sender: TObject);
|
|
begin
|
|
// Save GUI stuff
|
|
OpenRegistry;
|
|
MainReg.WriteInteger(REGNAME_SESSMNGR_LISTWIDTH, ListSessions.Width);
|
|
MainReg.WriteInteger(REGNAME_SESSMNGR_WINWIDTH, Width);
|
|
MainReg.WriteInteger(REGNAME_SESSMNGR_WINHEIGHT, Height);
|
|
MainForm.SaveListSetup(ListSessions);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
|
begin
|
|
// Modifications? Ask if they should be saved.
|
|
FinalizeModifications(CanClose);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.FormClose(Sender: TObject; var Action: TCloseAction);
|
|
begin
|
|
// Suspend calculating statistics as long as they're not visible
|
|
TimerStatistics.Enabled := False;
|
|
Action := caFree;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.FormShow(Sender: TObject);
|
|
begin
|
|
ListSessions.SetFocus;
|
|
// Reactivate statistics
|
|
TimerStatistics.Enabled := True;
|
|
TimerStatistics.OnTimer(Sender);
|
|
FLoaded := True;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.btnOpenClick(Sender: TObject);
|
|
var
|
|
Connection: TDBConnection;
|
|
begin
|
|
// Connect to selected session
|
|
Screen.Cursor := crHourglass;
|
|
if Mainform.InitConnection(CurrentParams, True, Connection) then
|
|
ModalResult := mrOK
|
|
else begin
|
|
TimerStatistics.OnTimer(Sender);
|
|
ModalResult := mrNone;
|
|
end;
|
|
Screen.Cursor := crDefault;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.SaveCurrentValues(Session: String; IsNew: Boolean);
|
|
var
|
|
Sess: PConnectionParameters;
|
|
begin
|
|
OpenRegistry(Session);
|
|
MainReg.WriteString(REGNAME_HOST, editHost.Text);
|
|
MainReg.WriteBool(REGNAME_WINDOWSAUTH, chkWindowsAuth.Checked);
|
|
MainReg.WriteString(REGNAME_USER, editUsername.Text);
|
|
MainReg.WriteString(REGNAME_PASSWORD, encrypt(editPassword.Text));
|
|
MainReg.WriteBool(REGNAME_LOGINPROMPT, chkLoginPrompt.Checked);
|
|
MainReg.WriteString(REGNAME_PORT, IntToStr(updownPort.Position));
|
|
MainReg.WriteInteger(REGNAME_NETTYPE, comboNetType.ItemIndex);
|
|
MainReg.WriteBool(REGNAME_COMPRESSED, chkCompressed.Checked);
|
|
MainReg.WriteString(REGNAME_DATABASES, comboDatabases.Text);
|
|
MainReg.WriteString(REGNAME_STARTUPSCRIPT, editStartupScript.Text);
|
|
MainReg.WriteString(REGNAME_SSHHOST, editSSHHost.Text);
|
|
MainReg.WriteInteger(REGNAME_SSHPORT, MakeInt(editSSHport.Text));
|
|
MainReg.WriteString(REGNAME_SSHUSER, editSSHUser.Text);
|
|
MainReg.WriteString(REGNAME_SSHPASSWORD, encrypt(editSSHPassword.Text));
|
|
MainReg.WriteInteger(REGNAME_SSHTIMEOUT, updownSSHTimeout.Position);
|
|
MainReg.WriteString(REGNAME_SSHKEY, editSSHPrivateKey.Text);
|
|
MainReg.WriteInteger(REGNAME_SSHLOCALPORT, MakeInt(editSSHlocalport.Text));
|
|
MainReg.WriteBool(REGNAME_SSL_ACTIVE, chkWantSSL.Checked);
|
|
MainReg.WriteString(REGNAME_SSL_KEY, editSSLPrivateKey.Text);
|
|
MainReg.WriteString(REGNAME_SSL_CERT, editSSLCertificate.Text);
|
|
MainReg.WriteString(REGNAME_SSL_CA, editSSLCACertificate.Text);
|
|
if IsNew then
|
|
MainReg.WriteString(REGNAME_SESSIONCREATED, DateTimeToStr(Now));
|
|
OpenRegistry;
|
|
MainReg.WriteString(REGNAME_PLINKEXE, editSSHPlinkExe.Text);
|
|
|
|
// Overtake edited values for in-memory parameter object
|
|
Sess := ListSessions.GetNodeData(ListSessions.FocusedNode);
|
|
Sess.Hostname := editHost.Text;
|
|
Sess.Username := editUsername.Text;
|
|
Sess.Password := editPassword.Text;
|
|
Sess.LoginPrompt := chkLoginPrompt.Checked;
|
|
Sess.WindowsAuth := chkWindowsAuth.Checked;
|
|
Sess.Port := updownPort.Position;
|
|
Sess.NetType := TNetType(comboNetType.ItemIndex);
|
|
Sess.Compressed := chkCompressed.Checked;
|
|
Sess.AllDatabasesStr := comboDatabases.Text;
|
|
Sess.StartupScriptFilename := editStartupScript.Text;
|
|
Sess.SSHHost := editSSHhost.Text;
|
|
Sess.SSHPort := MakeInt(editSSHport.Text);
|
|
Sess.SSHUser := editSSHUser.Text;
|
|
Sess.SSHPassword := editSSHPassword.Text;
|
|
Sess.SSHTimeout := updownSSHTimeout.Position;
|
|
Sess.SSHPrivateKey := editSSHPrivateKey.Text;
|
|
Sess.SSHLocalPort := MakeInt(editSSHlocalport.Text);
|
|
Sess.WantSSL := chkWantSSL.Checked;
|
|
Sess.SSLPrivateKey := editSSLPrivateKey.Text;
|
|
Sess.SSLCertificate := editSSLCertificate.Text;
|
|
Sess.SSLCACertificate := editSSLCACertificate.Text;
|
|
|
|
FSessionModified := False;
|
|
FSessionAdded := False;
|
|
ListSessions.Invalidate;
|
|
ValidateControls;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.btnSaveClick(Sender: TObject);
|
|
begin
|
|
// Save session settings
|
|
SaveCurrentValues(SelectedSession, FSessionAdded);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.btnSaveAsClick(Sender: TObject);
|
|
var
|
|
newName: String;
|
|
NameOK: Boolean;
|
|
NewSess: TConnectionParameters;
|
|
Node: PVirtualNode;
|
|
begin
|
|
// Save session as ...
|
|
newName := 'Enter new session name ...';
|
|
NameOK := False;
|
|
OpenRegistry;
|
|
while not NameOK do begin
|
|
if not InputQuery('Clone session ...', 'New session name:', newName) then
|
|
Exit; // Cancelled
|
|
NameOK := not MainReg.KeyExists(REGKEY_SESSIONS + newName);
|
|
if not NameOK then
|
|
ErrorDialog('Session name '''+newName+''' already in use.')
|
|
else begin
|
|
// Create the key and save its values
|
|
OpenRegistry(newName);
|
|
SaveCurrentValues(newName, True);
|
|
NewSess := TConnectionParameters.ReadFromRegistry(newName);
|
|
FSessions.Add(NewSess);
|
|
Node := ListSessions.AddChild(nil, @NewSess);
|
|
SelectNode(ListSessions, Node);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.btnImportSettingsClick(Sender: TObject);
|
|
begin
|
|
MainForm.actImportSettings.Execute;
|
|
FSettingsImportWaitTime := 0;
|
|
timerSettingsImport.Enabled := True;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.timerSettingsImportTimer(Sender: TObject);
|
|
begin
|
|
Inc(FSettingsImportWaitTime, timerSettingsImport.Interval);
|
|
SetSessions;
|
|
if FSessions.Count > 0 then
|
|
timerSettingsImport.Enabled := False;
|
|
if FSettingsImportWaitTime >= 10000 then begin
|
|
timerSettingsImport.Enabled := False;
|
|
MessageDialog('Imported sessions could not be detected. Restarting HeidiSQL may solve that.', mtWarning, [mbOK]);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.btnNewClick(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
CanProceed: Boolean;
|
|
NewSess: TConnectionParameters;
|
|
Node: PVirtualNode;
|
|
begin
|
|
// Create new session
|
|
FinalizeModifications(CanProceed);
|
|
if not CanProceed then
|
|
Exit;
|
|
|
|
i := 0;
|
|
NewSess := TConnectionParameters.Create;
|
|
NewSess.SessionName := 'Unnamed';
|
|
while MainReg.KeyExists(RegPath + REGKEY_SESSIONS + NewSess.SessionName) do begin
|
|
inc(i);
|
|
NewSess.SessionName := 'Unnamed-' + IntToStr(i);
|
|
end;
|
|
FSessions.Add(NewSess);
|
|
Node := ListSessions.AddChild(nil, @NewSess);
|
|
// Select it
|
|
SelectNode(ListSessions, Node);
|
|
FSessionAdded := True;
|
|
ValidateControls;
|
|
ListSessions.EditNode(Node, 0);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.btnDeleteClick(Sender: TObject);
|
|
var
|
|
SessionKey: String;
|
|
Sess: PConnectionParameters;
|
|
begin
|
|
Sess := ListSessions.GetNodeData(ListSessions.FocusedNode);
|
|
if MessageDialog('Delete session "' + Sess.SessionName + '" ?', mtConfirmation, [mbYes, mbCancel]) = mrYes then
|
|
begin
|
|
SessionKey := RegPath + REGKEY_SESSIONS + Sess.SessionName;
|
|
if MainReg.KeyExists(SessionKey) then
|
|
MainReg.DeleteKey(SessionKey);
|
|
ListSessions.DeleteSelectedNodes;
|
|
FSessions.Remove(Sess^);
|
|
if (not Assigned(ListSessions.FocusedNode)) and (ListSessions.RootNodeCount > 0) then
|
|
SelectNode(ListSessions, ListSessions.RootNodeCount-1)
|
|
else
|
|
SelectNode(ListSessions, nil);
|
|
end;
|
|
end;
|
|
|
|
|
|
function Tconnform.SelectedSession: String;
|
|
var
|
|
Sess: PConnectionParameters;
|
|
begin
|
|
Sess := ListSessions.GetNodeData(ListSessions.FocusedNode);
|
|
Result := Sess.SessionName;
|
|
end;
|
|
|
|
|
|
function Tconnform.CurrentParams: TConnectionParameters;
|
|
begin
|
|
// Return non-stored parameters
|
|
Result := TConnectionParameters.Create;
|
|
Result.SessionName := SelectedSession;
|
|
Result.SessionColor := FSessionColor;
|
|
Result.NetType := TNetType(comboNetType.ItemIndex);
|
|
Result.ServerVersion := FServerVersion;
|
|
Result.Hostname := editHost.Text;
|
|
Result.Username := editUsername.Text;
|
|
Result.Password := editPassword.Text;
|
|
Result.LoginPrompt := chkLoginPrompt.Checked;
|
|
Result.WindowsAuth := chkWindowsAuth.Checked;
|
|
if updownPort.Enabled then
|
|
Result.Port := updownPort.Position
|
|
else
|
|
Result.Port := 0;
|
|
Result.AllDatabasesStr := comboDatabases.Text;
|
|
Result.SSHHost := editSSHHost.Text;
|
|
Result.SSHPort := MakeInt(editSSHPort.Text);
|
|
Result.SSHUser := editSSHuser.Text;
|
|
Result.SSHPassword := editSSHpassword.Text;
|
|
Result.SSHTimeout := updownSSHTimeout.Position;
|
|
Result.SSHPrivateKey := editSSHPrivateKey.Text;
|
|
Result.SSHLocalPort := MakeInt(editSSHlocalport.Text);
|
|
Result.SSHPlinkExe := editSSHplinkexe.Text;
|
|
Result.WantSSL := chkWantSSL.Checked;
|
|
Result.SSLPrivateKey := editSSLPrivateKey.Text;
|
|
Result.SSLCertificate := editSSLCertificate.Text;
|
|
Result.SSLCACertificate := editSSLCACertificate.Text;
|
|
Result.StartupScriptFilename := editStartupScript.Text;
|
|
Result.Compressed := chkCompressed.Checked;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ListSessionsGetImageIndex(Sender: TBaseVirtualTree;
|
|
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
|
|
var Ghosted: Boolean; var ImageIndex: Integer);
|
|
var
|
|
Sess: PConnectionParameters;
|
|
begin
|
|
// A new session gets an additional plus symbol, editing gets a pencil
|
|
if Column > 0 then
|
|
ImageIndex := -1
|
|
else case Kind of
|
|
ikNormal, ikSelected: begin
|
|
Sess := Sender.GetNodeData(Node);
|
|
ImageIndex := Sess.ImageIndex;
|
|
end;
|
|
|
|
ikOverlay: if Node = Sender.FocusedNode then begin
|
|
if FSessionAdded then
|
|
ImageIndex := 163
|
|
else if FSessionModified then
|
|
ImageIndex := 162;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ListSessionsGetNodeDataSize(Sender: TBaseVirtualTree;
|
|
var NodeDataSize: Integer);
|
|
begin
|
|
NodeDataSize := SizeOf(TConnectionParameters);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ListSessionsGetText(Sender: TBaseVirtualTree;
|
|
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
|
|
var CellText: String);
|
|
var
|
|
Sess: PConnectionParameters;
|
|
begin
|
|
// Display session name cell
|
|
Sess := Sender.GetNodeData(Node);
|
|
case Column of
|
|
0: begin
|
|
CellText := Sess.SessionName;
|
|
if (FSessionModified or FSessionAdded) and (Node = Sender.FocusedNode) and (not Sender.IsEditing) then
|
|
CellText := CellText + ' *';
|
|
end;
|
|
1: CellText := Sess.Hostname;
|
|
2: CellText := Sess.Username;
|
|
3: CellText := Sess.ServerVersion;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ListSessionsInitNode(Sender: TBaseVirtualTree; ParentNode,
|
|
Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
|
|
var
|
|
Sess: PConnectionParameters;
|
|
begin
|
|
Sess := Sender.GetNodeData(Node);
|
|
Sess^ := FSessions[Node.Index];
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ListSessionsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode;
|
|
Column: TColumnIndex; out EditLink: IVTEditLink);
|
|
begin
|
|
// Use our own text editor to rename a session
|
|
EditLink := TInplaceEditorLink.Create(Sender as TVirtualStringTree);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ListSessionsFocusChanged(Sender: TBaseVirtualTree;
|
|
Node: PVirtualNode; Column: TColumnIndex);
|
|
var
|
|
SessionFocused: Boolean;
|
|
Sess: PConnectionParameters;
|
|
begin
|
|
// select one connection!
|
|
Screen.Cursor := crHourglass;
|
|
TimerStatistics.Enabled := False;
|
|
SessionFocused := Assigned(Node);
|
|
FLoaded := False;
|
|
tabStart.TabVisible := not SessionFocused;
|
|
tabSettings.TabVisible := SessionFocused;
|
|
tabSSHtunnel.TabVisible := SessionFocused;
|
|
tabSSLoptions.TabVisible := SessionFocused;
|
|
tabStatistics.TabVisible := SessionFocused;
|
|
|
|
if not SessionFocused then begin
|
|
PageControlDetails.ActivePage := tabStart;
|
|
if FSessions.Count = 0 then
|
|
lblHelp.Caption := 'New here? In order to connect to a server, you have to create a so called '+
|
|
'"session" at first. Just click the "New" button on the bottom left to create your first session.'+CRLF+CRLF+
|
|
'Give it a friendly name (e.g. "Local DB server") so you''ll recall it the next time you start '+APPNAME+'.'
|
|
else
|
|
lblHelp.Caption := 'Please click a session on the left list to edit parameters, doubleclick to open it.';
|
|
end else begin
|
|
PageControlDetails.ActivePage := tabSettings;
|
|
Sess := Sender.GetNodeData(Node);
|
|
|
|
comboNetType.ItemIndex := Integer(Sess.NetType);
|
|
editHost.Text := Sess.Hostname;
|
|
editUsername.Text := Sess.Username;
|
|
editPassword.Text := Sess.Password;
|
|
chkLoginPrompt.Checked := Sess.LoginPrompt;
|
|
chkWindowsAuth.Checked := Sess.WindowsAuth;
|
|
updownPort.Position := Sess.Port;
|
|
chkCompressed.Checked := Sess.Compressed;
|
|
comboDatabases.Text := Sess.AllDatabasesStr;
|
|
editStartupScript.Text := Sess.StartupScriptFilename;
|
|
editSSHPlinkExe.Text := Sess.SSHPlinkExe;
|
|
editSSHHost.Text := Sess.SSHHost;
|
|
editSSHport.Text := IntToStr(Sess.SSHPort);
|
|
editSSHUser.Text := Sess.SSHUser;
|
|
editSSHPassword.Text := Sess.SSHPassword;
|
|
updownSSHTimeout.Position := Sess.SSHTimeout;
|
|
editSSHPrivateKey.Text := Sess.SSHPrivateKey;
|
|
editSSHlocalport.Text := IntToStr(Sess.SSHLocalPort);
|
|
chkWantSSL.Checked := Sess.WantSSL;
|
|
editSSLPrivateKey.Text := Sess.SSLPrivateKey;
|
|
editSSLCertificate.Text := Sess.SSLCertificate;
|
|
editSSLCACertificate.Text := Sess.SSLCACertificate;
|
|
FServerVersion := Sess.ServerVersion;
|
|
FSessionColor := Sess.SessionColor;
|
|
end;
|
|
|
|
FLoaded := True;
|
|
FSessionModified := False;
|
|
FSessionAdded := False;
|
|
ListSessions.Repaint;
|
|
ValidateControls;
|
|
TimerStatistics.Enabled := True;
|
|
TimerStatistics.OnTimer(Sender);
|
|
|
|
Screen.Cursor := crDefault;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.TimerStatisticsTimer(Sender: TObject);
|
|
var
|
|
LastConnect, Created, DummyDate: TDateTime;
|
|
Connects, Refused: Integer;
|
|
begin
|
|
// Continuously update statistics labels
|
|
lblLastConnectRight.Caption := 'unknown or never';
|
|
lblLastConnectRight.Hint := '';
|
|
lblLastConnectRight.Enabled := False;
|
|
lblCreatedRight.Caption := 'unknown';
|
|
lblCreatedRight.Hint := '';
|
|
lblCreatedRight.Enabled := False;
|
|
lblCounterRight.Caption := 'not available';
|
|
lblCounterRight.Enabled := False;
|
|
|
|
if (not Assigned(ListSessions.FocusedNode))
|
|
or (not MainReg.KeyExists(RegPath + REGKEY_SESSIONS + SelectedSession)) then
|
|
Exit;
|
|
|
|
DummyDate := StrToDateTime('2000-01-01');
|
|
LastConnect := StrToDateTimeDef(GetRegValue(REGNAME_LASTCONNECT, '', SelectedSession), DummyDate);
|
|
if LastConnect <> DummyDate then begin
|
|
lblLastConnectRight.Hint := DateTimeToStr(LastConnect);
|
|
lblLastConnectRight.Caption := DateBackFriendlyCaption(LastConnect);
|
|
lblLastConnectRight.Enabled := True;
|
|
end;
|
|
Created := StrToDateTimeDef(GetRegValue(REGNAME_SESSIONCREATED, '', SelectedSession), DummyDate);
|
|
if Created <> DummyDate then begin
|
|
lblCreatedRight.Hint := DateTimeToStr(Created);
|
|
lblCreatedRight.Caption := DateBackFriendlyCaption(Created);
|
|
lblCreatedRight.Enabled := True;
|
|
end;
|
|
Connects := GetRegValue(REGNAME_CONNECTCOUNT, 0, SelectedSession);
|
|
Refused := GetRegValue(REGNAME_REFUSEDCOUNT, 0, SelectedSession);
|
|
lblCounterRight.Enabled := Connects + Refused > 0;
|
|
if Connects > 0 then begin
|
|
lblCounterRight.Caption := 'Successful connects: '+IntToStr(Connects);
|
|
if Refused > 0 then
|
|
lblCounterRight.Caption := lblCounterRight.Caption + ', unsuccessful: '+IntToStr(Refused);
|
|
end else if Refused > 0 then
|
|
lblCounterRight.Caption := 'Unsuccessful connects: '+IntToStr(Refused);
|
|
Invalidate;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ListSessionsFocusChanging(Sender: TBaseVirtualTree; OldNode,
|
|
NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
|
|
var Allowed: Boolean);
|
|
begin
|
|
if NewNode <> OldNode then
|
|
FinalizeModifications(Allowed)
|
|
else
|
|
Allowed := False;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ListSessionsNewText(Sender: TBaseVirtualTree;
|
|
Node: PVirtualNode; Column: TColumnIndex; NewText: String);
|
|
var
|
|
SessionKey: String;
|
|
Connection: TDBConnection;
|
|
Sess: PConnectionParameters;
|
|
Names: TStringList;
|
|
idx: Integer;
|
|
begin
|
|
// Rename session
|
|
Sess := Sender.GetNodeData(Node);
|
|
OpenRegistry;
|
|
Names := TStringList.Create;
|
|
MainReg.OpenKey(REGPATH + REGKEY_SESSIONS, true);
|
|
MainReg.GetKeyNames(Names);
|
|
idx := Names.IndexOf(Sess.SessionName);
|
|
if idx > -1 then
|
|
Names.Delete(idx);
|
|
if Names.IndexOf(NewText) > -1 then begin
|
|
ErrorDialog('Session "'+NewText+'" already exists!');
|
|
NewText := Sess.SessionName;
|
|
end else begin
|
|
SessionKey := RegPath + REGKEY_SESSIONS + Sess.SessionName;
|
|
if MainReg.KeyExists(SessionKey) then
|
|
MainReg.MoveKey(SessionKey, RegPath + REGKEY_SESSIONS + NewText, true);
|
|
// Also fix internal session names in main form, which gets used to store e.g. "lastuseddb" later
|
|
for Connection in MainForm.Connections do begin
|
|
if Connection.Parameters.SessionName = Sess.SessionName then
|
|
Connection.Parameters.SessionName := NewText;
|
|
end;
|
|
MainForm.SetWindowCaption;
|
|
Sess.SessionName := NewText;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.editHostChange(Sender: TObject);
|
|
begin
|
|
editSSHhost.TextHint := TEdit(Sender).Text;
|
|
Modification(Sender);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.chkLoginPromptClick(Sender: TObject);
|
|
var
|
|
Checked: Boolean;
|
|
begin
|
|
// Login prompt and SQL Server integrated Windows Auth are mutually exclusive
|
|
Checked := TCheckBox(Sender).Checked;
|
|
if Checked and (Sender = chkWindowsAuth) then
|
|
chkLoginPrompt.Checked := False;
|
|
if Checked and (Sender = chkLoginPrompt) then
|
|
chkWindowsAuth.Checked := False;
|
|
Modification(Sender);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.comboDatabasesDropDown(Sender: TObject);
|
|
var
|
|
Connection: TDBConnection;
|
|
Params: TConnectionParameters;
|
|
begin
|
|
// Try to connect and lookup database names
|
|
Params := CurrentParams;
|
|
Connection := Params.CreateConnection(Self);
|
|
Connection.Parameters.AllDatabasesStr := '';
|
|
Connection.LogPrefix := SelectedSession;
|
|
Connection.OnLog := Mainform.LogSQL;
|
|
comboDatabases.Items.Clear;
|
|
Screen.Cursor := crHourglass;
|
|
try
|
|
Connection.Active := True;
|
|
comboDatabases.Items := Connection.AllDatabases;
|
|
except
|
|
// Silence connection errors here - should be sufficient to log them
|
|
end;
|
|
FreeAndNil(Connection);
|
|
Screen.Cursor := crDefault;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.comboNetTypeChange(Sender: TObject);
|
|
var
|
|
Params: TConnectionParameters;
|
|
begin
|
|
// Autoset default port number as long as that was not modified by user
|
|
if (not editPort.Modified) and (FLoaded) then begin
|
|
Params := CurrentParams;
|
|
case Params.NetTypeGroup of
|
|
ngMySQL:
|
|
updownPort.Position := DEFAULT_PORT;
|
|
ngMSSQL:
|
|
updownPort.Position := 1433;
|
|
end;
|
|
FreeAndNil(Params);
|
|
end;
|
|
Modification(Sender);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.Modification(Sender: TObject);
|
|
var
|
|
PasswordModified: Boolean;
|
|
Sess: PConnectionParameters;
|
|
begin
|
|
// Some modification -
|
|
if FLoaded then begin
|
|
Sess := ListSessions.GetNodeData(ListSessions.FocusedNode);
|
|
FSessionModified := (Sess.Hostname <> editHost.Text)
|
|
or (Sess.Username <> editUsername.Text)
|
|
or (Sess.LoginPrompt <> chkLoginPrompt.Checked)
|
|
or (Sess.WindowsAuth <> chkWindowsAuth.Checked)
|
|
or (Sess.Port <> updownPort.Position)
|
|
or (Sess.Compressed <> chkCompressed.Checked)
|
|
or (Sess.NetType <> TNetType(comboNetType.ItemIndex))
|
|
or (Sess.StartupScriptFilename <> editStartupScript.Text)
|
|
or (Sess.AllDatabasesStr <> comboDatabases.Text)
|
|
or (Sess.SSHHost <> editSSHHost.Text)
|
|
or (IntToStr(Sess.SSHPort) <> editSSHPort.Text)
|
|
or (Sess.SSHPlinkExe <> editSSHPlinkExe.Text)
|
|
or (IntToStr(Sess.SSHLocalPort) <> editSSHlocalport.Text)
|
|
or (Sess.SSHUser <> editSSHUser.Text)
|
|
or (Sess.SSHPassword <> editSSHPassword.Text)
|
|
or (Sess.SSHTimeout <> updownSSHTimeout.Position)
|
|
or (Sess.SSHPrivateKey <> editSSHPrivateKey.Text)
|
|
or (Sess.WantSSL <> chkWantSSL.Checked)
|
|
or (Sess.SSLPrivateKey <> editSSLPrivateKey.Text)
|
|
or (Sess.SSLCertificate <> editSSLCertificate.Text)
|
|
or (Sess.SSLCACertificate <> editSSLCACertificate.Text);
|
|
PasswordModified := Sess.Password <> editPassword.Text;
|
|
FOnlyPasswordModified := PasswordModified and (not FSessionModified);
|
|
FSessionModified := FSessionModified or PasswordModified;
|
|
|
|
ListSessions.Repaint;
|
|
ValidateControls;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.FinalizeModifications(var CanProceed: Boolean);
|
|
begin
|
|
if (FSessionModified and (not FOnlyPasswordModified)) or FSessionAdded then begin
|
|
case MessageDialog('Save modifications?', 'Settings for "'+SelectedSession+'" were changed.', mtConfirmation, [mbYes, mbNo, mbCancel]) of
|
|
mrYes: begin
|
|
btnSave.OnClick(Self);
|
|
CanProceed := True;
|
|
end;
|
|
mrNo: begin
|
|
CanProceed := True;
|
|
end;
|
|
mrCancel: CanProceed := False;
|
|
end;
|
|
end else
|
|
CanProceed := True;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.ValidateControls;
|
|
var
|
|
SessionFocused: Boolean;
|
|
Params: TConnectionParameters;
|
|
begin
|
|
SessionFocused := Assigned(ListSessions.FocusedNode);
|
|
|
|
btnOpen.Enabled := SessionFocused;
|
|
btnNew.Enabled := not FSessionAdded;
|
|
btnSave.Enabled := FSessionModified or FSessionAdded;
|
|
btnDelete.Enabled := SessionFocused;
|
|
btnOpen.Enabled := SessionFocused;
|
|
|
|
if SessionFocused then begin
|
|
// Validate session GUI stuff
|
|
Params := CurrentParams;
|
|
if Params.NetType = ntMySQL_NamedPipe then
|
|
lblHost.Caption := 'Socket name:'
|
|
else
|
|
lblHost.Caption := 'Hostname / IP:';
|
|
chkWindowsAuth.Enabled := Params.NetTypeGroup = ngMSSQL;
|
|
lblUsername.Enabled := ((not chkLoginPrompt.Checked) or (not chkLoginPrompt.Enabled))
|
|
and ((not chkWindowsAuth.Checked) or (not chkWindowsAuth.Enabled));
|
|
editUsername.Enabled := lblUsername.Enabled;
|
|
lblPassword.Enabled := lblUsername.Enabled;
|
|
editPassword.Enabled := lblUsername.Enabled;
|
|
lblPort.Enabled := Params.NetType in [ntMySQL_TCPIP, ntMySQL_SSHtunnel, ntMSSQL_TCPIP];
|
|
if (Params.NetType = ntMSSQL_TCPIP) and (Pos('\', editHost.Text) > 0) then
|
|
lblPort.Enabled := False; // Named instance without port
|
|
editPort.Enabled := lblPort.Enabled;
|
|
updownPort.Enabled := lblPort.Enabled;
|
|
tabSSLoptions.TabVisible := Params.NetType = ntMySQL_TCPIP;
|
|
lblSSLPrivateKey.Enabled := Params.WantSSL;
|
|
editSSLPrivateKey.Enabled := Params.WantSSL;
|
|
lblSSLCACertificate.Enabled := Params.WantSSL;
|
|
editSSLCACertificate.Enabled := Params.WantSSL;
|
|
lblSSLCertificate.Enabled := Params.WantSSL;
|
|
editSSLCertificate.Enabled := Params.WantSSL;
|
|
tabSSHtunnel.TabVisible := Params.NetType = ntMySQL_SSHtunnel;
|
|
FreeAndNil(Params);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.splitterMainMoved(Sender: TObject);
|
|
var
|
|
ButtonWidth: Integer;
|
|
begin
|
|
// Splitter resized - adjust width of buttons
|
|
ButtonWidth := Round((ListSessions.Width - 2 * ListSessions.Margins.Left) / 3);
|
|
btnNew.Width := ButtonWidth;
|
|
btnSave.Width := ButtonWidth;
|
|
btnDelete.Width := ButtonWidth;
|
|
btnNew.Left := ListSessions.Left;
|
|
btnSave.Left := btnNew.Left + btnNew.Width + ListSessions.Margins.Left;
|
|
btnDelete.Left := btnSave.Left + btnSave.Width + ListSessions.Margins.Left;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.PickFile(Sender: TObject);
|
|
var
|
|
Selector: TOpenDialog;
|
|
Edit: TButtonedEdit;
|
|
i: Integer;
|
|
Control: TControl;
|
|
begin
|
|
// Select startup SQL file, SSL file or whatever button clicked
|
|
Edit := Sender as TButtonedEdit;
|
|
Selector := TOpenDialog.Create(Self);
|
|
Selector.FileName := editStartupScript.Text;
|
|
if Edit = editStartupScript then
|
|
Selector.Filter := 'SQL-files (*.sql)|*.sql|All files (*.*)|*.*'
|
|
else if Edit = editSSHPlinkExe then
|
|
Selector.Filter := 'Executables (*.exe)|*.exe|All files (*.*)|*.*'
|
|
else if Edit = editSSHPrivateKey then
|
|
Selector.Filter := 'PuTTY private key (*.ppk)|*.ppk|All files (*.*)|*.*'
|
|
else
|
|
Selector.Filter := 'Privacy Enhanced Mail certificates (*.pem)|*.pem|Certificates (*.crt)|*.crt|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];
|
|
if (Control is TLabel) and ((Control as TLabel).FocusControl = Edit) then begin
|
|
Selector.Title := 'Select ' + (Control as TLabel).Caption;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
if Selector.Execute then begin
|
|
Edit.Text := Selector.FileName;
|
|
Modification(Selector);
|
|
end;
|
|
Selector.Free;
|
|
end;
|
|
|
|
|
|
procedure Tconnform.editSSHPlinkExeChange(Sender: TObject);
|
|
begin
|
|
if not FileExists(editSSHPlinkExe.Text) then
|
|
editSSHPlinkExe.Font.Color := clRed
|
|
else
|
|
editSSHPlinkExe.Font.Color := clWindowText;
|
|
Modification(Sender);
|
|
end;
|
|
|
|
|
|
procedure Tconnform.lblDownloadPlinkClick(Sender: TObject);
|
|
begin
|
|
ShellExec(TLabel(Sender).Hint);
|
|
end;
|
|
|
|
|
|
end.
|