{ +-------------------------------------------------------------+ }
{ |                                                             | }
{ |   GM-Software                                               | }
{ |   ===========                                               | }
{ |                                                             | }
{ |   Project: DB Projects                                      | }
{ |                                                             | }
{ |   Description: ODBC User Interface Classes.                 | }
{ |                                                             | }
{ |                                                             | }
{ |   Copyright (C) - 2001 - Gerrit Moeller.                    | }
{ |                                                             | }
{ |   Source code dstributed under MIT license.                 | }
{ |                                                             | }
{ |   See: https://www.gm-software.de                           | }
{ |                                                             | }
{ +-------------------------------------------------------------+ }

{$INCLUDE GMCompilerSettings.inc}

unit GMOdbcUI;

{$R *.res}

interface

uses {$IFDEF JEDIAPI}JwaWinType,{$ELSE}Windows,{$ENDIF}
     GMStrDef, GMMessages, GMIntf, GMCommon, GMUICore, GMxCtrls, GMOsCtrls, GMOsExCtrls, GMSql, GMOdbcObj;

const

  UM_DSNDROPSELECT = UM_USER + 1;


type

  TOdbcDataChangeProc = procedure (const NewName: TGMString = '') of Object;


  TComboBoxOdbcDSN = class(TGMComboBox)
   protected
    procedure WMAppCommand(var Msg: TWMCommand); message WM_COMMAND + WM_APP;
    procedure UMDSNDropSelect(var Msg: TMessage); message UM_DSNDROPSELECT;
  end;


  TGMOdbcConnectionPropUIArea = class(TGMSurroundingUiArea)
   //
   // Need to use PostMessage for FComboBoxDSN so cannot be TGMUiArea
   //
   protected
    FConnectProperties: IGMOdbcConnectProperties;
    FOnDataChange: TOdbcDataChangeProc;

    FComboBoxDSN: TGMComboBox;
    FComboBoxAccessMode: TGMComboBox;
    FEditUsername: TGMEditBase;
    FEditPassword: TGMEditBase;
    FComboBoxCursorOrigin: TGMComboBox;
    FComboBoxTransIsolation: TGMComboBox;
    FComboBoxDriverDialogs: TGMComboBox;
    FIntEditLoginTimeout: TGMIntEdit;
    FIntEditStmtTimeout: TGMIntEdit;
    FBtnEditConnectionString: TGMxToolBtnArea;
    FAttrCheckBoxes: array [TOdbcConnectionAttribute] of TGMxCheckBoxArea;

    procedure SetConnectProperties(const AValue: IGMOdbcConnectProperties);
    //procedure AddDSNToComboBox(const DSN: TGMString; const Obj: TObject);
    procedure DataChanged(const ANewName: TGMString = '');

//  procedure OnComboBoxDSNDropSelect(const ASender: TObject);
    procedure OnComboBoxDSNTextChange(const ASender: TObject);
    procedure OnComboBoxAccessModeChange(const ASender: TObject);
    procedure OnComboBoxDriverDialogsChange(const ASender: TObject);
    procedure OnEditUserNameChange(const ASender: TObject);
    procedure OnEditPasswordChange(const ASender: TObject);
    procedure OnComboBoxCursorOriginChange(const ASender: TObject);
    procedure OnComboBoxTransIsolationChange(const ASender: TObject);
    procedure OnIntEditLoginTimeoutChange(const ASender: TObject);
    procedure OnIntEditOperationTimeoutChange(const ASender: TObject);
    procedure OnAttributesChange(const ASender: TObject);
    procedure OnBtnEditConnectionStringClick(const ASender: TObject);

   public
    OnAttributesChanged: TGMObjNotifyProc;

    constructor Create(const AParent: TObject;
                       const APosition: TRect;
                       const AAreaAlign: TGMAreaAlignRec;
                       const AOnDataChange: TOdbcDataChangeProc = nil;
                       const ABkgndColor: COLORREF = cDfltColor;
                       const AVisible: Boolean = True;
                       const ARefLifeTime: Boolean = False); reintroduce; overload;

    procedure CreateHandle; override;
    procedure FillupComboBoxDSN;

    property ConnectProperties: IGMOdbcConnectProperties read FConnectProperties write SetConnectProperties;
  end;


  TGMOdbcRecordsetPropUIArea = class(TGMSurroundingUiArea)
   protected
    FRecordsetProps: IGMOdbcRecordsetProperties;
    FOnDataChange: TOdbcDataChangeProc;

    FComboBoxCursorType: TGMComboBox;
    FComboBoxCursorSensitivity: TGMComboBox;
    FComboBoxUpdateStrategy: TGMComboBox;
    FComboBoxUpdateSimulation: TGMComboBox;
    //FComboBoxBlobCompression: TGMComboBox;
    FIntEditKeysetSize: TGMIntEdit;
    FIntEditReturnedRecords: TGMIntEdit;
    FIntEditMaxDataSize: TGMIntEdit;
    FIntEditReexecuteDelay: TGMIntEdit;
//  FComboBoxMaxStrLenOrigin: TGMComboBox;
//  FLabelCharSizeFactor: TGMxLabel;
//  FEditCharSizeFactor: TGMColorTextFramedEdit;
//  FSizeFactorConvertErrorHint: TGMHintWindow;

    FAttrCheckBoxes: array [TGMRecordsetAttribute] of TGMxCheckBoxArea;
    FCountStrgyCheckBoxes: array [TRecordCountStrategy] of TGMxCheckBoxArea;
    //FListViewAttributes: TOdbcCheckListView;
    //FListViewCountStrategies: TOdbcCheckListView;
//  FCheckBoxUseTimeoutFromCn: TGMCheckBox;
    FIntEditTimeout: TGMIntEdit;
    FCheckBoxDoEscapeScan: TGMcheckBox;

    FTimeoutLabel: TGMxLabel;

    //procedure UMAttributesChanged(var Msg: TMessage); message UM_ATTRIBUTESCHANGED;
    //procedure UMCountStrategyChanged(var Msg: TMessage); message UM_COUNTSTRATEGYCHANGED;

//  procedure ResetConvertErrorInfo;

    procedure SetRecordsetProps(const AValue: IGMOdbcRecordsetProperties);
//  procedure SetupTimeoutCtrls;
//  procedure SetupCharSizeFactor;
    procedure DataChanged(const ANewName: TGMString = '');

    procedure OnComboBoxCursorTypeChange(const ASender: TObject);
    procedure OnComboBoxCursorSensitivityChange(const ASender: TObject);
    procedure OnComboBoxUpdateStrategyChange(const ASender: TObject);
    procedure OnComboBoxUpdateSimulationChange(const ASender: TObject);
    procedure OnIntEditKeysetSizeChange(const ASender: TObject);
    procedure OnIntEditReturnedRecordsChange(const ASender: TObject);
    procedure OnIntEditMaxDataSizeChange(const ASender: TObject);
    procedure OnIntEditReexecuteDelayChange(const Sender: TObject);
    procedure OnAttributesChange(const ASender: TObject);
    procedure OnCountStrategiesChange(const ASender: TObject);
    procedure OnCheckBoxUseTimeoutFromCnChange(const ASender: TObject);
    procedure OnIntEditTimeoutChange(const ASender: TObject);
    procedure OnCheckBoxDoEscapeScanChange(const ASender: TObject);
//  procedure OnComboBoxMaxStrLenOriginChange(const Sender: TObject);
//  procedure OnEditCharSizeFactorChange(const Sender: TObject);

   public
    constructor Create(const AParent: TObject;
                       const APosition: TRect;
                       const AAreaAlign: TGMAreaAlignRec;
                       const AOnDataChange: TOdbcDataChangeProc = nil;
                       const ABkgndColor: COLORREF = cDfltColor;
                       const AVisible: Boolean = True;
                       const ARefLifeTime: Boolean = False); reintroduce; overload;

    procedure CreateHandle; override;

    property RecordsetProps: IGMOdbcRecordsetProperties read FRecordsetProps write SetRecordsetProps;
  end;


  TGMConnectionStrEditDlg = class(TGMDlgWindow)
   protected
    FConnectionString: TGMString;
    FEditor: TGMFramedEdit;
//  procedure OnBtnHelpClick(const ASender: TObject);

   public
    constructor Create(const AConnectionString, ATitle, ALargeText: TGMString;
                       const AParent: TGMWndObj = cDfltPrntWnd; const ABkgndColor: COLORREF = cDfltColor;
                       const ARefLifeTime: Boolean = True); reintroduce; overload;

    procedure DoneDialog(const ASetData: Boolean); override;
    function GetText: TGMString; override;
  end;


  TGMShowConnectionStrDlg = class(TGMDlgWindow)
   protected
    FConnectionString: TGMString;
    FEditor: TGMFramedEdit;
  //  procedure OnBtnHelpClick(const ASender: TObject);

   public
    constructor Create(const AConnectionString, ATitle, ALargeText: TGMString;
                       const AParent: TGMWndObj = cDfltPrntWnd; const ABkgndColor: COLORREF = cDfltColor;
                       const ARefLifeTime: Boolean = True); reintroduce; overload;

//  procedure DoneDialog(const ASetData: Boolean); override;
    function GetText: TGMString; override;
  end;


  TGMOdbcConnectDlg = class(TGMDlgWindow)
   protected
    FBtnODBCAdminDlg: TGMButton;
    FBottomArea: TGMDlgBottomArea;
    FCnPropsUIArea: TGMOdbcConnectionPropUIArea;

    procedure OnOdbcAdminDlgClick(const Sender: TObject);
    procedure OnDatachanged(const NewName: TGMString = '');

   public
    constructor Create(const APosition: TRect;
                       const AStyle: DWORD = cDfltWndStyle;
                       const AExStyle: DWORD = cPrntWndExStyle;
                       const AText: TGMString = cDfltWndText;
                       const AParent: TGMWndObj = cDfltPrntWnd;
                       const ADlgData: Pointer = cDfltDlgData;
                       const AMenu: HMENU = cDfltWndMenu;
                       const ABkgndColor: COLORREF = cDfltColor;
                       const ARefLifeTime: Boolean = False); override;

    procedure SetupControls; override;
    procedure GetDlgData; override;
    //function CanClose(const ASetData: Boolean): Boolean; override;
    procedure DoneDialog(const ASetData: Boolean); override;
  end;



function GMExecuteOdbcConnectDlg(const AOdbcCnProps: IUnknown; const AParent: TGMWndObj = cDfltPrntWnd): Integer;

function GMOdbcConnect(const AConnection: TGMOdbcConnection; const AParent: TGMWndObj = cDfltPrntWnd): Boolean;



implementation

uses GMGdi, GMDlgs, GMOdbcAPI, GMOdbcInstallAPI
     {$IFDEF JEDIAPI},jwaWinUser{$ENDIF};

const

  cMaxTimeout = 100000;
  cResOdbcDlgHeaderIcon = 'OdbcDlgHeaderIcon';
  cResOdbcDlgImageListBmp = 'OdbcDlgImageListBmp';
  cItemDataTxIsolationUseDflt = -1;


resourcestring

  RStrEditConnectionString = 'Edit connection string';
  RStrConnectionString = 'Connection string';

  RStrTryOtherParams = 'Try again with other parameters';
  RStrOdbcConnectDlgCaption = 'Select ODBC data source';

//RStrEditCnStrDlgHintTitle = 'Edit connection string';
  RStrEditCnStrDlgHintText = 'Edit the connection string in a separate dialog showing each entry on a separate line';
  srConnectionStrTextWhenEmpty = 'DRIVER=???;DATABASE=???;PWD=???;SERVER=???;UID=???';

  //RStrNoEmptyDSN = 'The data source name cannot be empty';

//RStrDataSource = 'Connection string';
  RStrAccessMode = 'Access Mode';
  RStrCursorOrigin = 'Cursor Origin';
  RStrIsolation = 'Isolation';
  RStrDriverDialogs = 'Driver Dialogs';
  RStrLoginTimeout = 'Login Timeout';
  RStrOperationTimeout = 'Operation Timeout';

  RStrOdbc = 'ODBC';
  RStrSelectDSN = 'Data source seletion';

  RStrUseDBDefaultTxIsolation = 'Use Database default';

  RStrCursorType = 'Cursor Type';
  RStrCursorSensitivity = 'Cursor Sensitivity';
  RStrUpdateStrategy = 'Update Strategy';
  RStrUpdateSimulation = 'Update Simulation';
//RStrBLOBCompression = 'BLOB Compression';
  RStrKeysetSize = 'Keyset Size';
  RStrReturnedRecords = 'Returned Records';
  RStrMaxDataSize = 'Max Data Size';
//RStrCharSizeFactor = 'String max-length factor';

  //RStrReexecuteDelay = 'Reexecute Delay';
  RStrAttributes = 'Attributes';
  RStrCountStrateies = 'Count Strategies';
  //RStrUseTimeoutFromCn = 'Use Timeout from Connection';
  //RStrTimeout = 'Timeout';
  //RStrDoEscScan = 'Scan SQL for escape sequences';
  RStrTimeDesc = '[s]  0 = infinite';

  RStrOdbcAdminDlg = 'ODBC Administration';
  RStrTemplate = 'Template';

  //RStrDataTypeConvertError = 'Datatype covert error';


var

  vOdbcDlgImages: IGMImageCollection = nil;


{ ------------------------- }
{ ---- Global Routines ---- }
{ ------------------------- }

function GMExecuteOdbcConnectDlg(const AOdbcCnProps: IUnknown; const AParent: TGMWndObj): Integer;
var PICnProps: IGMOdbcConnectProperties;
begin
  if not GMQueryInterface(AOdbcCnProps, IGMOdbcConnectProperties, PICnProps) then Result := IdCancel else
     Result := GMShowModalDlg(TGMOdbcConnectDlg, swShowNormal, Pointer(AOdbcCnProps), '', AParent);
end;

function GMOdbcConnect(const AConnection: TGMOdbcConnection; const AParent: TGMWndObj): Boolean;
var connectData: IGMOdbcConnectProperties; showConnectDlg: Boolean;
begin
  if AConnection = nil then begin Result := False; Exit; end;
  Result := AConnection.Active;
  if not Result then
   begin
    showConnectDlg := False;
    connectData := TGMOdbcConnectProperties.CreateFromObj(AConnection, True);
    repeat
     try
      if showConnectDlg or (Length(connectData.Obj.ConnectionString) <= 0) then
       begin
        case GMExecuteOdbcConnectDlg(connectData, AParent) of
         IdOk: connectData.Obj.AssignToObj(AConnection); // AConnection.AssignFromObj(connectData);
         IdCancel: raise EGMAbort.Create(RStrOperationCanceled);
        end;
       end;
      AConnection.Open;
      Result := True;
     except
      on ex: TObject do
        if GMIsFatalException(ex) then raise else
          if not GMAskExceptionContinue(ex, eaAskUser, RStrTryOtherParams) then raise else showConnectDlg := True;
//    on EAbort do raise;
//    on E: Exception do if not GMAskExceptionContinue(E, eaAskUser, RStrTryOtherParams) then raise else showConnectDlg := True; else raise;
     end;
    until AConnection.Active;
   end;
end;

function OdbcDlgImages: IGMImageCollection;
begin
  if vOdbcDlgImages = nil then vOdbcDlgImages := TGMImageCollection.Create(cResOdbcDlgImageListBmp, {$IFNDEF FPC}SysInit.{$ELSE}System.{$ENDIF}HInstance);
  Result := vOdbcDlgImages;
end;

//function ProfileCmdImages: IGMImageCollection;
//begin
//if vProfileCmdImages = nil then vProfileCmdImages := TGMImageCollection.Create(cResProfileCmdImages, {$IFNDEF FPC}SysInit.{$ELSE}System.{$ENDIF}HInstance);
//Result := vProfileCmdImages;
//end;



{ ------------------------- }
{ ---- Helper Routines ---- }
{ ------------------------- }

procedure AddDSNToComboBox(const ADSN: TGMString; const AObj: TObject);
begin
  GMSendObjMessage(AObj, CB_ADDSTRING, 0, LPARAM(PGMChar(ADSN)));
end;

procedure FillComboBoxDSN(const AComboBox: TGMComboBox; const ADSNEnumProc: TGMEnumDSNProc);
var odbcEnv: TGMOdbcEnvironment; i, wMax: LongInt; oldText: TGMString;
begin
  if (AComboBox = nil) or not Assigned(ADSNEnumProc) then Exit;
  oldText := AComboBox.Text;
  try
   GMSendObjMessage(AComboBox, CB_RESETCONTENT);

   AddDSNToComboBox(RStrTemplate + ': DRIVER=SQL Server;DATABASE=???;PWD=???;SERVER=???;UID=???', AComboBox);
   AddDSNToComboBox(RStrTemplate + ': DRIVER=Oracle in OraClient12Home1_32bit;DBQ=???;PWD=???;SERVER=???;UID=???', AComboBox);
   AddDSNToComboBox(RStrTemplate + ': DRIVER={Microsoft Text-Treiber (*.txt; *.csv)};DefaultDir=C:\Pfad\Daten;FIL=text', AComboBox);
   AddDSNToComboBox(RStrTemplate + ': DRIVER=Microsoft Excel-Treiber (*.xls);DBQ=C:\Pfad\Zur\Datei.xls;Readonly=1;HDR=YES;IMEX=0', AComboBox);
   AddDSNToComboBox(RStrTemplate + ': DRIVER=Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb);DBQ=C:\Pfad\Zur\Datei.xls;Readonly=1;HDR=YES;IMEX=0', AComboBox);
   AddDSNToComboBox(RStrTemplate + ': DRIVER=Microsoft Access-Treiber (*.mdb);DBQ=C:\Pfad\Zur\Datei.mdb', AComboBox);
   AddDSNToComboBox(RStrTemplate + ': DRIVER=Microsoft Access Driver (*.mdb, *.accdb);DBQ=C:\Pfad\Zur\Datei.mdb', AComboBox);

   odbcEnv := TGMOdbcEnvironment.Create(False);
   try
    ODBCEnumSystemDSN(odbcEnv, ADSNEnumProc, AComboBox);
    ODBCEnumUserDSN(odbcEnv, ADSNEnumProc, AComboBox);
   finally
    odbcEnv.Free;
   end;
   wMax := 0;
   for i:=0 to GMSendObjMessage(AComboBox, CB_GETCOUNT)-1 do
    wMax := Max(wMax, GMTextExtent(AComboBox.GetListBoxString(i), AComboBox.FontHandle).x);
   GMSendObjMessage(AComboBox, CB_SETDROPPEDWIDTH, wMax + 8, 0);
  finally
   AComboBox.Text := oldText;
  end;
end;


{ -------------------------- }
{ ---- TComboBoxOdbcDSN ---- }
{ -------------------------- }

procedure TComboBoxOdbcDSN.UMDSNDropSelect(var Msg: TMessage);
var dsnTxt: TGMString;
begin
  dsnTxt := ExtractDSNFromDisplayName(GetListBoxString(Msg.WParam));
  if GMStrLScan(PGMChar(dsnTxt), '=', Length(dsnTxt)) = nil then Text := cStrCnStrDSN + '=' + dsnTxt else Text := dsnTxt;
  if Assigned(OnAfterEditTextChange) then OnAfterEditTextChange(Self);
end;

procedure TComboBoxOdbcDSN.WMAppCommand(var Msg: TWMCommand);
begin
  case Msg.NotifyCode of
   CBN_SELCHANGE: GMPostObjMessage(Self, UM_DSNDROPSELECT, GMSendObjMessage(Self, CB_GETCURSEL));
   else inherited;
  end;
  FPassMessageToOriginalHandler := False;
end;


{ ----------------------------------- }
{ ---- TGMOdbcConnectionPropUIArea ---- }
{ ----------------------------------- }

constructor TGMOdbcConnectionPropUIArea.Create(const AParent: TObject;
  const APosition: TRect; const AAreaAlign: TGMAreaAlignRec;
  const AOnDataChange: TOdbcDataChangeProc; const ABkgndColor: COLORREF;
  const AVisible, ARefLifeTime: Boolean);
//const cSpace = c2CtlSpace;
var area, upperArea, labelArea, ctrlArea: TObject; a: TOdbcConnectionAttribute; // tableArea: TGMxTableArea;
begin
  inherited Create(AParent, APosition, AAreaAlign, ABkgndColor, AVisible, ARefLifeTime);
  FOnDataChange := AOnDataChange;

  upperArea := OwnArea(TGMSurroundingUiArea.Create(Self, cNullrect, cTopAligned, ABkgndColor));

//tableArea := OwnArea(TGMxTableArea.Create(upperArea, 2, cNullRect, cTopAligned, ABkgndColor)) as TGMxTableArea;
  labelArea := OwnArea(TGMSurroundingUiArea.Create(upperArea, GMRect(0, cCtlSpace, 0, 0), cTopLeftX, ABkgndColor));
  ctrlArea := OwnArea(TGMUiArea.Create(upperArea, GMRect(0, cCtlSpace, 0, 0), cClientAligned, ABkgndColor));

//tableArea.OwnArea(TGMxLabel.Create(tableArea, cNullRect, cLeftAligned, cNullRect, RStrDataSource + ':', ABkgndColor));
//band := tableArea.OwnArea(TGMSurroundingUiArea.Create(tableArea, GMRect(c2CtlSpace, 0, 0, 0), cTopAligned, ABkgndColor));
//FBtnEditConnectionString := OwnArea(TGMxToolBtnArea.Create(band, GMRect(-cEditHeight, 0, 0, cEditHeight), cTopRightX, OnBtnEditConnectionStringClick, '', 0, OdbcDlgImages)) as TGMxToolBtnArea;
//OwnArea(TGMHintWindow.Create(-Int64(FBtnEditConnectionString), cNullRect, cClientAligned, RStrEditCnStrDlgHintText, RStrEditCnStrDlgHintTitle));
//FComboBoxDSN := tableArea.OwnArea(TGMComboBox.Create(-Int64(band), GMRect(c2CtlSpace, 0, cCtlSpace, cEditHeight), cTopAligned, '', cVisibleTabstop or CBS_DROPDOWN or CBS_AUTOHSCROLL)) as TGMComboBox;

  OwnArea(TGMxLabel.Create(labelArea, GMRect(0, 0, 0, cEditHeight), cLabelAlign, cNullRect, RStrConnectionString + ':', ABkgndColor));
  area := OwnArea(TGMUiArea.Create(ctrlArea, GMRect(0, 0, 0, cEditHeight), cTopAligned, ABkgndColor));
//area := tableArea.OwnArea(TGMSurroundingUiArea.Create(tableArea, GMRect(c2CtlSpace, 0, 0, 0), cTopAligned, ABkgndColor));
  FBtnEditConnectionString := OwnArea(TGMxToolBtnArea.Create(area, GMRect(-cEditHeight, 0, 0, cEditHeight), cTopRightX, OnBtnEditConnectionStringClick, '', 0, OdbcDlgImages)) as TGMxToolBtnArea;
  OwnArea(TGMHintWindow.Create(-Int64(FBtnEditConnectionString), cNullRect, cClientAligned, RStrEditCnStrDlgHintText, RStrEditConnectionString));
  FComboBoxDSN := OwnArea(TComboBoxOdbcDSN.Create(-Int64(area), GMRect(c2CtlSpace, 0, cCtlSpace, cEditHeight), cTopAligned, '', cVisibleTabstop or CBS_DROPDOWN or CBS_AUTOHSCROLL)) as TGMComboBox;
  FComboBoxDSN.TextWhenEmpty := srConnectionStrTextWhenEmpty;

  FComboBoxAccessMode := GMInsertLabeledCtrl(RStrAccessMode, labelArea, ctrlArea, TGMComboBox, cVisibleTabstop or CBS_DROPDOWNLIST, clrWindow, ABkgndColor, 0, cEditHeight, c2CtlSpace).Ctrl as TGMComboBox;

  FEditUsername := GMInsertLabeledCtrl(RStrUsername, labelArea, ctrlArea, TGMFramedEdit, cVisibleTabstop, clrWindow, ABkgndColor, 0, cEditHeight, c2CtlSpace).Ctrl as TGMFramedEdit;
  FEditPassword := GMInsertLabeledCtrl(RStrPassword, labelArea, ctrlArea, TGMFramedEdit, cVisibleTabstop or ES_PASSWORD, clrWindow, ABkgndColor, 0, cEditHeight, c2CtlSpace).Ctrl as TGMFramedEdit;
//FEditPassword.TextWhenEmpty := RStrPassword;

  FComboBoxCursorOrigin := GMInsertLabeledCtrl(RStrCursorOrigin, labelArea, ctrlArea, TGMComboBox, cVisibleTabstop or CBS_DROPDOWNLIST, clrWindow, ABkgndColor, 0, cEditHeight, c2CtlSpace).Ctrl as TGMComboBox;
  FComboBoxTransIsolation := GMInsertLabeledCtrl(RStrIsolation, labelArea, ctrlArea, TGMComboBox, cVisibleTabstop or CBS_DROPDOWNLIST, clrWindow, ABkgndColor, 0, cEditHeight, c2CtlSpace).Ctrl as TGMComboBox;
  FComboBoxDriverDialogs := GMInsertLabeledCtrl(RStrDriverDialogs, labelArea, ctrlArea, TGMComboBox, cVisibleTabstop or CBS_DROPDOWNLIST, clrWindow, ABkgndColor, 0, cEditHeight, c2CtlSpace).Ctrl as TGMComboBox;

//  OwnArea(TGMxLabel.Create(labelArea, GMRect(0, cCtlSpace, 0, cEditHeight), cLabelAlign, cNullRect, RStrLoginTimeout + ':', BkgndColor));
//  FIntEditLoginTimeout := OwnArea(TGMIntEdit.Create(ctrlArea, GMRect(0, cCtlSpace, 0, cEditHeight), cTopAligned, 0, cMaxTimeout)) as TGMIntEdit;

//  OwnArea(TGMxLabel.Create(labelArea, GMRect(0, cCtlSpace, 0, cEditHeight), cLabelAlign, cNullRect, RStrOperationTimeout + ':', BkgndColor));
//  FIntEditStmtTimeout := OwnArea(TGMIntEdit.Create(ctrlArea, GMRect(0, cCtlSpace, 0, cEditHeight), cTopAligned, 0, cMaxTimeout)) as TGMIntEdit;

  OwnArea(TGMxLabel.Create(labelArea, GMRect(0, cCtlSpace, 0, cEditHeight), cLabelAlign, cNullRect, RStrLoginTimeout + ':', ABkgndColor));
  area := OwnArea(TGMUiArea.Create(ctrlArea, GMRect(0, cCtlSpace, 0, cEditHeight), cTopAligned, ABkgndColor));
  OwnArea(TGMxLabel.Create(area, GMRect(0, 0, 0, cEditHeight), cTopRightX, cNullRect, RStrTimeDesc, ABkgndColor));
  FIntEditLoginTimeout := OwnArea(TGMIntEdit.Create(area, GMRect(c2CtlSpace, 0, c2CtlSpace, cEditHeight), cTopAligned, 0, cMaxTimeout)) as TGMIntEdit;

  OwnArea(TGMxLabel.Create(labelArea, GMRect(0, cCtlSpace, 0, cEditHeight), cLabelAlign, cNullRect, RStrOperationTimeout + ':', ABkgndColor));
  area := OwnArea(TGMUiArea.Create(ctrlArea, GMRect(0, cCtlSpace, 0, cEditHeight), cTopAligned, ABkgndColor));
  OwnArea(TGMxLabel.Create(area, GMRect(0, 0, 0, cEditHeight), cTopRightX, cNullRect, RStrTimeDesc, ABkgndColor));
  FIntEditStmtTimeout := OwnArea(TGMIntEdit.Create(area, GMRect(c2CtlSpace, 0, c2CtlSpace, cEditHeight), cTopAligned, 0, cMaxTimeout)) as TGMIntEdit;

//  FCBChangeLogProtocolElement[e] := OwnArea(TGMCheckBox.Create(-Int64(Self), GMRect(c2CtlSpace, cTopSpace[e = Low(e)], c2CtlSpace, 0),
//    cWrapRightY, ChangeLogElementDisplayName(e), OnCBProtocolelementChanged, cAdjstChkBtnStyle, 0, ABkgndColor)) as TGMCheckBox;

//    FAttrCheckBoxes: array [TOdbcAllowDriverDialogs] of TGMxCheckBoxArea;
  OwnArea(TGMxLabel.Create(Self, GMRect(0, 6, 0, 0), cTopAligned, cNullRect, RStrAttributes + ':', ABkgndColor, GMBoldUIFont));
  area := OwnArea(TGMSurroundingUiArea.Create(Self, GMRect(0, 2, 0, 0), cTopAligned, GMPoint(0, cCtlSpace), vLightGray));
  GMAssignRoundedAreaProperties(area);
  //GMSetObjMultiFrame(area, frsRaised, frsLowered);
  for a:=Low(a) to High(a) do
   FAttrCheckBoxes[a] := OwnArea(TGMxCheckBoxArea.Create(area, GMRect(cCtlSpace, cCtlSpace, cCtlSpace, 0), cTopAligned, GMOdbcConnectionAttrName(a), OnAttributesChange, vLightGray)) as TGMxCheckBoxArea;

//FComboBoxDSN.OnAfterSelectionChange := OnComboBoxDSNDropSelect;
  FComboBoxDSN.OnAfterEditTextChange := OnComboBoxDSNTextChange;
  FComboBoxAccessMode.OnAfterSelectionChange := OnComboBoxAccessModeChange;
  FComboBoxDriverDialogs.OnAfterSelectionChange := OnComboBoxDriverDialogsChange;
  FEditUsername.OnAfterTextChange := OnEditUserNameChange;
  FEditPassword.OnAfterTextChange := OnEditPasswordChange;
  FComboBoxCursorOrigin.OnAfterSelectionChange := OnComboBoxCursorOriginChange;
  FComboBoxTransIsolation.OnAfterSelectionChange := OnComboBoxTransIsolationChange;
  FIntEditLoginTimeout.OnAfterValueChange := OnIntEditLoginTimeoutChange;
  FIntEditStmtTimeout.OnAfterValueChange := OnIntEditOperationTimeoutChange;

  //IntEditLoginTimeout.Hint := RStrValueBoundsHint;
  //IntEditOperationTimeout.Hint := RStrValueBoundsHint;
end;        

procedure TGMOdbcConnectionPropUIArea.DataChanged(const ANewName: TGMString);
begin
  if Assigned(FOnDataChange) then FOnDataChange(ANewName);
end;

procedure TGMOdbcConnectionPropUIArea.FillupComboBoxDSN;
begin
  FillComboBoxDSN(FComboBoxDSN, AddDSNToComboBox);
end;

procedure TGMOdbcConnectionPropUIArea.CreateHandle;
var strValues: TGMStringArray; am: TAccessMode; cor: TCursorOrigin; txi: TTransactionIsolation; ddlg: TOdbcAllowDriverDialogs;
    itemDataArr: TGMUiItemDataArray;
begin
//  if HandleAllocated then begin inherited CreateHandle; Exit; end else inherited CreateHandle;
  inherited;
  FillupComboBoxDSN;

  SetLength(strValues, 0);
  for am:=Low(am) to High(am) do GMAddStrToArray(GMAccessModeName(am), strValues);
  GMFillComboBoxFromStrings(FComboBoxAccessMode, strValues);

  SetLength(strValues, 0);
  for cor:=Low(cor) to High(cor) do GMAddStrToArray(GMCursorOriginName(cor), strValues);
  GMFillComboBoxFromStrings(FComboBoxCursorOrigin, strValues);

//SetLength(strValues, 0);
//for txi:=Low(txi) to High(txi) do GMAddStrToArray(GMTransactionIsolationName(txi), strValues);
//GMFillComboBoxFromStrings(FComboBoxTransIsolation, strValues);

  SetLength(itemDataArr, 0);
  GMAddUiItemDataToArray(GMInitUiItemData(RStrUseDBDefaultTxIsolation, cItemDataTxIsolationUseDflt), itemDataArr);
  for txi:=Low(txi) to High(txi) do
      GMAddUiItemDataToArray(GMInitUiItemData(GMTransactionIsolationName(txi), Ord(txi)), itemDataArr);
  GMFillComboBox(FComboBoxTransIsolation, itemDataArr);

  SetLength(strValues, 0);
  for ddlg:=Low(ddlg) to High(ddlg) do GMAddStrToArray(GMDriverDialogName(ddlg), strValues);
  GMFillComboBoxFromStrings(FComboBoxDriverDialogs, strValues);
end;

procedure TGMOdbcConnectionPropUIArea.OnBtnEditConnectionStringClick(const ASender: TObject);
var dlg: IGMGetHandle;
begin
  dlg := TGMConnectionStrEditDlg.Create(FComboBoxDSN.Text, RStrEditConnectionString, RStrConnectionString, GMModalDlgParentWnd);
  if GMShowModalWnd(dlg.Handle) = IDOK then
   begin
    FComboBoxDSN.Text := GMGetIntfText(dlg);
    OnComboBoxDSNTextChange(FComboBoxDSN);
   end;
end;

procedure TGMOdbcConnectionPropUIArea.SetConnectProperties(const AValue: IGMOdbcConnectProperties);
var t: TTransactionIsolation; a: TOdbcConnectionAttribute; itemData: PtrInt;
begin
  //if FConnectProperties = Value then Exit;

  FConnectProperties := AValue;
  GMenableControls(Self, FConnectProperties <> nil, True, []);
  if AValue = nil then GMClearControls(Self, True, []) else
   begin
    FComboBoxDSN.Text := ConnectProperties.Obj.ConnectionString;
    FComboBoxAccessMode.SelectedIndex := Ord(ConnectProperties.Obj.AccessMode);
    FEditUsername.Text := ConnectProperties.Obj.Username;
    FEditPassword.Text := ConnectProperties.Obj.Password;
    FComboBoxCursorOrigin.SelectedIndex := Ord(ConnectProperties.Obj.CursorOrigin);
    FComboBoxDriverDialogs.SelectedIndex := Ord(ConnectProperties.Obj.AllowDriverDialogs);

    itemData := -100;
    if ConnectProperties.Obj.TransactionIsolation = [] then itemData := cItemDataTxIsolationUseDflt else
     for t:=Low(t) to High(t) do
      if t in ConnectProperties.Obj.TransactionIsolation then itemData := Ord(t);
    FComboBoxTransIsolation.SelectItemData(itemData, False);

    FIntEditLoginTimeout.Value := ConnectProperties.Obj.TimeoutForLogin;
    FIntEditStmtTimeout.Value := ConnectProperties.Obj.TimeoutForStatements;
    for a:=Low(a) to High(a) do FAttrCheckBoxes[a].Checked := a in ConnectProperties.Obj.Attributes;
   end;
end;

procedure TGMOdbcConnectionPropUIArea.OnComboBoxDSNTextChange(const ASender: TObject);
begin
  if (ConnectProperties = nil) or GMSameText(ConnectProperties.Obj.ConnectionString, (ASender as TGMComboBox).Text) then Exit;
  ConnectProperties.Obj.ConnectionString := (ASender as TGMComboBox).Text;
  DataChanged(GMExtractNameFromConnectionString(ConnectProperties.Obj.ConnectionString));
end;

//procedure TGMOdbcConnectionPropUIArea.OnComboBoxDSNDropSelect(const ASender: TObject);
//begin
//if ConnectProperties = nil then Exit;
//
////GMPostObjMessage(FComboBoxDSN, WM_COMMAND + WM_APP, MakeLong(0, CBN_EDITCHANGE));
////PostMessage(FComboBoxDSN.Handle, WM_COMMAND, MakeLong(0, CBN_EDITCHANGE), 0);
//
////OnComboBoxDSNTextChange(FComboBoxDSN);
////FComboBoxDSN.SelectAll;
//end;

procedure TGMOdbcConnectionPropUIArea.OnComboBoxAccessModeChange(const ASender: TObject);
begin
  if ConnectProperties = nil then Exit;
  ConnectProperties.Obj.AccessMode := TAccessMode(GMBoundedInt(GMSendObjMessage(ASender, CB_GETCURSEL), Ord(Low(TAccessMode)), Ord(High(TAccessMode))));
  DataChanged;
end;

procedure TGMOdbcConnectionPropUIArea.OnComboBoxDriverDialogsChange(const ASender: TObject);
begin
  if ConnectProperties = nil then Exit;
  ConnectProperties.Obj.AllowDriverDialogs := TOdbcAllowDriverDialogs(GMBoundedInt(GMSendObjMessage(ASender, CB_GETCURSEL), Ord(Low(TOdbcAllowDriverDialogs)), Ord(High(TOdbcAllowDriverDialogs))));
  DataChanged;
end;

procedure TGMOdbcConnectionPropUIArea.OnEditUserNameChange(const ASender: TObject);
begin
  if ConnectProperties = nil then Exit;
  ConnectProperties.Obj.Username := (ASender as TGMFramedEdit).Text;
  DataChanged;
end;

procedure TGMOdbcConnectionPropUIArea.OnEditPasswordChange(const ASender: TObject);
begin
  if ConnectProperties = nil then Exit;
  ConnectProperties.Obj.Password := (ASender as TGMFramedEdit).Text;
  DataChanged;
end;

procedure TGMOdbcConnectionPropUIArea.OnComboBoxCursorOriginChange(const ASender: TObject);
begin
  if ConnectProperties = nil then Exit;
  ConnectProperties.Obj.CursorOrigin := TCursorOrigin(GMBoundedInt(GMSendObjMessage(ASender, CB_GETCURSEL), Ord(Low(TCursorOrigin)), Ord(High(TCursorOrigin))));
  DataChanged;
end;

procedure TGMOdbcConnectionPropUIArea.OnComboBoxTransIsolationChange(const ASender: TObject);
var itemVal: PtrInt;
begin
  if (ConnectProperties <> nil) and (ASender is TGMComboBox) then
   begin
    itemVal := TGMComboBox(ASender).GetItemData(TGMComboBox(ASender).SelectedIndex);

    if GMISInRange(itemVal, Ord(Low(TTransactionIsolation)), Ord(High(TTransactionIsolation))) then
     begin ConnectProperties.Obj.TransactionIsolation := [TTransactionIsolation(itemVal)]; DataChanged; end
    else
     if itemVal = cItemDataTxIsolationUseDflt then begin ConnectProperties.Obj.TransactionIsolation := []; DataChanged; end;
   end;
end;

procedure TGMOdbcConnectionPropUIArea.OnIntEditLoginTimeoutChange(const ASender: TObject);
begin
  if ConnectProperties = nil then Exit;
  ConnectProperties.Obj.TimeoutForLogin := (ASender as TGMIntEdit).Value;
  DataChanged;
end;

procedure TGMOdbcConnectionPropUIArea.OnIntEditOperationTimeoutChange(const ASender: TObject);
begin
  if ConnectProperties = nil then Exit;
  ConnectProperties.Obj.TimeoutForStatements := (ASender as TGMIntEdit).Value;
  DataChanged;
end;

procedure TGMOdbcConnectionPropUIArea.OnAttributesChange(const ASender: TObject);
var a: TOdbcConnectionAttribute;
begin
  if (ConnectProperties = nil) or not (ASender is TGMxCheckBoxArea) then Exit;
  for a:=Low(a) to High(a) do
   if ASender = FAttrCheckBoxes[a] then
    begin
     if (ASender as TGMxCheckBoxArea).Checked then
      ConnectProperties.Obj.Attributes := ConnectProperties.Obj.Attributes + [a]
     else
      ConnectProperties.Obj.Attributes := ConnectProperties.Obj.Attributes - [a];

     if Assigned(OnAttributesChanged) then OnAttributesChanged(ASender);
     Datachanged;
     Break;
    end;
end;


{ ------------------------------------ }
{ ---- TGMOdbcRecordsetPropUIArea ---- }
{ ------------------------------------ }

constructor TGMOdbcRecordsetPropUIArea.Create(const AParent: TObject;
  const APosition: TRect; const AAreaAlign: TGMAreaAlignRec;
  const AOnDataChange: TOdbcDataChangeProc; const ABkgndColor: COLORREF;
  const AVisible, ARefLifeTime: Boolean);
const //cSpace = c2CtlSpace; //cHAttrs = 92; cHCounts = 58;
      //cListStyle = LVS_SMALLICON or LVS_SINGLESEL or LVS_SHAREIMAGELISTS or LVS_SHOWSELALWAYS or LVS_NOSCROLL or LVS_AUTOARRANGE; // WS_VSCROLL
      cRCtrl: TRect = (Left: c2CtlSpace; Top: cCtlSpace; Right: 0; Bottom: cEditHeight);
      cRLabel: TRect = (Left: 0; Top: cCtlSpace; Right: 0; Bottom: 0);
      c2 = 2; c6 = 6;
var tableArea: TGMxTableArea; area: TObject; a: TGMRecordsetAttribute; c: TRecordCountStrategy;
begin
  inherited Create(AParent, APosition, AAreaAlign, ABkgndColor, AVisible, ARefLifeTime);
  FOnDataChange := AOnDataChange;

  tableArea := OwnArea(TGMxTableArea.Create(Self, 2, cNullRect, cTopAligned, ABkgndColor)) as TGMxTableArea;

  //FComboBoxCursorType := GMInsertLabeledCtrl(RStrCursorType, LabelArea, CtrlArea, TGMComboBox, cVisibleTabstop or CBS_DROPDOWNLIST, clrWindow, cDfltColor, cSpace).Ctrl as TGMComboBox;
  tableArea.OwnArea(TGMxLabel.Create(tableArea, cNullRect, cLeftAligned, cNullRect, RStrCursorType + ':', ABkgndColor));
  FComboBoxCursorType := tableArea.OwnArea(TGMComboBox.Create(-Int64(tableArea), GMRect(c2CtlSpace, 0, 0, cEditHeight), cTopAligned, '', cVisibleTabstop or CBS_DROPDOWNLIST)) as TGMComboBox;
  //tableArea[0, 1] := FComboBoxCursorType;
  FComboBoxCursorType.OnAfterSelectionChange := OnComboBoxCursorTypeChange;

  //FComboBoxCursorSensitivity := GMInsertLabeledCtrl(RStrCursorSensitivity, LabelArea, CtrlArea, TGMComboBox, cVisibleTabstop or CBS_DROPDOWNLIST, clrWindow, cDfltColor, cSpace).Ctrl as TGMComboBox;
  tableArea.OwnArea(TGMxLabel.Create(tableArea, cRLabel, cLeftAligned, cNullRect, RStrCursorSensitivity + ':', ABkgndColor));
  FComboBoxCursorSensitivity := tableArea.OwnArea(TGMComboBox.Create(-Int64(tableArea), cRCtrl, cTopAligned, '', cVisibleTabstop or CBS_DROPDOWNLIST)) as TGMComboBox;
  //tableArea[1, 1] := FComboBoxCursorSensitivity;
  FComboBoxCursorSensitivity.OnAfterSelectionChange := OnComboBoxCursorSensitivityChange;

  //FComboBoxUpdateStrategy := GMInsertLabeledCtrl(RStrUpdateStrategy, LabelArea, CtrlArea, TGMComboBox, cVisibleTabstop or CBS_DROPDOWNLIST, clrWindow, cDfltColor, cSpace).Ctrl as TGMComboBox;
  tableArea.OwnArea(TGMxLabel.Create(tableArea, cRLabel, cLeftAligned, cNullRect, RStrUpdateStrategy + ':', ABkgndColor));
  FComboBoxUpdateStrategy := tableArea.OwnArea(TGMComboBox.Create(-Int64(tableArea), cRCtrl, cTopAligned, '', cVisibleTabstop or CBS_DROPDOWNLIST)) as TGMComboBox;
  //tableArea[2, 1] := FComboBoxUpdateStrategy;
  FComboBoxUpdateStrategy.OnAfterSelectionChange := OnComboBoxUpdateStrategyChange;

  //FComboBoxUpdateSimulation := GMInsertLabeledCtrl(RStrUpdateSimulation, LabelArea, CtrlArea, TGMComboBox, cVisibleTabstop or CBS_DROPDOWNLIST, clrWindow, cDfltColor, cSpace).Ctrl as TGMComboBox;
  tableArea.OwnArea(TGMxLabel.Create(tableArea, cRLabel, cLeftAligned, cNullRect, RStrUpdateSimulation + ':', ABkgndColor));
  FComboBoxUpdateSimulation := tableArea.OwnArea(TGMComboBox.Create(-Int64(tableArea), cRCtrl, cTopAligned, '', cVisibleTabstop or CBS_DROPDOWNLIST)) as TGMComboBox;
  //tableArea[3, 1] := FComboBoxUpdateSimulation;
  FComboBoxUpdateSimulation.OnAfterSelectionChange := OnComboBoxUpdateSimulationChange;

  //FComboBoxBlobCompression := GMInsertLabeledCtrl(RStrBLOBCompression, LabelArea, CtrlArea, TGMComboBox, CBS_DROPDOWNLIST, clrWindow, cDfltColor, cSpace).Ctrl as TGMComboBox;

  //FIntEditKeysetSize := OwnArea(TGMIntEdit.Create(CtrlArea, GMRect(cSpace, cCtlSpace, cSpace, cEditHeight), cTopAligned, 0, High(LongInt))) as TGMIntEdit;
  tableArea.OwnArea(TGMxLabel.Create(tableArea, cRLabel, cLeftAligned, cNullRect, RStrKeysetSize + ':', ABkgndColor));
  FIntEditKeysetSize := tableArea.OwnArea(TGMIntEdit.Create(tableArea, cRCtrl, cTopAligned, 0, High(LongInt), ABkgndColor)) as TGMIntEdit;
  //tableArea[4, 1] := FIntEditKeysetSize;
  FIntEditKeysetSize.OnAfterValueChange := OnIntEditKeysetSizeChange;

  //FIntEditReturnedRecords := OwnArea(TGMIntEdit.Create(CtrlArea, GMRect(cSpace, cCtlSpace, cSpace, cEditHeight), cTopAligned, 0, High(LongInt))) as TGMIntEdit;
  tableArea.OwnArea(TGMxLabel.Create(tableArea, cRLabel, cLeftAligned, cNullRect, RStrReturnedRecords + ':', ABkgndColor));
  FIntEditReturnedRecords := tableArea.OwnArea(TGMIntEdit.Create(tableArea, cRCtrl, cTopAligned, 0, High(LongInt), ABkgndColor)) as TGMIntEdit;
  //tableArea[5, 1] := FIntEditReturnedRecords;
  FIntEditReturnedRecords.OnAfterValueChange := OnIntEditReturnedRecordsChange;

  //FIntEditMaxDataSize := OwnArea(TGMIntEdit.Create(CtrlArea, GMRect(cSpace, cCtlSpace, cSpace, cEditHeight), cTopAligned, 0, High(LongInt))) as TGMIntEdit;
  tableArea.OwnArea(TGMxLabel.Create(tableArea, cRLabel, cLeftAligned, cNullRect, RStrMaxDataSize + ':', ABkgndColor));
  FIntEditMaxDataSize := tableArea.OwnArea(TGMIntEdit.Create(tableArea, cRCtrl, cTopAligned, 0, High(LongInt), ABkgndColor)) as TGMIntEdit;
  //tableArea[6, 1] := FIntEditMaxDataSize;
  FIntEditMaxDataSize.OnAfterValueChange := OnIntEditMaxDataSizeChange;

//tableArea.OwnArea(TGMxLabel.Create(tableArea, cRLabel, cLeftAligned, cNullRect, RStrMaxStrLenOrigin + ':', ABkgndColor));
//FComboBoxMaxStrLenOrigin := tableArea.OwnArea(TGMComboBox.Create(-Int64(tableArea), cRCtrl, cTopAligned, '', cVisibleTabstop or CBS_DROPDOWNLIST)) as TGMComboBox;
//FComboBoxMaxStrLenOrigin.OnAfterSelectionChange := OnComboBoxMaxStrLenOriginChange;

//FLabelCharSizeFactor :=
//tableArea.OwnArea(TGMxLabel.Create(tableArea, cRLabel, cLeftAligned, cNullRect, RStrCharSizeFactor + ':', ABkgndColor)); // as TGMxLabel;
//FEditCharSizeFactor := tableArea.OwnArea(TGMColorTextFramedEdit.Create(-Int64(tableArea), cRCtrl, cTopAligned, '', cVisibleTabstop)) as TGMColorTextFramedEdit;
//FEditCharSizeFactor.OnAfterTextChange := OnEditCharSizeFactorChange;
//FSizeFactorConvertErrorHint := OwnArea(TGMHintWindow.Create(-Int64(FEditCharSizeFactor), cNullRect, cClientAligned, '', '')) as TGMHintWindow;

  OwnArea(TGMxLabel.Create(Self, GMRect(0, c6, 0, 0), cTopAligned, cNullRect, RStrAttributes + ':', ABkgndColor, GMBoldUIFont));
  area := OwnArea(TGMSurroundingUiArea.Create(Self, GMRect(0, c2, 0, 0), cTopAligned, GMPoint(0, cCtlSpace), vLightGray));
  GMAssignRoundedAreaProperties(area);
  //GMSetObjMultiFrame(area, frsRaised, frsLowered);
  for a:=Low(a) to High(a) do
   FAttrCheckBoxes[a] := OwnArea(TGMxCheckBoxArea.Create(area, GMRect(cCtlSpace, cCtlSpace, cCtlSpace, 0), cTopAligned, GMRecordsetAttributeName(a), OnAttributesChange, vLightGray)) as TGMxCheckBoxArea;

  OwnArea(TGMxLabel.Create(Self, GMRect(0, c6, 0, 0), cTopAligned, cNullRect, RStrCountStrateies + ':', ABkgndColor, GMBoldUIFont));
  area := OwnArea(TGMSurroundingUiArea.Create(Self, GMRect(0, c2, 0, 0), cTopAligned, GMPoint(0, cCtlSpace), vLightGray));
  GMAssignRoundedAreaProperties(area);
  //GMSetObjMultiFrame(area, frsRaised, frsLowered);
  for c:=Low(c) to High(c) do
   FCountStrgyCheckBoxes[c] := OwnArea(TGMxCheckBoxArea.Create(area, GMRect(cCtlSpace, cCtlSpace, cCtlSpace, 0), cTopAligned, GMCountStrategyName(c), OnCountStrategiesChange, vLightGray)) as TGMxCheckBoxArea;

//
//
//OwnArea(TGMxLabel.Create(LabelArea, GMRect(cSpace, cCtlSpace, 0, cEditHeight), cLabelAlign, cNullRect, RStrReexecuteDelay + ':', haLeft, vaCenter, BkgndColor));
//FIntEditReexecuteDelay := OwnArea(TGMIntEdit.Create(CtrlArea, GMRect(cSpace, cCtlSpace, cSpace, cEditHeight), cTopAligned, 0, High(LongInt))) as TGMIntEdit;
//FIntEditReexecuteDelay.OnAfterValueChange := OnIntEditReexecuteDelayChange;
//

//
//area := OwnArea(TGMSurroundingUiArea.Create(Self, GMRect(cSpace, cCtlSpace, cSpace, 0), cTopAligned, GMPoint(0, cCtlSpace)));
//FCheckBoxUseTimeoutFromCn := OwnArea(TGMCheckBox.Create(-Int64(area), GMRect(cSpace, cCtlSpace, cSpace, 0), cTopAligned, RStrUseTimeoutFromCn, cAdjstChkBtnStyle)) as TGMCheckBox;
//FTimeoutLabel := OwnArea(TGMxLabel.Create(area, GMRect(cSpace, cCtlSpace, 0, cEditHeight), cTopLeftX, cNullRect, RStrTimeout + ':', haLeft, vaCenter, BkgndColor)) as TGMxLabel;
//FIntEditTimeout := OwnArea(TGMIntEdit.Create(area, GMRect(cSpace, cCtlSpace, cSpace, cEditHeight), cTopAligned, 0, High(LongInt))) as TGMIntEdit;
//GMSetObjMultiFrame(area, frsRaised, frsLowered);
//
//FCheckBoxDoEscapeScan := OwnArea(TGMCheckBox.Create(-Int64(Self), GMRect(cSpace, cCtlSpace, cSpace, 0), cTopAligned, RStrDoEscScan, cAdjstChkBtnStyle)) as TGMCheckBox;
//

//FCheckBoxUseTimeoutFromCn.OnClick := OnCheckBoxUseTimeoutFromCnChange;
//FIntEditTimeout.OnAfterValueChange := OnIntEditTimeoutChange;
//FCheckBoxDoEscapeScan.OnClick := OnCheckBoxDoEscapeScanChange;
end;

procedure TGMOdbcRecordsetPropUIArea.DataChanged(const ANewName: TGMString);
begin
  if Assigned(FOnDataChange) then FOnDataChange(ANewName);
end;

//procedure TGMOdbcRecordsetPropUIArea.SetupTimeoutCtrls;
////const cColor: array [Boolean] of COLORREF = (clBlack, clDkGray);
//begin
//FIntEditTimeout.Enabled := not FCheckBoxUseTimeoutFromCn.Checked;
////FTimeoutLabel.SetFontColor(cColor[FCheckBoxUseTimeoutFromCn.Checked]);
//FTimeoutLabel.SetEnabled(not FCheckBoxUseTimeoutFromCn.Checked);
//end;

procedure TGMOdbcRecordsetPropUIArea.CreateHandle;
var strValues: TGMStringArray; c: TGMCursorType; s: TCursorSensitivity; u: TUpdateStrategy; v: TPositionedUpdateSimulation;
//  l: TGMMaxStringLengthOrigin;
begin
//  if HandleAllocated then begin inherited CreateHandle; Exit; end else inherited CreateHandle;
  inherited;

  SetLength(strValues, 0);
  for c:=Low(c) to High(c) do GMAddStrToArray(GMCursorTypeName(c), strValues);
  GMFillComboBoxFromStrings(FComboBoxCursorType, strValues);

  SetLength(strValues, 0);
  for s:=Low(s) to High(s) do GMAddStrToArray(GMCursorSensitivityName(s), strValues);
  GMFillComboBoxFromStrings(FComboBoxCursorSensitivity, strValues);

  SetLength(strValues, 0);
  for u:=Low(u) to High(u) do GMAddStrToArray(GMUpdateStrategyName(u), strValues);
  GMFillComboBoxFromStrings(FComboBoxUpdateStrategy, strValues);

  SetLength(strValues, 0);
  for v:=Low(v) to High(v) do GMAddStrToArray(GMUpdateSimulationName(v), strValues);
  GMFillComboBoxFromStrings(FComboBoxUpdateSimulation, strValues);

//SetLength(strValues, 0);
//for l:=Low(l) to High(l) do GMAddStrToArray(GMMaxStrLenOriginName(l), strValues);
//GMFillComboBoxFromStrings(FComboBoxMaxStrLenOrigin, strValues);
end;

procedure TGMOdbcRecordsetPropUIArea.SetRecordsetProps(const AValue: IGMOdbcRecordsetProperties);
var a: TGMRecordsetAttribute; c: TRecordCountStrategy; // txt: TGMString;
begin
//ResetConvertErrorInfo;
  FRecordsetProps := AValue;
  GMenableControls(Self, FRecordsetProps <> nil, True, []);
  if AValue = nil then GMClearControls(Self, True, []) else
   begin
    FComboBoxCursorType.SelectedIndex := Ord(RecordsetProps.Obj.CursorType);
    FComboBoxCursorSensitivity.SelectedIndex := Ord(RecordsetProps.Obj.CursorSensitivity);
    FComboBoxUpdateStrategy.SelectedIndex := Ord(RecordsetProps.Obj.UpdateStrategy);
    FComboBoxUpdateSimulation.SelectedIndex := Ord(RecordsetProps.Obj.PositionedUpdateSimulation);

    for a:=Low(a) to High(a) do FAttrCheckBoxes[a].Checked := a in RecordsetProps.Obj.Attributes;
    for c:=Low(c) to High(c) do FCountStrgyCheckBoxes[c].Checked := c in RecordsetProps.Obj.RecordCountStrategies;

    FIntEditKeysetSize.Value := RecordsetProps.Obj.KeysetSize;
    FIntEditReturnedRecords.Value := RecordsetProps.Obj.MaxRecordsReturned;
    FIntEditMaxDataSize.Value := RecordsetProps.Obj.MaxFieldDataSize;
//  FIntEditReexecuteDelay.Value := RecordsetProps.TimedReExecutionDelay;

//  FComboBoxMaxStrLenOrigin.SelectedIdx := Ord(RecordsetProps.MaxStringLengthOrigin);


//  txt := GMStripRight(GMExtendedToStr(RecordsetProps.MaxStringLengthCharSizeFactor, -1, 20), cWhiteSpace + '0');
//  if (Length(txt) > 0) then
//   case txt[Length(txt)] of
//    ',', '.': txt := txt + '0';
//   end;
//  FEditCharSizeFactor.Text := txt;


//  SetupCharSizeFactor;

//  if FListViewAttributes.HandleAllocated then
//   for a:=Low(a) to High(a) do ListView_SetCheckState(FListViewAttributes.Handle, Ord(a), a in RecordsetProps.Attributes);
//
//  if FListViewCountStrategies.HandleAllocated then
//   for c:=Low(c) to High(c) do ListView_SetCheckState(FListViewCountStrategies.Handle, Ord(c), c in RecordsetProps.RecordCountStrategies);
//
//  FCheckBoxUseTimeoutFromCn.Checked := RecordsetProps.TimeoutProperties.UseValueFromConnection;
//  FIntEditTimeout.AValue := RecordsetProps.TimeoutProperties.TimeoutForStatements;
//
//  FCheckBoxDoEscapeScan.Checked := RecordsetProps.UseSQLEscapeSequences;
//  SetupTimeoutCtrls;
   end;
end;

//procedure TGMOdbcRecordsetPropUIArea.SetupCharSizeFactor;
//var enable: Boolean;
//begin
//enable := FComboBoxMaxStrLenOrigin.SelectedIdx = Ord(sloLengthInChars);
//FLabelCharSizeFactor.SetEnabled(enable);
//GMEnableObj(FEditCharSizeFactor, enable);
//end;

//procedure TGMOdbcRecordsetPropUIArea.ResetConvertErrorInfo;
//begin
//GMSendObjMessage(FSizeFactorConvertErrorHint, TTM_POP);
//FSizeFactorConvertErrorHint.SetText('');
//FSizeFactorConvertErrorHint.SetTitleAndIcon('', -1);
//FEditCharSizeFactor.SetFontColor(GMRGBColor(cDfltFontColor));
//end;

procedure TGMOdbcRecordsetPropUIArea.OnComboBoxCursorTypeChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.CursorType := TGMCursorType(GMBoundedInt(GMSendObjMessage(ASender, CB_GETCURSEL), Ord(Low(TGMCursorType)), Ord(High(TGMCursorType))));
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnComboBoxCursorSensitivityChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.CursorSensitivity := TCursorSensitivity(GMBoundedInt(GMSendObjMessage(ASender, CB_GETCURSEL), Ord(Low(TCursorSensitivity)), Ord(High(TCursorSensitivity))));
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnComboBoxUpdateStrategyChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.UpdateStrategy := TUpdateStrategy(GMBoundedInt(GMSendObjMessage(ASender, CB_GETCURSEL), Ord(Low(TUpdateStrategy)), Ord(High(TUpdateStrategy))));
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnComboBoxUpdateSimulationChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.PositionedUpdateSimulation := TPositionedUpdateSimulation(GMBoundedInt(GMSendObjMessage(ASender, CB_GETCURSEL), Ord(Low(TPositionedUpdateSimulation)), Ord(High(TPositionedUpdateSimulation))));
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnIntEditKeysetSizeChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.KeysetSize := (ASender as TGMIntEdit).Value;
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnIntEditMaxDataSizeChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.MaxFieldDataSize := (ASender as TGMIntEdit).Value;
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnIntEditReexecuteDelayChange(const Sender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.TimedReExecutionDelay := (Sender as TGMIntEdit).Value;
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnIntEditReturnedRecordsChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.MaxRecordsReturned := (ASender as TGMIntEdit).Value;
  Datachanged;
end;

//procedure TGMOdbcRecordsetPropUIArea.OnComboBoxMaxStrLenOriginChange(const ASender: TObject);
//begin
//if Recordset = nil then Exit;
//Recordset.MaxStringLengthOrigin := TGMMaxStringLengthOrigin(GMBoundedInt(GMSendObjMessage(ASender, CB_GETCURSEL), Ord(Low(TGMMaxStringLengthOrigin)), Ord(High(TGMMaxStringLengthOrigin))));
//Datachanged;
//SetupCharSizeFactor;
//end;

//procedure TGMOdbcRecordsetPropUIArea.OnEditCharSizeFactorChange(const ASender: TObject);
//var dblVal: Double; strVal: TGMString; convertCode: Integer;
//begin
//if Recordset = nil then Exit;
//strVal := (ASender as TGMEditBase).Text;
//strVal := GMReplaceChars(strVal, ',', '.'); // GMDeleteChars(AValue, ThousandSeparator)
//Val(strVal, dblVal, convertCode);
//if convertCode <> 0 then
// begin
//  (ASender as TGMColorTextFramedEdit).SetFontColor(clRed);
//  FSizeFactorConvertErrorHint.SetText(GMFormat(RStrInvalidFloatStrFmt, [strVal, convertCode]));
//  FSizeFactorConvertErrorHint.SetTitleAndIcon(RStrDataTypeConvertError, TTI_ERROR);
//  GMSendObjMessage(FSizeFactorConvertErrorHint, TTM_POPUP);
// end
//else
// begin
//  Recordset.MaxStringLengthCharSizeFactor := dblVal;
//  Datachanged;
//  ResetConvertErrorInfo;
// end;
////if convertCode <> 0 then raise EGMConvertException.ObjError(GMFormat(RStrInvalidFloatStrFmt, [AValue, convertCode]), nil, 'GMStrToDouble');
//end;

procedure TGMOdbcRecordsetPropUIArea.OnAttributesChange(const ASender: TObject);
var a: TGMRecordsetAttribute;
begin
  if (RecordsetProps = nil) or not (ASender is TGMxCheckBoxArea) then Exit;
  for a:=Low(a) to High(a) do
   if ASender = FAttrCheckBoxes[a] then
    begin
     if (ASender as TGMxCheckBoxArea).Checked then
      RecordsetProps.Obj.Attributes := RecordsetProps.Obj.Attributes + [a]
     else
      RecordsetProps.Obj.Attributes := RecordsetProps.Obj.Attributes - [a];

     Datachanged; Break;
    end;
end;

procedure TGMOdbcRecordsetPropUIArea.OnCountStrategiesChange(const ASender: TObject);
var c: TRecordCountStrategy;
begin
  if (RecordsetProps = nil) or not (ASender is TGMxCheckBoxArea) then Exit;
  for c:=Low(c) to High(c) do
   if ASender = FCountStrgyCheckBoxes[c] then
    begin
     if (ASender as TGMxCheckBoxArea).Checked then
      RecordsetProps.Obj.RecordCountStrategies := RecordsetProps.Obj.RecordCountStrategies + [c]
     else
      RecordsetProps.Obj.RecordCountStrategies := RecordsetProps.Obj.RecordCountStrategies - [c];

     Datachanged; Break;
    end;
end;

procedure TGMOdbcRecordsetPropUIArea.OnCheckBoxUseTimeoutFromCnChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.TimeoutProperties.UseValueFromConnection := (ASender as TGMCheckBox).Checked;
//SetupTimeoutCtrls;
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnIntEditTimeoutChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.TimeoutProperties.TimeoutForStatements := (ASender as TGMIntEdit).Value;
  Datachanged;
end;

procedure TGMOdbcRecordsetPropUIArea.OnCheckBoxDoEscapeScanChange(const ASender: TObject);
begin
  if RecordsetProps = nil then Exit;
  RecordsetProps.Obj.UseSQLEscapeSequences := (ASender as TGMCheckBox).Checked;
  Datachanged;
end;


{ --------------------------------- }
{ ---- TGMConnectionStrEditDlg ---- }
{ --------------------------------- }

constructor TGMConnectionStrEditDlg.Create(const AConnectionString, ATitle, ALargeText: TGMString; const AParent: TGMWndObj; const ABkgndColor: COLORREF; const ARefLifeTime: Boolean);
var clientArea: TObject; txt: TGMString; cnStorage: IGMConnectionStringStorage;
begin
  inherited Create(cNullRect, cSizeDlgWndStyle, 0, ATitle, AParent, nil, 0, ABkgndColor, ARefLifeTime);
  FSizeConstraints.MinSize := WndSizeFromClientSize(GMPoint(230, 300));
  //FLayoutBounds := GMCenteredWndRect(GMPoint(300, 500), AParent);
  //FLayoutBounds := GMCenteredWndRect(GMRectSize(GMLoadDlgRect(UserSettings, '\' + cPrsFolderWindow, cPrsFolderWindow, GMPoint(300, 500), 0)), AParent);
//FLayoutBounds := GMLoadDlgRect(UserSettings, GMAbsPath(cPrsMaskEditDlg), cPrsMaskEditDlg, GMPoint(300, 500), AParent);
  FLayoutBounds := GMCenteredWndRect(GMPoint(400, 500), AParent);

  OwnArea(TGMDlgHeaderArea.Create(self, cNullRect, cTopAligned, ALargeText, ATitle));

  clientArea := OwnArea(TGMUiArea.Create(Self, cNullRect, cClientAligned, ABkgndColor));

  cnStorage := TGMConnectionStringStorage.Create(AConnectionString);
  txt := GMNamesAndValuesAsString(cnStorage.Obj.Values, GMVarToConnectionStrLiteral, cNewLine, cCnStrValSep);

  FEditor := OwnArea(TGMFramedEdit.Create(-Int64(clientArea), GMRect(cCtlSpace, cCtlSpace, cCtlSpace, cCtlSpace), cClientAligned, txt, cVisibleTabstop or ES_MultiLine or WS_HSCROLL or WS_VSCROLL)) as TGMFramedEdit;

  //area :=
  OwnArea(TGMDlgBottomArea.Create(Self, cDlgBtnsOkCancel, dbkOk));
//OwnArea(TGMHintToolBtnArea.Create(area, GMRect(cCtlSpace, 0, cDlgBtnSize, cDlgBtnSize),
//         GMAreaAlign(ealAligned, ealCentered, ealFixed, ealCentered, True), OnBtnHelpClick, '', Ord(fmbHelp),
//         MainDlgBtnImg, RStrNameMaskHelp, RStrNameMaskHelpText));

  ActiveControl := FEditor;
end;

procedure TGMConnectionStrEditDlg.DoneDialog(const ASetData: Boolean);
var i: LongInt; line: TGMString; len: Word;
begin
//if WndStyle and cMinimizedOrMaximized = 0 then
//   GMStoreRect(UserSettings, GMAbsPath(cPrsMaskEditDlg), cPrsMaskEditDlg, LayoutBounds);

  if ASetData then
   begin
//  FConnectionString := '';
    for i:=0 to GMSendObjMessage(FEditor, EM_GETLINECOUNT) - 1 do
     begin
      len := GMSendObjMessage(FEditor, EM_LINELENGTH, GMSendObjMessage(FEditor, EM_LINEINDEX, i));
      SetLength(line, len + SizeOf(len));
      Inc(len); // <- allow to write terminating zero TGMChar
      Move(len, PGMChar(line)^, SizeOf(len));
      GMSendObjMessage(FEditor, EM_GETLINE, i, LPARAM(PGMChar(line)));
      FConnectionString := GMStringJoin(FConnectionString, cCnStrEntrySep, GMStrip(Copy(line, 1, len-1), cCnStrEntrySep));
     end;
   end;
end;

function TGMConnectionStrEditDlg.GetText: TGMString;
begin
  Result := FConnectionString;
end;


{ --------------------------------- }
{ ---- TGMShowConnectionStrDlg ---- }
{ --------------------------------- }

constructor TGMShowConnectionStrDlg.Create(const AConnectionString, ATitle,
  ALargeText: TGMString; const AParent: TGMWndObj;
  const ABkgndColor: COLORREF; const ARefLifeTime: Boolean);
var clientArea: TObject; txt: TGMString; // cnStorage: IGMConnectionStringStorage;
begin
  inherited Create(cNullRect, cSizeDlgWndStyle, 0, ATitle, AParent, nil, 0, ABkgndColor, ARefLifeTime);
  FSizeConstraints.MinSize := WndSizeFromClientSize(GMPoint(230, 300));
  //FLayoutBounds := GMCenteredWndRect(GMPoint(300, 500), AParent);
  //FLayoutBounds := GMCenteredWndRect(GMRectSize(GMLoadDlgRect(UserSettings, '\' + cPrsFolderWindow, cPrsFolderWindow, GMPoint(300, 500), 0)), AParent);
//FLayoutBounds := GMLoadDlgRect(UserSettings, GMAbsPath(cPrsMaskEditDlg), cPrsMaskEditDlg, GMPoint(300, 500), AParent);
  FLayoutBounds := GMCenteredWndRect(GMPoint(400, 500), AParent);

  OwnArea(TGMDlgHeaderArea.Create(self, cNullRect, cTopAligned, ALargeText, ATitle));

  clientArea := OwnArea(TGMUiArea.Create(Self, cNullRect, cClientAligned, ABkgndColor));

//cnStorage := TGMConnectionStringStorage.Create(AConnectionString);
//txt := GMNamesAndValuesAsString(cnStorage.Obj.Values, GMVarToConnectionStrLiteral, cNewLine, cCnStrValSep);

  FEditor := OwnArea(TGMFramedEdit.Create(-Int64(clientArea), GMRect(cCtlSpace, cCtlSpace, cCtlSpace, cCtlSpace), cClientAligned, txt, cVisibleTabstop or ES_READONLY or ES_MultiLine or WS_HSCROLL or WS_VSCROLL)) as TGMFramedEdit;

  //area :=
  OwnArea(TGMDlgBottomArea.Create(Self, [dbkClose], dbkClose));
//OwnArea(TGMHintToolBtnArea.Create(area, GMRect(cCtlSpace, 0, cDlgBtnSize, cDlgBtnSize),
//         GMAreaAlign(ealAligned, ealCentered, ealFixed, ealCentered, True), OnBtnHelpClick, '', Ord(fmbHelp),
//         MainDlgBtnImg, RStrNameMaskHelp, RStrNameMaskHelpText));

  ActiveControl := FEditor;
end;

//procedure TGMShowConnectionStrDlg.DoneDialog(const ASetData: Boolean);
//begin
//inherited;
//
//end;

function TGMShowConnectionStrDlg.GetText: TGMString;
begin
  Result := FEditor.Text;
end;


{ --------------------------- }
{ ---- TGMOdbcConnectDlg ---- }
{ --------------------------- }

constructor TGMOdbcConnectDlg.Create(const APosition: TRect; const AStyle,
  AExStyle: DWORD; const AText: TGMString; const AParent: TGMWndObj;
  const ADlgData: Pointer; const AMenu: HMENU;
  const ABkgndColor: COLORREF; const ARefLifeTime: Boolean);
//const cSpace = c2CtlSpace;
var DlgClient, Panel: TObject;
begin
  inherited Create(cNullRect, AStyle or cSizeDlgWndStyle, AExStyle,
                   RStrOdbcConnectDlgCaption, AParent, ADlgData, AMenu, ABkgndColor, ARefLifeTime);

  FSizeConstraints.MinSize := WndSizeFromClientSize(GMPoint(350, 450));
  FLayoutBounds := GMCenteredWndRect(FSizeConstraints.MinSize, AParent);

  OwnArea(TGMDlgHeaderArea.Create(Self, cNullRect, cTopAligned, RStrOdbc, RStrSelectDSN, cResOdbcDlgHeaderIcon));

  DlgClient := OwnArea(TGMUiArea.Create(Self, cNullRect, cClientAligned));

  Panel := OwnArea(TGMUiArea.Create(DlgClient, GMRect(cCtlSpace, cCtlSpace, cCtlSpace, cCtlSpace), cClientAligned, vLightGray));
  GMAssignRoundedAreaProperties(Panel);

  //GMSetObjMultiFrame(DlgClient, frsNone, frsLowered, cAllEdges, frkTile, cDlgFrmSpace); // frkTile  frkFlat

  FCnPropsUIArea := OwnArea(TGMOdbcConnectionPropUIArea.Create(Panel, GMRect(c2CtlSpace, c2CtlSpace, c2CtlSpace, 0), cClientAligned, OnDatachanged, vLightGray)) as TGMOdbcConnectionPropUIArea;
  //GMSetObjMultiFrame(FCnPropsUIArea, frsNone, frsLowered, cAllEdges, frkTile); // frkTile  frkFlat

  FBottomArea := OwnArea(TGMDlgBottomArea.Create(Self, cDlgBtnsOkCancel, dbkOk)) as TGMDlgBottomArea;
  FBtnODBCAdminDlg := OwnArea(TGMMinWidthBtn.Create(-Int64(FBottomArea), GMRect(0, 0, c2CtlSpace, cDlgBtnHeight), cDlgBtnAlign, RStrOdbcAdminDlg + cStr_More, OnOdbcAdminDlgClick, cVisibleTabstop)) as TGMButton;

  ActiveControl := FCnPropsUIArea.FComboBoxDSN;
  MessageBeep(MB_ICONQUESTION);
end;

procedure TGMOdbcConnectDlg.SetupControls;
begin
  GMEnableWindow(FBottomArea.Buttons[dbkOk], Length(GMStrip(FCnPropsUIArea.FComboBoxDSN.Text)) > 0);
end;

procedure TGMOdbcConnectDlg.OnDatachanged(const NewName: TGMString);
begin
  SetupControls;
end;

procedure TGMOdbcConnectDlg.GetDlgData;
var odbcCnProperties: IGMOdbcConnectProperties;
begin
  odbcCnProperties := TGMOdbcConnectProperties.CreateFromIntf(IUnknown(DlgData), nil, True);
  FCnPropsUIArea.ConnectProperties := odbcCnProperties;
end;

//function TGMOdbcConnectDlg.CanClose(const ASetData: Boolean): Boolean;
//begin
//if ASetData and (GMStrip(FComboBoxDSN.Text) = '') then raise EGMException.ObjError(RStrNoEmptyDSN, Self, 'CanClose');
//Result := inherited CanClose(ASetData);
//end;

procedure TGMOdbcConnectDlg.DoneDialog(const ASetData: Boolean);
begin
  if ASetData and (FCnPropsUIArea.ConnectProperties <> nil) then
     FCnPropsUIArea.ConnectProperties.Obj.AssignToIntf(IUnknown(DlgData));
end;

procedure TGMOdbcConnectDlg.OnOdbcAdminDlgClick(const Sender: TObject);
begin
  //
  // A simple call to SQLManageDataSources would do.
  // But the ODBC Admin Dialog on WinXP isn't safe against common control 6.0 manifest! - very stupid!
  // So we create the ODBC Admin Dialog via CreateProcess and wait for the process to terminate.
  //
  //if GMWinVersion <= wvWin2000 then
  if GMWinVersion <> wvWinXP then
   begin
    if SQLManageDataSources(Handle) then FCnPropsUIArea.FillupComboBoxDSN;
   end
  else
   begin
    GMEnableWindow(Self, False);
    try
     if GMExecProcess('OdbcAd32.exe', 0, True) = 0 then FCnPropsUIArea.FillupComboBoxDSN;
    finally
     GMEnableWindow(Self, True);
     SetForegroundWindow(Handle); // BringWindowToTop(Handle); SetActiveWindow(ActiveWindow);
    end;
  end;
end;


end.