restemplate/indy/Core/IdDsnPropEdBindingVCL.pas

820 lines
23 KiB
Plaintext

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.9 10/26/2004 8:45:26 PM JPMugaas
Should compile.
Rev 1.8 10/26/2004 8:42:58 PM JPMugaas
Should be more portable with new references to TIdStrings and TIdStringList.
Rev 1.7 5/19/2004 10:44:28 PM DSiders
Corrected spelling for TIdIPAddress.MakeAddressObject method.
Rev 1.6 2/3/2004 11:34:26 AM JPMugaas
Should compile.
Rev 1.5.1.0 2/3/2004 11:32:26 AM JPMugaas
Should compile.
Rev 1.5 2/1/2004 2:44:20 AM JPMugaas
Bindings editor should be fully functional including IPv6 support.
Rev 1.4 2/1/2004 1:03:34 AM JPMugaas
This now work properly in both Win32 and DotNET. The behavior had to change
in DotNET because of some missing functionality and because implementing that
functionality creates more problems than it would solve.
Rev 1.3 2003.12.31 10:42:22 PM czhower
Warning removed
Rev 1.2 10/15/2003 10:12:32 PM DSiders
Added localization comments.
Rev 1.1 2003.10.11 5:47:46 PM czhower
-VCL fixes for servers
-Chain suport for servers (Super core)
-Scheduler upgrades
-Full yarn support
Rev 1.0 11/13/2002 08:43:58 AM JPMugaas
}
unit IdDsnPropEdBindingVCL;
interface
{$I IdCompilerDefines.inc}
uses
Classes,
{$IFDEF WIDGET_KYLIX}
QActnList, QStdCtrls, QForms, QExtCtrls, QControls, QComCtrls, QGraphics, Qt,
{$ENDIF}
{$IFDEF WIDGET_VCL_LIKE}
ActnList, StdCtrls, Buttons, ExtCtrls, Graphics, Controls, ComCtrls, Forms, Dialogs,
{$ENDIF}
{$IFDEF HAS_UNIT_Types}
Types,
{$ENDIF}
{$IFDEF WINDOWS}
Windows,
{$ENDIF}
{$IFDEF LCL}
LResources,
{$ENDIF}
IdSocketHandle;
{
Design Note: It turns out that in DotNET, there are no services file functions and
IdPorts does not work as expected in DotNET. It is probably possible to read the
services file ourselves but that creates some portability problems as the placement
is different in every operating system.
e.g.
Linux and Unix-like systems - /etc
Windows 95, 98, and ME - c:\windows
Windows NT systems - c:\winnt\system32\drivers\etc
Thus, it will undercut whatever benefit we could get with DotNET.
About the best I could think of is to use an edit control because
we can't offer anything from the services file in DotNET.
TODO: Maybe there might be a way to find the location in a more elegant
manner than what I described.
}
type
TIdDsnPropEdBindingVCL = class(TForm)
{$IFDEF USE_TBitBtn}
btnOk: TBitBtn;
btnCancel: TBitBtn;
{$ELSE}
btnOk: TButton;
btnCancel: TButton;
{$ENDIF}
lblBindings: TLabel;
edtPort: TComboBox;
rdoBindingType: TRadioGroup;
lblIPAddress: TLabel;
lblPort: TLabel;
btnNew: TButton;
btnDelete: TButton;
ActionList1: TActionList;
btnBindingsNew: TAction;
btnBindingsDelete: TAction;
edtIPAddress: TComboBox;
lbBindings: TListBox;
procedure btnBindingsNewExecute(Sender: TObject);
procedure btnBindingsDeleteExecute(Sender: TObject);
procedure btnBindingsDeleteUpdate(Sender: TObject);
procedure edtPortKeyPress(Sender: TObject; var Key: Char);
procedure edtIPAddressChange(Sender: TObject);
procedure edtPortChange(Sender: TObject);
procedure rdoBindingTypeClick(Sender: TObject);
procedure lbBindingsClick(Sender: TObject);
private
procedure SetHandles(const Value: TIdSocketHandles);
procedure SetIPv4Addresses(const Value: TStrings);
procedure SetIPv6Addresses(const Value: TStrings);
procedure UpdateBindingList;
protected
FInUpdateRoutine : Boolean;
FHandles : TIdSocketHandles;
FDefaultPort : Integer;
FIPv4Addresses : TStrings;
FIPv6Addresses : TStrings;
fCreatedStack : Boolean;
FCurrentHandle : TIdSocketHandle;
procedure UpdateEditControls;
function PortDescription(const PortNumber: integer): string;
public
Constructor Create(AOwner : TComponent); overload; override;
constructor Create; reintroduce; overload;
Destructor Destroy; override;
function Execute : Boolean;
function GetList: string;
procedure SetList(const AList: string);
property Handles : TIdSocketHandles read FHandles write SetHandles;
property DefaultPort : Integer read FDefaultPort write FDefaultPort;
property IPv4Addresses : TStrings read FIPv4Addresses write SetIPv4Addresses;
property IPv6Addresses : TStrings read FIPv6Addresses write SetIPv6Addresses;
end;
var
IdPropEdBindingEntry: TIdDsnPropEdBindingVCL;
procedure FillHandleList(const AList: string; ADest: TIdSocketHandles);
function GetListValues(const ASocketHandles : TIdSocketHandles) : String;
implementation
uses
IdGlobal,
IdIPAddress,
IdDsnCoreResourceStrings,
IdStack,
IdStackBSDBase,
SysUtils;
const
IPv6Wildcard1 = '::'; {do not localize}
{CH IPv6Wildcard2 = '0:0:0:0:0:0:0:0'; } {do not localize}
IPv6Loopback = '::1'; {do not localize}
IPv4Wildcard = '0.0.0.0'; {do not localize}
IPv4Loopback = '127.0.0.1'; {do not localize}
function IsValidIP(const AAddr : String): Boolean;
var
LIP : TIdIPAddress;
begin
LIP := TIdIPAddress.MakeAddressObject(AAddr);
Result := Assigned(LIP);
if Result then begin
FreeAndNil(LIP);
end;
end;
procedure FillHandleList(const AList: string; ADest: TIdSocketHandles);
var
LItems: TStringList;
i: integer;
LIPVersion: TIdIPVersion;
LAddr, LText: string;
LPort: integer;
LSocket: TIdSocketHandle;
begin
ADest.Clear;
LItems := TStringList.Create;
try
LItems.CommaText := AList;
for i := 0 to LItems.Count-1 do begin
if Length(LItems[i]) > 0 then begin
if TextStartsWith(LItems[i], '[') then begin
// ipv6
LIPVersion := Id_IPv6;
LText := Copy(LItems[i], 2, MaxInt);
LAddr := Fetch(LText, ']:');
LPort := StrToIntDef(LText, -1);
end else begin
// ipv4
LIPVersion := Id_IPv4;
LText := LItems[i];
LAddr := Fetch(LText, ':');
LPort := StrToIntDef(LText, -1);
//Note that 0 is legal and indicates the server binds to a random port
end;
if IsValidIP(LAddr) and (LPort > -1) and (LPort < 65536) then begin
LSocket := ADest.Add;
LSocket.IPVersion := LIPVersion;
LSocket.IP := LAddr;
LSocket.Port := LPort;
end;
end;
end;
finally
LItems.Free;
end;
end;
{ TIdDsnPropEdBindingVCL }
function NumericOnly(const AText : String) : String;
var
i : Integer;
begin
Result := '';
for i := 1 to Length(AText) do
begin
if IsNumeric(AText[i]) then begin
Result := Result + AText[i];
end else begin
Break;
end;
end;
if Length(Result) = 0 then begin
Result := '0';
end;
end;
function IndexOfNo(const ANo : Integer; AStrings : TStrings) : Integer;
begin
for Result := 0 to AStrings.Count-1 do
begin
if ANo = IndyStrToInt(NumericOnly(AStrings[Result])) then begin
Exit;
end;
end;
Result := -1;
end;
function GetDisplayString(ASocketHandle: TIdSocketHandle): string;
begin
Result := '';
case ASocketHandle.IPVersion of
Id_IPv4 : Result := Format('%s:%d',[ASocketHandle.IP, ASocketHandle.Port]);
Id_IPv6 : Result := Format('[%s]:%d',[ASocketHandle.IP, ASocketHandle.Port]);
end;
end;
function GetListValues(const ASocketHandles : TIdSocketHandles) : String;
var i : Integer;
begin
Result := '';
for i := 0 to ASocketHandles.Count -1 do begin
Result := Result + ',' + GetDisplayString(ASocketHandles[i]);
end;
Delete(Result,1,1);
end;
constructor TIdDsnPropEdBindingVCL.Create(AOwner: TComponent);
var
i : Integer;
LLocalAddresses: TIdStackLocalAddressList;
begin
inherited CreateNew(AOwner, 0);
{$IFNDEF WIDGET_KYLIX}
Borderstyle := bsDialog;
{$ENDIF}
BorderIcons := [biSystemMenu];
// Width := 480;
// Height := 252;
ClientWidth := 472;
{$IFDEF USE_TBitBtn}
ClientHeight := 230;
{$ELSE}
ClientHeight := 225;
{$ENDIF}
Constraints.MaxWidth := Width;
Constraints.MaxHeight := Height;
Constraints.MinWidth := Width;
Constraints.MinHeight := Height;
Position := poScreenCenter;
lblBindings := TLabel.Create(Self);
lbBindings := TListBox.Create(Self);
ActionList1 := TActionList.Create(Self);
btnBindingsNew := TAction.Create(Self);
btnBindingsDelete := TAction.Create(Self);
btnNew := TButton.Create(Self);
btnDelete := TButton.Create(Self);
lblIPAddress := TLabel.Create(Self);
edtIPAddress := TComboBox.Create(Self);
lblPort := TLabel.Create(Self);
edtPort := TComboBox.Create(Self);
rdoBindingType := TRadioGroup.Create(Self);
{$IFDEF USE_TBitBtn}
btnOk := TBitBtn.Create(Self);
btnCancel := TBitBtn.Create(Self);
{$ELSE}
btnOk := TButton.Create(Self);
btnCancel := TButton.Create(Self);
{$ENDIF}
lblBindings.Name := 'lblBindings'; {do not localize}
lblBindings.Parent := Self;
lblBindings.Left := 8;
lblBindings.Top := 8;
lblBindings.Width := 35;
lblBindings.Height := 13;
lblBindings.Caption := '&Binding'; {do not localize}
lbBindings.Name := 'lbBindings'; {do not localize}
lbBindings.Parent := Self;
lbBindings.Left := 8;
lbBindings.Top := 24;
lbBindings.Width := 137;
lbBindings.Height := 161;
lbBindings.ItemHeight := 13;
lbBindings.TabOrder := 8;
lbBindings.OnClick := lbBindingsClick;
ActionList1.Name := 'ActionList1'; {do not localize}
{
ActionList1.Left := 152;
ActionList1.Top := 32;
}
btnBindingsNew.Name := 'btnBindingsNew'; {do not localize}
btnBindingsNew.Caption := RSBindingNewCaption;
btnBindingsNew.OnExecute := btnBindingsNewExecute;
btnBindingsDelete.Name := 'btnBindingsDelete'; {do not localize}
btnBindingsDelete.Caption := RSBindingDeleteCaption;
btnBindingsDelete.OnExecute := btnBindingsDeleteExecute;
btnBindingsDelete.OnUpdate := btnBindingsDeleteUpdate;
btnNew.Name := 'btnNew'; {do not localize}
btnNew.Parent := Self;
btnNew.Left := 152;
btnNew.Top := 72;
btnNew.Width := 75;
btnNew.Height := 25;
btnNew.Action := btnBindingsNew;
btnNew.TabOrder := 6;
btnDelete.Name := 'btnDelete'; {do not localize}
btnDelete.Parent := Self;
btnDelete.Left := 152;
btnDelete.Top := 104;
btnDelete.Width := 75;
btnDelete.Height := 25;
btnDelete.Action := btnBindingsDelete;
btnDelete.TabOrder := 7;
lblIPAddress.Name := 'lblIPAddress'; {do not localize}
lblIPAddress.Parent := Self;
lblIPAddress.Left := 240;
lblIPAddress.Top := 8;
lblIPAddress.Width := 54;
lblIPAddress.Height := 13;
lblIPAddress.Caption := RSBindingHostnameLabel;
lblIPAddress.Enabled := False;
edtIPAddress.Name := 'edtIPAddress'; {do not localize}
edtIPAddress.Parent := Self;
edtIPAddress.Left := 240;
edtIPAddress.Top := 24;
edtIPAddress.Width := 221;
edtIPAddress.Height := 21;
edtIPAddress.Enabled := False;
edtIPAddress.ItemHeight := 13;
edtIPAddress.TabOrder := 3;
edtIPAddress.OnChange := edtIPAddressChange;
lblPort.Name := 'lblPort'; {do not localize}
lblPort.Parent := Self;
lblPort.Left := 240;
lblPort.Top := 56;
lblPort.Width := 22;
lblPort.Height := 13;
lblPort.Caption := RSBindingPortLabel;
lblPort.Enabled := False;
lblPort.FocusControl := edtPort;
edtPort.Name := 'edtPort'; {do not localize}
edtPort.Parent := Self;
edtPort.Left := 240;
edtPort.Top := 72;
edtPort.Width := 221;
edtPort.Height := 21;
edtPort.Enabled := False;
edtPort.ItemHeight := 13;
edtPort.TabOrder := 4;
edtPort.OnChange := edtPortChange;
edtPort.OnKeyPress := edtPortKeyPress;
rdoBindingType.Name := 'rdoBindingType'; {do not localize}
rdoBindingType.Parent := Self;
rdoBindingType.Left := 240;
rdoBindingType.Top := 120;
rdoBindingType.Width := 221;
rdoBindingType.Height := 65;
rdoBindingType.Caption := RSBindingIPVerLabel;
rdoBindingType.Enabled := False;
rdoBindingType.Items.Add(RSBindingIPV4Item);
rdoBindingType.Items.Add(RSBindingIPV6Item);
rdoBindingType.TabOrder := 5;
rdoBindingType.OnClick := rdoBindingTypeClick;
btnOk.Name := 'btnOk'; {do not localize}
btnOk.Parent := Self;
btnOk.Anchors := [akRight, akBottom];
btnOk.Left := 306;
btnOk.Top := 193;
btnOk.Width := 75;
{$IFDEF USE_TBitBtn}
btnOk.Height := 30;
btnOk.Kind := bkOk;
{$ELSE}
btnOk.Height := 25;
btnOk.Caption := RSOk;
btnOk.Default := True;
btnOk.ModalResult := 1;
{$ENDIF}
btnOk.TabOrder := 0;
btnCancel.Name := 'btnCancel'; {do not localize}
btnCancel.Parent := Self;
btnCancel.Anchors := [akRight, akBottom];
btnCancel.Left := 386;
btnCancel.Top := 193;
btnCancel.Width := 75;
{$IFDEF USE_TBitBtn}
btnCancel.Height := 30;
btnCancel.Kind := bkCancel;
{$ELSE}
btnCancel.Height := 25;
btnCancel.Cancel := True;
btnCancel.Caption := RSCancel;
btnCancel.ModalResult := 2;
{$ENDIF}
btnCancel.Anchors := [akRight, akBottom];
btnCancel.TabOrder := 1;
FHandles := TIdSocketHandles.Create(nil);
FIPv4Addresses := TStringList.Create;
FIPv6Addresses := TStringList.Create;
SetIPv4Addresses(nil);
SetIPv6Addresses(nil);
TIdStack.IncUsage;
try
LLocalAddresses := TIdStackLocalAddressList.Create;
try
GStack.GetLocalAddressList(LLocalAddresses);
for i := 0 to LLocalAddresses.Count-1 do
begin
case LLocalAddresses[i].IPVersion of
Id_IPv4: FIPv4Addresses.Add(LLocalAddresses[i].IPAddress);
Id_IPv6: FIPv6Addresses.Add(LLocalAddresses[i].IPAddress);
end;
end;
finally
LLocalAddresses.Free;
end;
finally
TIdStack.DecUsage;
end;
edtPort.Items.BeginUpdate;
try
edtPort.Items.Add(PortDescription(0));
for i := 0 to IdPorts.Count - 1 do begin
edtPort.Items.Add(
PortDescription(
{$IFDEF HAS_GENERICS_TList}
IdPorts[i]
{$ELSE}
PtrInt(IdPorts[i])
{$ENDIF}
)
);
end;
finally
edtPort.Items.EndUpdate;
end;
AutoScroll := False;
Caption := RSBindingFormCaption;
{$IFDEF WIDGET_VCL}
Scaled := False;
{$ENDIF}
Font.Color := clBtnText;
Font.Height := -11;
Font.Name := 'MS Sans Serif'; {Do not Localize}
Font.Style := [];
Position := poScreenCenter;
PixelsPerInch := 96;
FInUpdateRoutine := False;
UpdateEditControls;
end;
destructor TIdDsnPropEdBindingVCL.Destroy;
begin
FreeAndNil(FIPv4Addresses);
FreeAndNil(FIPv6Addresses);
FreeAndNil(FHandles);
inherited Destroy;
end;
function TIdDsnPropEdBindingVCL.PortDescription(const PortNumber: integer): string;
var
LList: TStringList;
begin
if PortNumber = 0 then begin
Result := IndyFormat('%d: %s', [PortNumber, RSBindingAny]);
end else begin
Result := ''; {Do not Localize}
LList := TStringList.Create;
try
GBSDStack.AddServByPortToList(PortNumber, LList);
if LList.Count > 0 then begin
Result := Format('%d: %s', [PortNumber, LList.CommaText]); {Do not Localize}
end;
finally
LList.Free;
end;
end;
end;
procedure TIdDsnPropEdBindingVCL.SetHandles(const Value: TIdSocketHandles);
begin
FHandles.Assign(Value);
UpdateBindingList;
end;
procedure TIdDsnPropEdBindingVCL.btnBindingsNewExecute(Sender: TObject);
begin
FCurrentHandle := FHandles.Add;
FCurrentHandle.IP := IPv4Wildcard;
FCurrentHandle.Port := FDefaultPort;
UpdateBindingList;
edtIPAddress.Items.Assign(FIPv4Addresses);
UpdateEditControls;
end;
procedure TIdDsnPropEdBindingVCL.UpdateEditControls;
var
i : Integer;
begin
if Assigned(FCurrentHandle) then
begin
i := IndexOfNo(FCurrentHandle.Port,edtPort.Items);
if i = -1 then begin
edtPort.Text := IntToStr(FCurrentHandle.Port);
end else begin
edtPort.ItemIndex := i;
end;
case FCurrentHandle.IPVersion of
Id_IPv4 :
begin
rdoBindingType.ItemIndex := 0;
edtIPAddress.Items.Assign(FIPv4Addresses);
end;
Id_IPv6 :
begin
rdoBindingType.ItemIndex := 1;
edtIPAddress.Items.Assign(FIPv6Addresses);
end;
end;
if edtIPAddress.Style = csDropDown then begin
edtIPAddress.Text := FCurrentHandle.IP;
end else begin
edtIPAddress.ItemIndex := edtIPAddress.Items.IndexOf(FCurrentHandle.IP);
end;
end
else
begin
edtIPAddress.Text := '';
//in LCL, the line below caused an index out of range error.
{$IFDEF WIDGET_VCL}
edtPort.ItemIndex := -1; //-2;
{$ENDIF}
edtPort.Text := '';
end;
lblIPAddress.Enabled := Assigned(FCurrentHandle);
edtIPAddress.Enabled := Assigned(FCurrentHandle);
lblPort.Enabled := Assigned(FCurrentHandle);
edtPort.Enabled := Assigned(FCurrentHandle);
rdoBindingType.Enabled := Assigned(FCurrentHandle);
{$IFDEF WIDGET_KYLIX}
//WOrkaround for CLX quirk that might be Kylix 1
for i := 0 to rdoBindingType.ControlCount -1 do begin
rdoBindingType.Controls[i].Enabled := Assigned(FCurrentHandle);
end;
{$ENDIF}
{$IFDEF WIDGET_VCL_LIKE}
//The Win32 VCL does not change the control background to a greyed look
//when controls are disabled. This quirk is not present in CLX.
if Assigned(FCurrentHandle) then
begin
edtIPAddress.Color := clWindow;
edtPort.Color := clWindow;
end else
begin
edtIPAddress.Color := clBtnFace;
edtPort.Color := clBtnFace;
end;
{$ENDIF}
end;
procedure TIdDsnPropEdBindingVCL.btnBindingsDeleteExecute(Sender: TObject);
var
LSH : TIdSocketHandle;
begin
if lbBindings.ItemIndex >= 0 then
begin
// Delete is not available in D4's collection classes
// This should work just as well.
LSH := Handles[lbBindings.ItemIndex];
FreeAndNil(LSH);
FCurrentHandle := nil;
UpdateBindingList;
end;
lbBindingsClick(nil);
UpdateEditControls;
end;
procedure TIdDsnPropEdBindingVCL.btnBindingsDeleteUpdate(Sender: TObject);
begin
btnBindingsDelete.Enabled := lbBindings.ItemIndex >= 0;
end;
procedure TIdDsnPropEdBindingVCL.SetIPv4Addresses(const Value: TStrings);
begin
if Assigned(Value) then begin
FIPv4Addresses.Assign(Value);
end;
// Ensure that these two are always present
if FIPv4Addresses.IndexOf(IPv6Loopback) = -1 then begin
FIPv4Addresses.Insert(0, IPv4Loopback);
end;
if FIPv4Addresses.IndexOf(IPv4Wildcard) = -1 then begin
FIPv4Addresses.Insert(0, IPv4Wildcard);
end;
end;
procedure TIdDsnPropEdBindingVCL.SetIPv6Addresses(const Value: TStrings);
begin
if Assigned(Value) then begin
FIPv6Addresses.Assign(Value);
end;
// Ensure that these two are always present
if FIPv6Addresses.IndexOf(IPv6Loopback) = -1 then begin
FIPv6Addresses.Insert(0, IPv6Loopback);
end;
if FIPv6Addresses.IndexOf(IPv6Wildcard1) = -1 then begin
FIPv6Addresses.Insert(0, IPv6Wildcard1);
end;
end;
procedure TIdDsnPropEdBindingVCL.edtPortKeyPress(Sender: TObject; var Key: Char);
begin
// RLebeau 1/7/09: using Char() for #128-#255 because in D2009, the compiler
// may change characters >= #128 from their Ansi codepage value to their true
// Unicode codepoint value, depending on the codepage used for the source code.
// For instance, #128 may become #$20AC...
if (Key > Chr(31)) and (Key < Chr(128)) then begin
if not IsNumeric(Key) then begin
Key := #0;
end;
end;
end;
procedure TIdDsnPropEdBindingVCL.edtIPAddressChange(Sender: TObject);
begin
FCurrentHandle.IP := edtIPAddress.Text;
UpdateBindingList;
end;
procedure TIdDsnPropEdBindingVCL.edtPortChange(Sender: TObject);
begin
if Assigned(FCurrentHandle) then begin
FCurrentHandle.Port := IndyStrToInt(NumericOnly(edtPort.Text), 0);
end;
UpdateBindingList;
end;
procedure TIdDsnPropEdBindingVCL.rdoBindingTypeClick(Sender: TObject);
begin
case rdoBindingType.ItemIndex of
0 :
begin
if FCurrentHandle.IPVersion <> Id_IPv4 then
begin
FCurrentHandle.IPVersion := Id_IPv4;
edtIPAddress.Items.Assign(FIPv4Addresses);
FCurrentHandle.IP := IPv4Wildcard;
end;
end;
1 :
begin
if FCurrentHandle.IPVersion <> Id_IPv6 then
begin
FCurrentHandle.IPVersion := Id_IPv6;
edtIPAddress.Items.Assign(FIPv6Addresses);
FCurrentHandle.IP := IPv6Wildcard1;
end;
end;
end;
UpdateEditControls;
UpdateBindingList;
end;
function TIdDsnPropEdBindingVCL.GetList: string;
begin
Result := GetListValues(Handles);
end;
procedure TIdDsnPropEdBindingVCL.lbBindingsClick(Sender: TObject);
begin
if lbBindings.ItemIndex >= 0 then begin
FCurrentHandle := FHandles[lbBindings.ItemIndex];
end else begin
FCurrentHandle := nil;
end;
UpdateEditControls;
end;
procedure TIdDsnPropEdBindingVCL.SetList(const AList: string);
begin
FCurrentHandle := nil;
FillHandleList(AList, Handles);
UpdateBindingList;
UpdateEditControls;
end;
procedure TIdDsnPropEdBindingVCL.UpdateBindingList;
var
i: integer;
selected: integer;
s: string;
begin
//in Lazarus, for some odd reason, if you have more than one binding,
//the routine is called while the items are updated
if FInUpdateRoutine then begin
Exit;
end;
FInUpdateRoutine := True;
try
selected := lbBindings.ItemIndex;
lbBindings.Items.BeginUpdate;
try
if lbBindings.Items.Count = FHandles.Count then begin
for i := 0 to FHandles.Count - 1 do begin
s := GetDisplayString(FHandles[i]);
if s <> lbBindings.Items[i] then begin
lbBindings.Items[i] := s;
end;
end;
end else begin
lbBindings.Items.Clear;
for i := 0 to FHandles.Count-1 do begin
lbBindings.Items.Add(GetDisplayString(FHandles[i]));
end;
end;
finally
lbBindings.Items.EndUpdate;
if Assigned(FCurrentHandle) then begin
lbBindings.ItemIndex := FCurrentHandle.Index;
end else begin
lbBindings.ItemIndex := IndyMin(selected, lbBindings.Items.Count-1);
end;
end;
finally
FInUpdateRoutine := False;
end;
end;
function TIdDsnPropEdBindingVCL.Execute: Boolean;
begin
Result := ShowModal = mrOk;
end;
constructor TIdDsnPropEdBindingVCL.Create;
begin
Create(nil);
end;
end.