{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

The Original Code is: JvToolEdit.PAS, released on 2002-07-04.

The Initial Developers of the Original Code are: Fedor Koshevnikov, Igor Pavluk and Serge Korolev
Copyright (c) 1997, 1998 Fedor Koshevnikov, Igor Pavluk and Serge Korolev
Copyright (c) 2001,2002 SGB Software
All Rights Reserved.

Contributers:
  Rob den Braasem [rbraasem att xs4all dott nl]
  Polaris Software
  rblaurindo
  Andreas Hausladen

You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net

Known Issues:
  (rb) Move button related functionality from TJvCustomComboEdit to TJvEditButton
-----------------------------------------------------------------------------}
// $Id: JvToolEdit.pas 11281 2007-05-09 16:44:52Z ahuser $

unit JvToolEdit;

{$I jvcl.inc}
{$I crossplatform.inc}

interface

uses
  {$IFDEF UNITVERSIONING}
  JclUnitVersioning,
  {$ENDIF UNITVERSIONING}
  {$IFDEF CLR}
  Types, WinUtils, System.Text, System.IO, System.Reflection,
  System.Runtime.InteropServices,
  {$ENDIF CLR}
  {$IFDEF MSWINDOWS}
  Windows, Messages, ShellAPI, ActiveX,
  {$ENDIF MSWINDOWS}
  {$IFDEF VCL}
  ShlObj,
  {$ENDIF VCL}
  {$IFDEF HAS_UNIT_VARIANTS}
  Variants,
  {$ENDIF HAS_UNIT_VARIANTS}
  SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Menus,
  Buttons, FileCtrl, Mask, ImgList, ActnList, ExtDlgs,
  {$IFDEF VisualCLX}
  Qt, QComboEdits, JvQExComboEdits, QWindows,
  {$ENDIF VisualCLX}
  JvVCL5Utils,
  JvExControls, JvSpeedButton, JvTypes, JvExMask, JvExForms, JvButton,
  JvDataSourceIntf;

const
  scAltDown = scAlt + VK_DOWN;
  DefEditBtnWidth = 21;

  CM_POPUPCLOSEUP = CM_BASE + $0300; // arbitrary value

{$IFDEF CLR}
type
  [ComImport, InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
  IUnknown = IInterface;
{$ENDIF CLR}

{$IFNDEF COMPILER7_UP}
// Autocomplete stuff for Delphi 5 and 6. (missing in ShlObj)
type
  IAutoComplete = interface(IUnknown)
    ['{00bb2762-6a77-11d0-a535-00c04fd7d062}']
    function Init(hwndEdit: THandle; punkACL: IUnknown;
      pwszRegKeyPath: LPCWSTR; pwszQuickComplete: LPCWSTR): HRESULT; stdcall;
    function Enable(fEnable: BOOL): HRESULT; stdcall;
  end;

const
  { IAutoComplete2 options }
  ACO_NONE = 0;
  ACO_AUTOSUGGEST = $1;
  ACO_AUTOAPPEND = $2;
  ACO_SEARCH = $4;
  ACO_FILTERPREFIXES = $8;
  ACO_USETAB = $10;
  ACO_UPDOWNKEYDROPSLIST = $20;
  ACO_RTLREADING = $40;

type
  IAutoComplete2 = interface(IAutoComplete)
    ['{EAC04BC0-3791-11d2-BB95-0060977B464C}']
    function SetOptions(dwFlag: DWORD): HRESULT; stdcall;
    function GetOptions(var dwFlag: DWORD): HRESULT; stdcall;
  end;

{$ENDIF !COMPILER7_UP}

// C++ Builder needs this HPPEMIT in order for the generated header to compile.
{$HPPEMIT 'typedef DelphiInterface<IEnumString> _di_IEnumString;'}

type
  TFileExt = type string;

  TCloseUpEvent = procedure(Sender: TObject; Accept: Boolean) of object;
  TPopupAlign = (epaRight, epaLeft);

  {$IFDEF VisualCLX}
  TJvPopupWindowBase = TJvExCustomForm;
  {$ENDIF VisualCLX}
  {$IFDEF VCL}
  TJvPopupWindowBase = TJvExCustomControl;
  {$ENDIF VCL}

  TJvPopupWindow = class(TJvPopupWindowBase)
  private
    FEditor: TWinControl;
    FCloseUp: TCloseUpEvent;
    {$IFDEF VCL}
    procedure WMMouseActivate(var Msg: TMessage); message WM_MOUSEACTIVATE;
    procedure WMActivate(var Msg: TWMActivate); message WM_ACTIVATE;
    {$ENDIF VCL}
  protected
    FActiveControl: TWinControl;
    FIsFocusable: Boolean;
    {$IFDEF VCL}
    procedure CreateParams(var Params: TCreateParams); override;
    {$ENDIF VCL}
    {$IFDEF VisualCLX}
    procedure SetParent(const Value: TWidgetControl); override;
    function WidgetFlags: Integer; override;
    {$ENDIF VisualCLX}
    function GetValue: Variant; virtual; abstract;
    procedure SetValue(const Value: Variant); virtual; abstract;
    procedure InvalidateEditor;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure CloseUp(Accept: Boolean); virtual;
    {$IFDEF CLR}
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    {$ENDIF CLR}
  public
    constructor Create(AOwner: TComponent); override;
    function GetPopupText: string; virtual;
    procedure Hide;
    procedure Show(Origin: TPoint); virtual; // Polaris
    { Determines the ctrl that receives the keyboard input if the dropdown
      window is showing, but the combo edit still has focus }
    property ActiveControl: TWinControl read FActiveControl;
    { Determines whether the popup window may be activated }
    property IsFocusable: Boolean read FIsFocusable;
    property OnCloseUp: TCloseUpEvent read FCloseUp write FCloseUp;
  end;

  TJvEditButton = class(TJvImageSpeedButton)
  private
    FNoAction: Boolean;
    {$IFDEF VCL}
    procedure WMContextMenu(var Msg: TWMContextMenu); message WM_CONTEXTMENU;
    {$ENDIF VCL}
    function GetGlyph: TBitmap;
    function GetNumGlyphs: TJvNumGlyphs;
    function GetUseGlyph: Boolean;
    procedure SetGlyph(const Value: TBitmap);
    procedure SetNumGlyphs(Value: TJvNumGlyphs);
  protected
    {$IFDEF JVCLThemesEnabled}
    FDrawThemedDropDownBtn: Boolean;
    {$ENDIF JVCLThemesEnabled}
    FStandard: Boolean; // Polaris
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure PaintImage(Canvas: TCanvas; ARect: TRect; const Offset: TPoint;
      AState: TJvButtonState; DrawMark: Boolean); override;
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure Click; override;

    property UseGlyph: Boolean read GetUseGlyph;// write FDrawGlyph;
    property Glyph: TBitmap read GetGlyph write SetGlyph;
    property NumGlyphs: TJvNumGlyphs read GetNumGlyphs write SetNumGlyphs;
  end;

  TGlyphKind = (gkCustom, gkDefault, gkDropDown, gkEllipsis);
  TJvImageKind = (ikCustom, ikDefault, ikDropDown, ikEllipsis);

  TJvCustomComboEdit = class;

  TJvCustomComboEditActionLink = class(TWinControlActionLink)
  protected
    function IsCaptionLinked: Boolean; override;
    function IsHintLinked: Boolean; override;
    function IsImageIndexLinked: Boolean; override;
    function IsOnExecuteLinked: Boolean; override;
    function IsShortCutLinked: Boolean; override;
    procedure SetHint(const Value: THintString); override;
    procedure SetImageIndex(Value: Integer); override;
    procedure SetOnExecute(Value: TNotifyEvent); override;
    procedure SetShortCut(Value: TShortCut); override;
  end;

  TJvCustomComboEditActionLinkClass = class of TJvCustomComboEditActionLink;

  {$IFDEF VCL}
  TJvAutoCompleteOption = (acoAutoSuggest, acoAutoAppend, acoSearch,
    acoFilterPrefixes, acoUseTab, acoUpDownKeyDropsList, acoRTLReading);
  TJvAutoCompleteOptions = set of TJvAutoCompleteOption;
  TJvAutoCompleteFileOption = (acfFileSystem, acfFileSysDirs, acfURLHistory, acfURLMRU);
  TJvAutoCompleteFileOptions = set of TJvAutoCompleteFileOption;
  {$ENDIF VCL}

  TJvCustomComboEditDataConnector = class(TJvFieldDataConnector)
  private
    FEdit: TJvCustomComboEdit;
  protected
    procedure RecordChanged; override;
    procedure UpdateData; override;
    property Control: TJvCustomComboEdit read FEdit;  
  public
    constructor Create(AEdit: TJvCustomComboEdit);
  end;

  {$IFDEF VCL}
  TJvCustomComboEditBase = TJvExCustomMaskEdit;
  {$ENDIF VCL}
  {$IFDEF VisualCLX}
  TJvCustomComboEditBase = TJvExCustomComboMaskEdit;
  {$ENDIF VisualCLX}

  TJvCustomComboEdit = class(TJvCustomComboEditBase)
  private
    FOnButtonClick: TNotifyEvent;
    FOnPopupShown: TNotifyEvent;
    FOnPopupHidden: TNotifyEvent;
    FClickKey: TShortCut;
    FReadOnly: Boolean;
    FDirectInput: Boolean;
    FAlwaysEnableButton: Boolean;
    FAlwaysShowPopup: Boolean;
    FPopupAlign: TPopupAlign;
    FGroupIndex: Integer; // RDB
    FDisabledColor: TColor; // RDB
    FDisabledTextColor: TColor; // RDB
    FOnKeyDown: TKeyEvent; // RDB
    FImages: TCustomImageList;
    FImageIndex: TImageIndex;
    FImageKind: TJvImageKind;
    FNumGlyphs: Integer;
    FStreamedButtonWidth: Integer;
    FStreamedFixedWidth: Boolean;
    FOnEnabledChanged: TNotifyEvent;
    { We hide the button by setting its width to 0, thus we have to store the
      width the button should have when shown again in FSavedButtonWidth: }
    FSavedButtonWidth: Integer;
    FDataConnector: TJvCustomComboEditDataConnector;
    {$IFDEF VCL}
    FAlignment: TAlignment;
    FAutoCompleteIntf: IAutoComplete;
    FAutoCompleteItems: TStrings;
    FAutoCompleteOptions: TJvAutoCompleteOptions;
    FTextChanged: Boolean;
    procedure SetAutoCompleteItems(Strings: TStrings);
    procedure SetAutoCompleteOptions(const Value: TJvAutoCompleteOptions);
    procedure SetAlignment(Value: TAlignment);
    function GetFlat: Boolean;
    procedure ReadCtl3D(Reader: TReader);
    procedure ReadParentCtl3D(Reader: TReader);
    procedure SetFlat(const Value: Boolean);
    function GetParentFlat: Boolean;
    procedure SetParentFlat(const Value: Boolean);
    function IsFlatStored: Boolean;
    {$ENDIF VCL}
    function BtnWidthStored: Boolean;
    function GetButtonFlat: Boolean;
    function GetButtonHint: string;
    function GetButtonWidth: Integer;
    function GetDirectInput: Boolean;
    function GetGlyph: TBitmap;
    function GetGlyphKind: TGlyphKind;
    function GetMinHeight: Integer;
    function GetNumGlyphs: TNumGlyphs;
    function GetPopupVisible: Boolean;
    function GetShowButton: Boolean;
    function GetTextHeight: Integer;
    function IsImageIndexStored: Boolean;
    function IsCustomGlyph: Boolean;
    procedure EditButtonClick(Sender: TObject);
    procedure ReadGlyphKind(Reader: TReader);
    procedure RecreateGlyph;
    procedure SetButtonFlat(const Value: Boolean);
    procedure SetButtonHint(const Value: string);
    procedure SetButtonWidth(Value: Integer);
    procedure SetGlyph(Value: TBitmap);
    procedure SetGlyphKind(Value: TGlyphKind);
    procedure SetImageIndex(const Value: TImageIndex);
    procedure SetImageKind(const Value: TJvImageKind);
    procedure SetImages(const Value: TCustomImageList);
    procedure SetNumGlyphs(const Value: TNumGlyphs);
    procedure SetShowButton(const Value: Boolean);
    procedure SetDataConnector(const Value: TJvCustomComboEditDataConnector);
    {$IFDEF COMPILER6_UP}
    procedure UpdateBtnBounds(var NewLeft, NewTop, NewWidth, NewHeight: Integer);
    {$ENDIF COMPILER6_UP}
    { (rb) renamed from UpdateEdit }
    procedure UpdateGroup; // RDB
    {$IFDEF VCL}
    procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY;
    procedure CMBiDiModeChanged(var Msg: TMessage); message CM_BIDIMODECHANGED;
    procedure CMCancelMode(var Msg: TCMCancelMode); message CM_CANCELMODE;
    procedure CMCtl3DChanged(var Msg: TMessage); message CM_CTL3DCHANGED;
    procedure CNCtlColor(var Msg: TMessage); message CN_CTLCOLOREDIT;
    procedure WMPaint(var Msg: TWMPaint); message WM_PAINT; // RDB
    procedure CMPopupCloseup(var Msg: TMessage); message CM_POPUPCLOSEUP;
    {$IFDEF JVCLThemesEnabled}
    procedure WMNCPaint(var Msg: TWMNCPaint); message WM_NCPAINT;
    procedure WMNCCalcSize(var Msg: TWMNCCalcSize); message WM_NCCALCSIZE;
    {$ENDIF JVCLThemesEnabled}
    procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
    {$ENDIF VCL}
  protected
    FButton: TJvEditButton; // Polaris
    FBtnControl: TWinControl;
    FPopupVisible: Boolean; // Polaris
    FFocused: Boolean; // Polaris
    FPopup: TWinControl;
    function CreateDataConnector: TJvCustomComboEditDataConnector; virtual;
    {$IFDEF COMPILER6_UP}
    {$IFDEF VCL}
    procedure CustomAlignPosition(Control: TControl; var NewLeft, NewTop, NewWidth,
      NewHeight: Integer; var AlignRect: TRect; AlignInfo: TAlignInfo); override;
    {$ENDIF VCL}
    {$IFDEF VisualCLX}
    procedure CustomAlignPosition(Control: TControl; var NewLeft,
      NewTop, NewWidth, NewHeight: Integer; var AlignRect: TRect); override;
    {$ENDIF VisualCLX}
    {$ENDIF COMPILER6_UP}
    {$IFDEF VCL}
    procedure WndProc(var Msg: TMessage); override;
    {$ENDIF VCL}
    procedure WMClear(var Msg: TMessage); message WM_CLEAR;
    procedure WMCut(var Msg: TMessage); message WM_CUT;
    procedure WMPaste(var Msg: TMessage); message WM_PASTE;
    procedure AdjustSize; override;
    procedure FocusKilled(NextWnd: THandle); override;
    procedure FocusSet(PrevWnd: THandle); override;
    procedure EnabledChanged; override;
    procedure FontChanged; override;
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure DoCtl3DChanged; virtual;
    function DoEraseBackground(Canvas: TCanvas; Param: Integer): Boolean; override;
    { Repositions the child controls; checkbox }
    procedure UpdateControls; virtual;
    { Updates the margins of the edit box }
    procedure UpdateMargins; dynamic;
    { Returns the margins of the edit box }
    procedure GetInternalMargins(var ALeft, ARight: Integer); virtual;
    procedure CreatePopup; virtual;
    procedure HidePopup; virtual; // (ahuser): WARNING: Do not release or free the component in HidePopup -> else AV in MouseUp
    procedure ShowPopup(Origin: TPoint); virtual;
    {$IFDEF VisualCLX}
    procedure DoFlatChanged; override;
    procedure Paint; override;
    {$ENDIF VisualCLX}
    function AcceptPopup(var Value: Variant): Boolean; virtual;
    function EditCanModify: Boolean; override;
    function GetActionLinkClass: TControlActionLinkClass; override;
    function GetPopupValue: Variant; virtual;
    function GetReadOnly: Boolean; virtual;
    function GetSettingCursor: Boolean;
    procedure AcceptValue(const Value: Variant); virtual;
    procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
    procedure AdjustHeight;
    procedure ButtonClick; dynamic;
    procedure Change; override;
    procedure CreateWnd; override;
    {$IFDEF VCL}
    procedure CreateParams(var Params: TCreateParams); override;
    procedure CreateAutoComplete; virtual;
    procedure DestroyWnd; override;
    procedure DestroyAutoComplete; virtual;
    procedure UpdateAutoComplete; virtual;
    function GetAutoCompleteSource: IEnumString; virtual;
    {$ENDIF VCL}
    procedure DefineProperties(Filer: TFiler); override;
    procedure DoChange; virtual; //virtual Polaris
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure Loaded; override;
    procedure LocalKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); // RDB
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure PopupChange; virtual;
    procedure PopupCloseUp(Sender: TObject; Accept: Boolean); virtual; //virtual Polaris
    procedure AsyncPopupCloseUp(Accept: Boolean); virtual;
    procedure PopupDropDown(DisableEdit: Boolean); virtual;
    procedure SetClipboardCommands(const Value: TJvClipboardCommands); override; // RDB
    procedure SetDirectInput(Value: Boolean); // Polaris
    procedure SetDisabledColor(const Value: TColor); virtual; // RDB
    procedure SetDisabledTextColor(const Value: TColor); virtual; // RDB
    procedure SetGroupIndex(const Value: Integer); // RDB
    procedure SetPopupValue(const Value: Variant); virtual;
    procedure SetReadOnly(Value: Boolean); virtual;
    procedure SetShowCaret; // Polaris
    procedure UpdatePopupVisible;
    {$IFDEF VCL}
    property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
    {$ENDIF VCL}
    {$IFDEF VisualCLX}
    property Alignment;
    {$ENDIF VisualCLX}
    property AlwaysEnableButton: Boolean read FAlwaysEnableButton write FAlwaysEnableButton default False;
    property AlwaysShowPopup: Boolean read FAlwaysShowPopup write FAlwaysShowPopup default False;
    {$IFDEF VCL}
    property AutoCompleteItems: TStrings read FAutoCompleteItems write SetAutoCompleteItems;
    property AutoCompleteOptions: TJvAutoCompleteOptions read FAutoCompleteOptions
      write SetAutoCompleteOptions default [];
    {$ENDIF VCL}
    property Button: TJvEditButton read FButton;
    property ButtonFlat: Boolean read GetButtonFlat write SetButtonFlat default False;
    property ButtonHint: string read GetButtonHint write SetButtonHint;
    property ButtonWidth: Integer read GetButtonWidth write SetButtonWidth stored BtnWidthStored;
    property ClickKey: TShortCut read FClickKey write FClickKey default scAltDown;
    property DirectInput: Boolean read GetDirectInput write SetDirectInput default True;
    property DisabledColor: TColor read FDisabledColor write SetDisabledColor default clWindow; // RDB
    property DisabledTextColor: TColor read FDisabledTextColor write SetDisabledTextColor default clGrayText; // RDB
    {$IFDEF VCL}
    property Flat: Boolean read GetFlat write SetFlat {$IFDEF VisualCLX} default False; {$ENDIF VisualCLX}
      {$IFDEF VCL} stored IsFlatStored; {$ENDIF VCL}
    property ParentFlat: Boolean read GetParentFlat write SetParentFlat default True;
    {$ENDIF VCL}
    property Glyph: TBitmap read GetGlyph write SetGlyph stored IsCustomGlyph;
    property GroupIndex: Integer read FGroupIndex write SetGroupIndex default -1;
    property ImageIndex: TImageIndex read FImageIndex write SetImageIndex stored IsImageIndexStored default -1;
    property ImageKind: TJvImageKind read FImageKind write SetImageKind default ikCustom;
    property Images: TCustomImageList read FImages write SetImages;
    property NumGlyphs: TNumGlyphs read GetNumGlyphs write SetNumGlyphs default 1;
    property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
    property OnKeyDown: TKeyEvent read FOnKeyDown write FOnKeyDown;
    property PopupAlign: TPopupAlign read FPopupAlign write FPopupAlign default epaRight;
    property PopupVisible: Boolean read GetPopupVisible;
    property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
    property SettingCursor: Boolean read GetSettingCursor;
    property ShowButton: Boolean read GetShowButton write SetShowButton default True;
    property OnEnabledChanged: TNotifyEvent read FOnEnabledChanged write FOnEnabledChanged;
    property OnPopupShown: TNotifyEvent read FOnPopupShown write FOnPopupShown;
    property OnPopupHidden: TNotifyEvent read FOnPopupHidden write FOnPopupHidden;

    property DataConnector: TJvCustomComboEditDataConnector read FDataConnector write SetDataConnector;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    class function DefaultImageIndex: TImageIndex; virtual;
    class function DefaultImages: TCustomImageList; virtual;
    procedure DoClick;
    procedure SelectAll;
    {$IFDEF VisualCLX}
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
    {$ENDIF VisualCLX}
    { Backwards compatibility; moved to public&published; eventually remove }
    property GlyphKind: TGlyphKind read GetGlyphKind write SetGlyphKind;
    {$IFDEF VCL}
    property Ctl3D;
    {$ENDIF VCL}
  end;

  TJvComboEdit = class(TJvCustomComboEdit)
  public
    property Button;
  published
    //Polaris
    property Action;
    property Align;
    property Alignment;
    property AlwaysEnableButton;
    property AlwaysShowPopup;
    property Anchors;
    property AutoSelect;
    property AutoSize;
    {$IFDEF VCL}
    property AutoCompleteItems;
    property AutoCompleteOptions;
    {$IFDEF COMPILER6_UP}
    property BevelEdges;
    property BevelInner;
    property BevelKind default bkNone;
    property BevelOuter;
    {$ENDIF COMPILER6_UP}
    property BiDiMode;
    property DragCursor;
    property DragKind;
    property Flat;
    property ImeMode;
    property ImeName;
    property OEMConvert;
    property ParentBiDiMode;
    property ParentFlat;
    property OnEndDock;
    property OnStartDock;
    {$ENDIF VCL}
    property BorderStyle;
    property ButtonFlat;
    property ButtonHint;
    property ButtonWidth;
    property CharCase;
    property ClickKey;
    property ClipboardCommands; // RDB
    property Color;
    property Constraints;
    property DirectInput;
    property DisabledColor; // RDB
    property DisabledTextColor; // RDB
    property DragMode;
    property EditMask;
    property Enabled;
    property Font;
    property Glyph;
    property HideSelection;
    property ImageIndex;
    property ImageKind;
    property Images;
    property MaxLength;
    property NumGlyphs;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property ShowButton;
    property TabOrder;
    property TabStop;
    property Text;
    property Visible;
    property OnButtonClick;
    property OnChange;
    property OnClick;
    property OnContextPopup;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown; // RDB
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnMouseMove;
    property OnMouseUp;
    property OnStartDrag;

    property DataConnector;
  end;

  { TJvFileDirEdit }
  { The common parent of TJvFilenameEdit and TJvDirectoryEdit      }
  { For internal use only; it's not intended to be used separately }

type
  TExecOpenDialogEvent = procedure(Sender: TObject; var AName: string; var AAction: Boolean) of object;

  TJvFileDirEdit = class(TJvCustomComboEdit)
  private
    FErrMode: Cardinal;
    FMultipleDirs: Boolean;
    FOnDropFiles: TNotifyEvent;
    FOnBeforeDialog: TExecOpenDialogEvent;
    FOnAfterDialog: TExecOpenDialogEvent;
    {$IFDEF VCL}
    FAcceptFiles: Boolean;
    FMRUList: IUnknown;
    FHistoryList: IUnknown;
    FFileSystemList: IUnknown;
    FAutoCompleteFileOptions: TJvAutoCompleteFileOptions;
    FAutoCompleteSourceIntf: IEnumString;
    procedure SetAutoCompleteFileOptions(const Value: TJvAutoCompleteFileOptions);
    procedure SetDragAccept(Value: Boolean);
    procedure SetAcceptFiles(Value: Boolean);
    procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES;
    {$IFDEF JVCLThemesEnabled}
    procedure CMSysColorChange(var Msg: TMessage); message CM_SYSCOLORCHANGE;
    {$ENDIF JVCLThemesEnabled}
    {$ENDIF VCL}
  protected
    {$IFDEF VCL}
    procedure CreateHandle; override;
    procedure DestroyWindowHandle; override;
    procedure DestroyAutoComplete; override;
    procedure UpdateAutoComplete; override;
    function GetAutoCompleteSource: IEnumString; override;
    {$ENDIF VCL}
    function GetLongName: string; virtual; abstract;
    function GetShortName: string; virtual; abstract;
    procedure DoAfterDialog(var FileName: string; var Action: Boolean); dynamic;
    procedure DoBeforeDialog(var FileName: string; var Action: Boolean); dynamic;
    procedure ReceptFileDir(const AFileName: string); virtual; abstract;
    procedure ClearFileList; virtual;
    procedure Change; override;
    procedure DisableSysErrors;
    procedure EnableSysErrors;
    {$IFDEF VCL}
    property AutoCompleteFileOptions: TJvAutoCompleteFileOptions read FAutoCompleteFileOptions write
      SetAutoCompleteFileOptions;
    property AutoCompleteOptions default [acoAutoSuggest];
    {$ENDIF VCL}
    property ImageKind default ikDefault;
    property MaxLength;
  public
    constructor Create(AOwner: TComponent); override;
    property LongName: string read GetLongName;
    property ShortName: string read GetShortName;
  published
    {$IFDEF VCL}
    property AcceptFiles: Boolean read FAcceptFiles write SetAcceptFiles default True;
    {$ENDIF VCL}
    property OnBeforeDialog: TExecOpenDialogEvent read FOnBeforeDialog write FOnBeforeDialog;
    property OnAfterDialog: TExecOpenDialogEvent read FOnAfterDialog write FOnAfterDialog;
    property OnDropFiles: TNotifyEvent read FOnDropFiles write FOnDropFiles;
    property OnButtonClick;
    property ClipboardCommands; // RDB
    property DisabledTextColor; // RDB
    property DisabledColor; // RDB
    property OEMConvert default True; // Mantis 3621
  end;

  TFileDialogKind = (dkOpen, dkSave, dkOpenPicture, dkSavePicture);

  TJvFilenameEdit = class(TJvFileDirEdit)
  private
    FDialog: TOpenDialog;
    FDialogKind: TFileDialogKind;
    FAddQuotes: Boolean;
    procedure CreateEditDialog;
    function GetFileName: TFileName;
    function GetDefaultExt: TFileExt;
    {$IFDEF VCL}
    function GetFileEditStyle: TFileEditStyle;
    {$ENDIF VCL}
    function GetFilter: string;
    function GetFilterIndex: Integer;
    function GetInitialDir: string;
    function GetHistoryList: TStrings;
    function GetOptions: TOpenOptions;
    function GetDialogTitle: string;
    function GetDialogFiles: TStrings;
    procedure SetDialogKind(Value: TFileDialogKind);
    procedure SetFileName(const Value: TFileName);
    procedure SetDefaultExt(Value: TFileExt);
    {$IFDEF VCL}
    procedure SetFileEditStyle(Value: TFileEditStyle);
    {$ENDIF VCL}
    procedure SetFilter(const Value: string);
    procedure SetFilterIndex(Value: Integer);
    procedure SetInitialDir(const Value: string);
    procedure SetHistoryList(Value: TStrings);
    procedure SetOptions(Value: TOpenOptions);
    procedure SetDialogTitle(const Value: string);
    function IsCustomTitle: Boolean;
    function IsCustomFilter: Boolean;
  protected
    procedure PopupDropDown(DisableEdit: Boolean); override;
    procedure ReceptFileDir(const AFileName: string); override;
    procedure ClearFileList; override;
    function GetLongName: string; override;
    function GetShortName: string; override;
  public
    constructor Create(AOwner: TComponent); override;
    class function DefaultImageIndex: TImageIndex; override;
    property Dialog: TOpenDialog read FDialog;
    property DialogFiles: TStrings read GetDialogFiles;
  published
    //Polaris
    property Action;
    property Align;
    property AutoSize;
    property AddQuotes: Boolean read FAddQuotes write FAddQuotes default True;
    property DialogKind: TFileDialogKind read FDialogKind write SetDialogKind
      default dkOpen;
    property DefaultExt: TFileExt read GetDefaultExt write SetDefaultExt;
    {$IFDEF VCL}
    property AutoCompleteOptions;
    property AutoCompleteFileOptions default [acfFileSystem];
    {$IFDEF COMPILER6_UP}
    property BevelEdges;
    property BevelInner;
    property BevelKind default bkNone;
    property BevelOuter;
    {$ENDIF COMPILER6_UP}
    property Flat;
    property ParentFlat;
    { (rb) Obsolete; added 'stored False', eventually remove }
    property FileEditStyle: TFileEditStyle read GetFileEditStyle write SetFileEditStyle stored False;
    {$ENDIF VCL}
    property FileName: TFileName read GetFileName write SetFileName stored False;
    property Filter: string read GetFilter write SetFilter stored IsCustomFilter;
    property FilterIndex: Integer read GetFilterIndex write SetFilterIndex default 1;
    property InitialDir: string read GetInitialDir write SetInitialDir;
    { (rb) Obsolete; added 'stored False', eventually remove }
    property HistoryList: TStrings read GetHistoryList write SetHistoryList stored False;
    property DialogOptions: TOpenOptions read GetOptions write SetOptions default [ofHideReadOnly];
    property DialogTitle: string read GetDialogTitle write SetDialogTitle stored IsCustomTitle;
    property AutoSelect;
    property ButtonHint;
    property ButtonFlat;
    property BorderStyle;
    property CharCase;
    property ClickKey;
    property Color;
    property DirectInput;
    {$IFDEF VCL}
    property DragCursor;
    property BiDiMode;
    property DragKind;
    property ParentBiDiMode;
    property ImeMode;
    property ImeName;
    property OnEndDock;
    property OnStartDock;
    {$ENDIF VCL}
    property DragMode;
    property EditMask;
    property Enabled;
    property Font;
    property Glyph;
    property GroupIndex;
    property ImageIndex;
    property Images;
    property ImageKind;
    property NumGlyphs;
    property ButtonWidth;
    property HideSelection;
    property Anchors;
    property Constraints;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property ShowButton;
    property TabOrder;
    property TabStop;
    property Text;
    property Visible;
    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnMouseMove;
    property OnMouseUp;
    property OnStartDrag;
    property OnContextPopup;
  end;

  TDirDialogKind = (dkVCL, dkWin32);

  TJvDirectoryEdit = class(TJvFileDirEdit)
  private
    {$IFDEF VCL}
    FOptions: TSelectDirOpts;
    {$ENDIF VCL}
    FInitialDir: string;
    FDialogText: string;
    FDialogKind: TDirDialogKind;
  protected
    FMultipleDirs: Boolean; // Polaris (???)
    procedure PopupDropDown(DisableEdit: Boolean); override;
    procedure ReceptFileDir(const AFileName: string); override;
    function GetLongName: string; override;
    function GetShortName: string; override;
  public
    constructor Create(AOwner: TComponent); override;
    class function DefaultImageIndex: TImageIndex; override;
  published
    //Polaris
    property Action;
    property Align;
    property AutoSize;
    property DialogKind: TDirDialogKind read FDialogKind write FDialogKind default dkVCL;
    property DialogText: string read FDialogText write FDialogText;
    {$IFDEF VCL}
    property AutoCompleteOptions;
    property AutoCompleteFileOptions default [acfFileSystem, acfFileSysDirs];
    {$IFDEF COMPILER6_UP}
    property BevelEdges;
    property BevelInner;
    property BevelKind default bkNone;
    property BevelOuter;
    {$ENDIF COMPILER6_UP}
    property Flat;
    property ParentFlat;
    property DialogOptions: TSelectDirOpts read FOptions write FOptions default [sdAllowCreate];
    {$ENDIF VCL}
    property InitialDir: string read FInitialDir write FInitialDir;
    property MultipleDirs: Boolean read FMultipleDirs write FMultipleDirs default False;
    property AutoSelect;
    property ButtonHint;
    property ButtonFlat;
    property BorderStyle;
    property CharCase;
    property ClickKey;
    property Color;
    property DirectInput;
    {$IFDEF VCL}
    property DragCursor;
    property BiDiMode;
    property ParentBiDiMode;
    property ImeMode;
    property ImeName;
    property DragKind;
    property OnEndDock;
    property OnStartDock;
    {$ENDIF VCL}
    property DragMode;
    property EditMask;
    property Enabled;
    property Font;
    property Glyph;
    property GroupIndex;
    property ImageIndex;
    property Images;
    property ImageKind;
    property NumGlyphs;
    property ButtonWidth;
    property HideSelection;
    property Anchors;
    property Constraints;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property ShowButton;
    property TabOrder;
    property TabStop;
    property Text;
    property Visible;
    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnMouseMove;
    property OnMouseUp;
    property OnStartDrag;
    property OnContextPopup;
  end;

  TCalendarStyle = (csPopup, csDialog);
  TYearDigits = (dyDefault, dyFour, dyTwo);

const
  {$IFDEF DEFAULT_POPUP_CALENDAR}
  dcsDefault = csPopup;
  {$ELSE}
  dcsDefault = csDialog;
  {$ENDIF DEFAULT_POPUP_CALENDAR}

type
  TExecDateDialog = procedure(Sender: TObject; var ADate: TDateTime;
    var Action: Boolean) of object;
  TJvInvalidDateEvent = procedure(Sender: TObject; const DateString: string;
    var NewDate: TDateTime; var Accept: Boolean) of object;
  TPreferredDateFormat = (pdLocale, pdLocaleOnly, pdCustom, pdCustomOnly);

  TJvCustomDateEditDataConnector = class(TJvCustomComboEditDataConnector)
  private
    FDefaultDate: TDateTime;
    FDefaultDateIsNow: Boolean;
    procedure SetDefaultDateIsNow(const Value: Boolean);
    function IsDefaultDateStored: Boolean;
  protected
    procedure RecordChanged; override;
    procedure UpdateData; override;
  public
    procedure Assign(Source: TPersistent); override;
  published
    property DefaultDate: TDateTime read FDefaultDate write FDefaultDate stored IsDefaultDateStored;
    property DefaultDateIsNow: Boolean read FDefaultDateIsNow write SetDefaultDateIsNow default False; 
  end;

  TJvCustomDateEdit = class(TJvCustomComboEdit)
  private
    FMinDate: TDateTime; // Polaris
    FMaxDate: TDateTime; // Polaris
    FTitle: string;
    FOnAcceptDate: TExecDateDialog;
    FOnInvalidDate: TJvInvalidDateEvent;
    FDefaultToday: Boolean;
    FPopupColor: TColor;
    FCheckOnExit: Boolean;
    FBlanksChar: Char;
    FCalendarHints: TStringList;
    FStartOfWeek: TDayOfWeekName;
    FWeekends: TDaysOfWeek;
    FWeekendColor: TColor;
    FCustomDateFormat: string;
    FYearDigits: TYearDigits;
    FDateFormatPreferred: TPreferredDateFormat;
    FDateFormat: string[10];
    FDateFormat2: string[10];
    FFormatting: Boolean;
    // Polaris
    procedure SetMinDate(Value: TDateTime);
    procedure SetMaxDate(Value: TDateTime);
    // Polaris
    function GetDate: TDateTime;
    procedure SetCustomDateFormat(const Value: string);
    procedure SetDateFormatPreferred(Value: TPreferredDateFormat);
    function IsDateFormatStored: Boolean;
    function IsDateFormatPreferredStored: Boolean;
    procedure SetYearDigits(Value: TYearDigits);
    function GetPopupColor: TColor;
    procedure SetPopupColor(Value: TColor);
    function GetDialogTitle: string;
    procedure SetDialogTitle(const Value: string);
    function IsCustomTitle: Boolean;
    function IsDateStored: Boolean;
    function GetCalendarStyle: TCalendarStyle;
    procedure SetCalendarStyle(Value: TCalendarStyle);
    function GetCalendarHints: TStrings;
    procedure SetCalendarHints(Value: TStrings);
    procedure CalendarHintsChanged(Sender: TObject);
    procedure SetWeekendColor(Value: TColor);
    procedure SetWeekends(Value: TDaysOfWeek);
    procedure SetStartOfWeek(Value: TDayOfWeekName);
    procedure SetBlanksChar(Value: Char);
    function TextStored: Boolean;
    // Polaris
    function StoreMinDate: Boolean;
    function StoreMaxDate: Boolean;
    // Polaris
    function FourDigitYear: Boolean;
    {$IFDEF VCL}
    procedure WMContextMenu(var Msg: TWMContextMenu); message WM_CONTEXTMENU;
    {$ENDIF VCL}
  protected
    // Polaris
    FDateAutoBetween: Boolean;
    procedure SetDate(Value: TDateTime); virtual;
    function DoInvalidDate(const DateString: string; var ANewDate: TDateTime): Boolean; virtual;
    procedure SetDateAutoBetween(Value: Boolean); virtual;
    procedure TestDateBetween(var Value: TDateTime); virtual;
    // Polaris
    procedure DoExit; override;
    procedure Change; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    {$IFDEF VCL}
    procedure CreateWindowHandle(const Params: TCreateParams); override;
    {$ENDIF VCL}
    {$IFDEF VisualCLX}
    procedure CreateWidget; override;
    {$ENDIF VisualCLX}
    function AcceptPopup(var Value: Variant): Boolean; override;
    procedure AcceptValue(const Value: Variant); override;
    procedure SetPopupValue(const Value: Variant); override;
    function GetDateFormat: string;
    procedure ApplyDate(Value: TDateTime); virtual;
    procedure UpdateFormat;
    procedure UpdatePopup;
    procedure PopupDropDown(DisableEdit: Boolean); override;
    procedure SetParent(AParent: TWinControl); override;
    function GetDefaultDateFormat: string; virtual;
    function GetDefaultDateFormatPreferred: TPreferredDateFormat; virtual;
    function CreateDataConnector: TJvCustomComboEditDataConnector; override;

    property BlanksChar: Char read FBlanksChar write SetBlanksChar default ' ';
    property CalendarHints: TStrings read GetCalendarHints write SetCalendarHints;
    property CheckOnExit: Boolean read FCheckOnExit write FCheckOnExit default False;
    property DefaultToday: Boolean read FDefaultToday write FDefaultToday default False;
    property DialogTitle: string read GetDialogTitle write SetDialogTitle stored IsCustomTitle;
    property EditMask stored False;
    property Formatting: Boolean read FFormatting;
    property ImageKind default ikDefault;
    property PopupColor: TColor read GetPopupColor write SetPopupColor default clMenu;
    property CalendarStyle: TCalendarStyle read GetCalendarStyle
      write SetCalendarStyle default dcsDefault;
    property StartOfWeek: TDayOfWeekName read FStartOfWeek write SetStartOfWeek default Mon;
    property Weekends: TDaysOfWeek read FWeekends write SetWeekends default [Sun];
    property WeekendColor: TColor read FWeekendColor write SetWeekendColor default clRed;
    property DateFormat: string read FCustomDateFormat write SetCustomDateFormat stored IsDateFormatStored;
    property DateFormatPreferred: TPreferredDateFormat read FDateFormatPreferred
      write SetDateFormatPreferred stored IsDateFormatPreferredStored;
    property YearDigits: TYearDigits read FYearDigits write SetYearDigits default dyDefault;
    property OnAcceptDate: TExecDateDialog read FOnAcceptDate write FOnAcceptDate;
    property OnInvalidDate: TJvInvalidDateEvent read FOnInvalidDate write FOnInvalidDate;
    property MaxLength stored False;
    { Text is already stored via Date property }
    property Text stored False;
  public
    // Polaris
    property DateAutoBetween: Boolean read FDateAutoBetween write SetDateAutoBetween default True;
    property MinDate: TDateTime read FMinDate write SetMinDate stored StoreMinDate;
    property MaxDate: TDateTime read FMaxDate write SetMaxDate stored StoreMaxDate;
    procedure ValidateEdit; override;
    // Polaris
    constructor Create(AOwner: TComponent); override;
    class function DefaultImageIndex: TImageIndex; override;
    destructor Destroy; override;
    procedure CheckValidDate; virtual;
    function GetDateMask: string;
    procedure UpdateMask; virtual;
    property Date: TDateTime read GetDate write SetDate stored IsDateStored;
    property PopupVisible;
  end;

  TJvDateEdit = class(TJvCustomDateEdit)
    // Polaris
  protected
    procedure SetDate(Value: TDateTime); override;
    // Polaris
  public
    constructor Create(AOwner: TComponent); override;
    property EditMask;
  published
    property Date;
    property DateFormat;
    property DateFormatPreferred;
    property DateAutoBetween; // Polaris
    property MinDate; // Polaris
    property MaxDate; // Polaris
    property Align; // Polaris
    property Action;
    property AutoSelect;
    property AutoSize;
    property BlanksChar;
    property BorderStyle;
    property ButtonHint;
    property ButtonFlat;
    property CalendarHints;
    property CheckOnExit;
    property ClickKey;
    property Color;
    property DefaultToday;
    property DialogTitle;
    property DirectInput;
    {$IFDEF VCL}
    property DragCursor;
    {$IFDEF COMPILER6_UP}
    property BevelEdges;
    property BevelInner;
    property BevelKind default bkNone;
    property BevelOuter;
    {$ENDIF COMPILER6_UP}
    property BiDiMode;
    property DragKind;
    property Flat;
    property ParentBiDiMode;
    property ParentFlat;
    property ImeMode;
    property ImeName;
    property OnEndDock;
    property OnStartDock;
    {$ENDIF VCL}
    property DragMode;
    property Enabled;
    property Font;
    property Glyph;
    property GroupIndex;
    property ImageIndex;
    property Images;
    property ImageKind;
    property NumGlyphs;
    property ButtonWidth;
    property HideSelection;
    property Anchors;
    property Constraints;
    property MaxLength;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupAlign;
    property PopupColor;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property ShowButton;
    property CalendarStyle;
    property StartOfWeek;
    property Weekends;
    property WeekendColor;
    property YearDigits;
    property TabOrder;
    property TabStop;
    property Text;
    property Visible;
    property OnAcceptDate;
    property OnInvalidDate;
    property OnButtonClick;
    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnMouseMove;
    property OnMouseUp;
    property OnStartDrag;
    property OnContextPopup;
    property ClipboardCommands; // RDB
    property DisabledTextColor; // RDB
    property DisabledColor; // RDB
    property OnKeyDown; // RDB

    property DataConnector;
  end;

  EComboEditError = class(EJVCLException);

{ Utility routines }

procedure DateFormatChanged;

function EditorTextMargins(Editor: TCustomEdit): TPoint;
{$IFDEF VCL}
function PaintComboEdit(Editor: TJvCustomComboEdit; const AText: string;
  AAlignment: TAlignment; StandardPaint: Boolean;
  var ACanvas: TControlCanvas; var Msg: TWMPaint): Boolean;
function PaintEdit(Editor: TCustomEdit; const AText: string;
  AAlignment: TAlignment; PopupVisible: Boolean;
  DisabledTextColor: TColor; StandardPaint: Boolean;
  var ACanvas: TControlCanvas; var Msg: TWMPaint): Boolean;
{$ENDIF VCL}
{$IFDEF VisualCLX}
function PaintComboEdit(Editor: TJvCustomComboEdit; const AText: string;
  AAlignment: TAlignment; StandardPaint: Boolean; Flat: Boolean; ACanvas: TCanvas): Boolean;
{ PaintEdit (CLX) needs an implemented EM_GETRECT message handler or a
  TCustomComboEdit/TCustomComboMask class. If no EM_GETTEXT handler exists or
  the class is derived from another class, it uses the ClientRect of the edit
  control. }
function PaintEdit(Editor: TCustomEdit; const AText: WideString;
  AAlignment: TAlignment; PopupVisible: Boolean; 
  DisabledTextColor: TColor; StandardPaint: Boolean; Flat: Boolean;
  ACanvas: TCanvas): Boolean;
{$ENDIF VisualCLX}

{$IFDEF VisualCLX}
const
  OBM_COMBO = 1;
{$ENDIF VisualCLX}

function LoadDefaultBitmap(Bmp: TBitmap; Item: Integer): Boolean;

function IsInWordArray(Value: Word; const A: array of Word): Boolean;

{$IFDEF UNITVERSIONING}
const
  UnitVersioning: TUnitVersionInfo = (
    RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvToolEdit.pas $';
    Revision: '$Revision: 11281 $';
    Date: '$Date: 2007-05-09 18:44:52 +0200 (mer., 09 mai 2007) $';
    LogPath: 'JVCL\run'
  );
{$ENDIF UNITVERSIONING}

implementation

uses
  {$IFDEF HAS_UNIT_RTLCONSTS}
  RTLConsts,
  {$ENDIF HAS_UNIT_RTLCONSTS}
  Math, Consts,
  {$IFDEF COMPILER6_UP}
  MaskUtils,
  {$ENDIF COMPILER6_UP}
  {$IFDEF VCL}
  MultiMon,
  {$IFNDEF CLR}
  JvBrowseFolder,
  {$ENDIF !CLR}
  {$ENDIF VCL}
  JvPickDate, JvJCLUtils, JvJVCLUtils,
  JvThemes, JvResources, JvConsts;

{$R JvToolEdit.res}

type
  {$IFDEF CLR}
  TCustomEditAccessProtected = class(TCustomEdit)
  public
    property Ctl3D;
    property BorderStyle;
  end;
  {$ELSE}

  {$HINTS OFF}
  TCustomMaskEditAccessPrivate = class(TCustomEdit)
  private
    // Do not remove these fields, although they are not used.
    {$IFDEF COMPILER6_UP}
    FEditMask: TEditMask;
    {$ELSE}
    FEditMask: string;
    {$ENDIF COMPILER6_UP}
    FMaskBlank: Char;
    FMaxChars: Integer;
    FMaskSave: Boolean;
    FMaskState: TMaskedState;
    FCaretPos: Integer;
    FBtnDownX: Integer;
    FOldValue: string;
    FSettingCursor: Boolean;
  end;
  {$HINTS ON}

  TCustomEditAccessProtected = class(TCustomEdit);
  {$ENDIF CLR}
  TCustomFormAccessProtected = class(TCustomForm);
  TWinControlAccessProtected = class(TWinControl);

const
  sDirBmp = 'JvDirectoryEditGLYPH';    { Directory editor button glyph }
  sFileBmp = 'JvFilenameEditGLYPH';    { Filename editor button glyph }
  sDateBmp = 'JvCustomDateEditGLYPH';  { Date editor button glyph }

  {$IFDEF JVCLThemesEnabled}
  // (rb) should/can these be put in a separate resource file?
  sDirXPBmp = 'JvDirectoryEditXPGLYPH';
  sFileXPBmp = 'JvFilenameEditXPGLYPH';
  {$ENDIF JVCLThemesEnabled}

{$IFDEF VCL}

const
  ACLO_NONE            = 0;   // don't enumerate anything
  ACLO_CURRENTDIR      = 1;   // enumerate current directory
  ACLO_MYCOMPUTER      = 2;   // enumerate MyComputer
  ACLO_DESKTOP         = 4;   // enumerate Desktop Folder
  ACLO_FAVORITES       = 8;   // enumerate Favorites Folder
  ACLO_FILESYSONLY     = 16;  // enumerate only the file system
  ACLO_FILESYSDIRS     = 32;  // enumerate only the file system dirs, UNC shares, and UNC servers.

  //IID_IAutoCompList: TGUID = (D1:$00BB2760; D2:$6A77; D3:$11D0; D4:($A5, $35, $00, $C0, $4F, $D7, $D0, $62));
  //IID_IObjMgr: TGUID = (D1:$00BB2761; D2:$6A77; D3:$11D0; D4:($A5, $35, $00, $C0, $4F, $D7, $D0, $62));
  //IID_IACList: TGUID = (D1:$77A130B0; D2:$94FD; D3:$11D0; D4:($A5, $44, $00, $C0, $4F, $D7, $d0, $62));
  //IID_IACList2: TGUID = (D1:$470141a0; D2:$5186; D3:$11d2; D4:($bb, $b6, $00, $60, $97, $7b, $46, $4c));
  //IID_ICurrentWorkingDirectory: TGUID = (D1:$91956d21; D2:$9276; D3:$11d1; D4:($92, $1a, $00, $60, $97, $df, $5b, $d4));

  {$IFDEF CLR}
  CLSID_AutoComplete = '{00BB2763-6A77-11D0-A535-00C04FD7D062}';
  CLSID_ACLMulti     = '{00BB2765-6A77-11D0-A535-00C04FD7D062}';
  CLSID_ACLHistory   = '{00BB2764-6A77-11D0-A535-00C04FD7D062}';
  CLSID_ACLMRU       = '{6756A641-DE71-11D0-831B-00AA005B4383}';
  CLSID_ACListISF    = '{03C036F1-A186-11D0-824A-00AA005B4383}';
  {$ELSE}
  CLSID_AutoComplete: TGUID = (D1:$00BB2763; D2:$6A77; D3:$11D0; D4:($A5, $35, $00, $C0, $4F, $D7, $D0, $62));
  CLSID_ACLHistory: TGUID = (D1:$00BB2764; D2:$6A77; D3:$11D0; D4:($A5, $35, $00, $C0, $4F, $D7, $D0, $62));
  CLSID_ACListISF: TGUID = (D1:$03C036F1; D2:$A186; D3:$11D0; D4:($82, $4A, $00, $AA, $00, $5B, $43, $83));
  CLSID_ACLMRU: TGUID = (D1:$6756a641; D2:$de71; D3:$11d0; D4:($83, $1b, $0, $aa, $0, $5b, $43, $83));
  CLSID_ACLMulti: TGUID = (D1:$00BB2765; D2:$6A77; D3:$11D0; D4:($A5, $35, $00, $C0, $4F, $D7, $D0, $62));
  {$ENDIF CLR}

  //#if (_WIN32_IE >= 0x0600)
  //CLSID_ACLCustomMRU: TGUID = (D1:$6935db93; D2:$21e8; D3:$4ccc; D4:($be, $b9, $9f, $e3, $c7, $7a, $29, $7a));
  //#endif

type
{$IFDEF CLR}
  TAutoCompleteSource = class(TInterfacedObject, IEnumString)
  private
    FComboEdit: TJvCustomComboEdit;
    FCurrentIndex: Integer;
  protected
    { IEnumString }
    function Next(celt: Longint; rgelt: array of string; out pceltFetched: Longint): HResult;
    function Skip(celt: Longint): HResult;
    function Reset: HResult;
    function Clone(out enm: IEnumString): HResult;
  public
    constructor Create(AComboEdit: TJvCustomComboEdit; const StartIndex: Integer); virtual;
  end;
{$ELSE}
  TAutoCompleteSource = class(TInterfacedObject, IEnumString)
  private
    FComboEdit: TJvCustomComboEdit;
    FCurrentIndex: Integer;
  protected
    { IEnumString }
    function Next(celt: Longint; out elt; pceltFetched: PLongint): HRESULT; stdcall;
    function Skip(celt: Longint): HRESULT; stdcall;
    function Reset: HRESULT; stdcall;
    function Clone(out enm: IEnumString): HRESULT; stdcall;
  public
    constructor Create(AComboEdit: TJvCustomComboEdit; const StartIndex: Integer); virtual;
  end;
{$ENDIF CLR}

  {$IFDEF CLR}
  [ComImport, InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
  {$ENDIF CLR}
  IACList = interface(IUnknown)
    ['{77A130B0-94FD-11D0-A544-00C04FD7d062}']
    {$IFDEF CLR}[PreserveSig]{$ENDIF CLR}
    function Expand(pszExpand: string): HRESULT; {$IFNDEF CLR}stdcall;{$ENDIF}
  end;

  {$IFDEF CLR}
  [ComImport, InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
  {$ENDIF CLR}
  IACList2 = interface(IACList)
    ['{470141a0-5186-11d2-bbb6-0060977b464c}']
    {$IFDEF CLR}[PreserveSig]{$ENDIF CLR}
    function SetOptions(dwFlag: DWORD): HRESULT; {$IFNDEF CLR}stdcall;{$ENDIF}
    {$IFDEF CLR}[PreserveSig]{$ENDIF CLR}
    function GetOptions(var pdwFlag: DWORD): HRESULT; {$IFNDEF CLR}stdcall;{$ENDIF}
  end;

  {$IFDEF CLR}
  [ComImport, InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
  {$ENDIF CLR}
  IObjMgr = interface(IUnknown)
    ['{00BB2761-6A77-11D0-a535-00c04fd7d062}']
    {$IFDEF CLR}[PreserveSig]{$ENDIF CLR}
    function Append(punk: IUnknown): HRESULT; {$IFNDEF CLR}stdcall;{$ENDIF}
    {$IFDEF CLR}[PreserveSig]{$ENDIF CLR}
    function Remove(punk: IUnknown): HRESULT; {$IFNDEF CLR}stdcall;{$ENDIF}
  end;

type
  { TDateHook is used to only have 1 hook per application for monitoring
    date changes;

    We can't use WM_WININICHANGE or CM_WININICHANGE in the controls
    itself, because it comes too early. (The Application object does the
    changing on receiving WM_WININICHANGE; The Application object receives it
    later than the forms, controls etc.
  }

  TDateHook = class(TObject)
  private
    FCount: Integer;
    FHooked: Boolean;
    FWinIniChangeReceived: Boolean;
  protected
    function FormatSettingsChange(var Msg: TMessage): Boolean;
    procedure Hook;
    procedure UnHook;
  public
    procedure Add;
    procedure Delete;
  end;

var
  GDateHook: TDateHook = nil;

{$ENDIF VCL}

var
  GDateImageIndex: TImageIndex = -1;
  GDefaultComboEditImagesList: TImageList = nil;
  GDirImageIndex: TImageIndex = -1;
  GFileImageIndex: TImageIndex = -1;
  {$IFDEF JVCLThemesEnabled}
  GDirImageIndexXP: TImageIndex = -1;
  GFileImageIndexXP: TImageIndex = -1;
  {$ENDIF JVCLThemesEnabled}

//=== Local procedures =======================================================

{$IFDEF VCL}

function DateHook: TDateHook;
begin
  if GDateHook = nil then
    GDateHook := TDateHook.Create;
  Result := GDateHook;
end;

{$ENDIF VCL}

function ClipFilename(const FileName: string; const Clip: Boolean): string;
var
  Params: string;
begin
  if FileExists(FileName) then
    Result := FileName
  else
  if DirectoryExists(FileName) then
    Result := IncludeTrailingPathDelimiter(FileName)
  else
  if Clip then
    SplitCommandLine(FileName, Result, Params)
  else
    Result := FileName;
end;

function ExtFilename(const FileName: string): string;
begin
  if (Pos(' ', FileName) > 0) and (FileName[1] <> '"') then
    Result := Format('"%s"', [FileName])
  else
    Result := FileName;
end;

function NvlDate(DateValue, DefaultValue: TDateTime): TDateTime;
begin
  if DateValue = NullDate then
    Result := DefaultValue
  else
    Result := DateValue;
end;

{$IFDEF VisualCLX}

procedure DrawSelectedText(Canvas: TCanvas; const R: TRect; X, Y: Integer;
  const Text: WideString; SelStart, SelLength: Integer;
  HighlightColor, HighlightTextColor: TColor);
var
  W, H, Width: Integer;
  S: WideString;
  SelectionRect: TRect;
  Brush: TBrushRecall;
  PenMode: TPenMode;
  FontColor: TColor;
begin
  W := R.Right - R.Left;
  H := R.Bottom - R.Top;
  if (W <= 0) or (H <= 0) then
    Exit;

  S := Copy(Text, 1, SelStart);
  if S <> '' then
  begin
    Canvas.TextRect(R, X, Y, S);
    Inc(X, Canvas.TextWidth(S));
  end;

  S := Copy(Text, SelStart + 1, SelLength);
  if S <> '' then
  begin
    Width := Canvas.TextWidth(S);
    Brush := TBrushRecall.Create(Canvas.Brush);
    PenMode := Canvas.Pen.Mode;
    try
      SelectionRect := Rect(Max(X, R.Left), R.Top,
        Min(X + Width, R.Right), R.Bottom);
      Canvas.Pen.Mode := pmCopy;
      Canvas.Brush.Color := HighlightColor;
      Canvas.FillRect(SelectionRect);
      FontColor := Canvas.Font.Color;
      Canvas.Font.Color := HighlightTextColor;
      Canvas.TextRect(R, X, Y, S);
      Canvas.Font.Color := FontColor;
    finally
      Canvas.Pen.Mode := PenMode;
      Brush.Free;
    end;
    Inc(X, Width);
  end;

  S := Copy(Text, SelStart + SelLength + 1, MaxInt);
  if S <> '' then
    Canvas.TextRect(R, X, Y, S);
end;

{$ENDIF VisualCLX}

function ParentFormVisible(AControl: TControl): Boolean;
var
  Form: TCustomForm;
begin
  Form := GetParentForm(AControl);
  Result := Assigned(Form) and Form.Visible;
end;

//=== Global procedures ======================================================

procedure DateFormatChanged;
var
  I: Integer;

  procedure IterateControls(AControl: TWinControl);
  var
    I: Integer;
  begin
    with AControl do
      for I := 0 to ControlCount - 1 do
      begin
        if Controls[I] is TJvCustomDateEdit then
          TJvCustomDateEdit(Controls[I]).UpdateMask
        else
        if Controls[I] is TWinControl then
          IterateControls(TWinControl(Controls[I]));
      end;
  end;

begin
  if Screen <> nil then
    for I := 0 to Screen.FormCount - 1 do
      IterateControls(Screen.Forms[I]);
end;

{$IFDEF VisualCLX}
function EditorTextMargins(Editor: TCustomEdit): TPoint;
var
  I: Integer;
  ed: TCustomEditAccessProtected;
begin
  ed := TCustomEditAccessProtected(Editor);
  if ed.BorderStyle = bsNone then
    I := 0
  else
  if Supports(Editor, IComboEditHelper) then
  begin
    if (Editor as IComboEditHelper).GetFlat then
      I := 1
    else
      I := 2;
  end
  else
    I := 2;
  {if GetWindowLong(ed.Handle, GWL_STYLE) and ES_MULTILINE = 0 then
    Result.X := (SendMessage(ed.Handle, EM_GETMARGINS, 0, 0) and $0000FFFF) + I
  else}
    Result.X := I;
  Result.Y := I;
end;
{$ENDIF VisualCLX}

{$IFDEF VCL}
function EditorTextMargins(Editor: TCustomEdit): TPoint;
var
  DC: HDC;
  I: Integer;
  SaveFont: HFONT;
  SysMetrics, Metrics: TTextMetric;
  ed: TCustomEditAccessProtected;
begin
  ed := TCustomEditAccessProtected(Editor);
  if NewStyleControls then
  begin
    if ed.BorderStyle = bsNone then
      I := 0
    else
    if ed.Ctl3D then
      I := 1
    else
      I := 2;
    if GetWindowLong(ed.Handle, GWL_STYLE) and ES_MULTILINE = 0 then
      Result.X := (SendMessage(ed.Handle, EM_GETMARGINS, 0, 0) and $0000FFFF) + I
    else
      Result.X := I;
    Result.Y := I;
  end
  else
  begin
    if ed.BorderStyle = bsNone then
      I := 0
    else
    begin
      DC := GetDC(HWND_DESKTOP);
      GetTextMetrics(DC, SysMetrics);
      SaveFont := SelectObject(DC, ed.Font.Handle);
      GetTextMetrics(DC, Metrics);
      SelectObject(DC, SaveFont);
      ReleaseDC(HWND_DESKTOP, DC);
      I := SysMetrics.tmHeight;
      if I > Metrics.tmHeight then
        I := Metrics.tmHeight;
      I := I div 4;
    end;
    Result.X := I;
    Result.Y := I;
  end;
end;
{$ENDIF VCL}

function IsInWordArray(Value: Word; const A: array of Word): Boolean;
var
  I: Integer;
begin
  Result := True;
  for I := 0 to High(A) do
    if A[I] = Value then
      Exit;
  Result := False;
end;

function LoadDefaultBitmap(Bmp: TBitmap; Item: Integer): Boolean;
begin
  {$IFDEF VCL}
  {$IFDEF CLR}
  Bmp.Handle := LoadBitmap(0, Item);
  {$ELSE}
  Bmp.Handle := LoadBitmap(0, PChar(Item));
  {$ENDIF CLR}
  Result := Bmp.Handle <> 0;
  {$ENDIF VCL}
  {$IFDEF VisualCLX}
  Result := True;
  case Item of
    OBM_COMBO:
      begin
        Bmp.Width := QStyle_sliderLength(Application.Style.Handle);
        Bmp.Height := Bmp.Width;
        Bmp.Canvas.Start;
        DrawFrameControl(Bmp.Canvas.Handle, Rect(0, 0, Bmp.Width, Bmp.Height),
          DFC_SCROLL, DFCS_SCROLLDOWN);
        Bmp.Canvas.Stop;
      end;
  else
    Bmp.Width := 0;
    Bmp.Height := 0;
    Result := False;
  end;
  {$ENDIF VisualCLX}
end;

{$IFDEF VCL}
function PaintComboEdit(Editor: TJvCustomComboEdit; const AText: string;
  AAlignment: TAlignment; StandardPaint: Boolean;
  var ACanvas: TControlCanvas; var Msg: TWMPaint): Boolean;
begin
  if not (csDestroying in Editor.ComponentState) then
  begin
    Result := PaintEdit(Editor, AText, AAlignment, Editor.PopupVisible,
      Editor.FDisabledTextColor, StandardPaint, ACanvas, Msg);
  end
  else
    Result := True;
end;
{$ENDIF VCL}

{$IFDEF VisualCLX}
function PaintComboEdit(Editor: TJvCustomComboEdit; const AText: string;
  AAlignment: TAlignment; StandardPaint: Boolean; Flat: Boolean;
  ACanvas: TCanvas): Boolean;
begin
  if not (csDestroying in Editor.ComponentState) then
  begin
    Result := PaintEdit(Editor, AText, AAlignment, Editor.PopupVisible,
      Editor.FDisabledTextColor, StandardPaint, Flat, ACanvas);
  end
  else
    Result := True;
end;
{$ENDIF VisualCLX}

{$IFDEF VCL}
function PaintEdit(Editor: TCustomEdit; const AText: string;
  AAlignment: TAlignment; PopupVisible: Boolean; 
  DisabledTextColor: TColor; StandardPaint: Boolean;
  var ACanvas: TControlCanvas; var Msg: TWMPaint): Boolean;
type
  TEd = TCustomEditAccessProtected;
const
  AlignStyle: array [Boolean, TAlignment] of DWORD =
    ((WS_EX_LEFT, WS_EX_RIGHT, WS_EX_LEFT),
    (WS_EX_RIGHT, WS_EX_LEFT, WS_EX_LEFT));
var
  LTextWidth, X: Integer;
  EditRect: TRect;
  DC: HDC;
  PS: TPaintStruct;
  S: string;
  ExStyle: DWORD;
begin
  Result := True;
  if csDestroying in Editor.ComponentState then
    Exit;
  if TEd(Editor).UseRightToLeftAlignment then
    ChangeBiDiModeAlignment(AAlignment);
  if StandardPaint and not (csPaintCopy in TEd(Editor).ControlState) then
  begin
    if SysLocale.MiddleEast and TEd(Editor).HandleAllocated and (TEd(Editor).IsRightToLeft) then
    begin { This keeps the right aligned text, right aligned }
      ExStyle := DWORD(GetWindowLong(TEd(Editor).Handle, GWL_EXSTYLE)) and (not WS_EX_RIGHT) and
        (not WS_EX_RTLREADING) and (not WS_EX_LEFTSCROLLBAR);
      if TEd(Editor).UseRightToLeftReading then
        ExStyle := ExStyle or WS_EX_RTLREADING;
      if TEd(Editor).UseRightToLeftScrollBar then
        ExStyle := ExStyle or WS_EX_LEFTSCROLLBAR;
      ExStyle := ExStyle or
        AlignStyle[TEd(Editor).UseRightToLeftAlignment, AAlignment];
      if DWORD(GetWindowLong(TEd(Editor).Handle, GWL_EXSTYLE)) <> ExStyle then
        SetWindowLong(TEd(Editor).Handle, GWL_EXSTYLE, ExStyle);
    end;
    Result := False;
    { return false if we need to use standard paint handler }
    Exit;
  end;
  { Since edit controls do not handle justification unless multi-line (and
    then only poorly) we will draw right and center justify manually unless
    the edit has the focus. }
  if ACanvas = nil then
  begin
    ACanvas := TControlCanvas.Create;
    ACanvas.Control := Editor;
  end;
  DC := Msg.DC;
  if DC = 0 then
    DC := BeginPaint(TEd(Editor).Handle, PS);
  ACanvas.Handle := DC;
  try
    ACanvas.Font := TEd(Editor).Font;
    with ACanvas do
    begin
      SendRectMessage(Editor.Handle, EM_GETRECT, 0, EditRect);
      if not (NewStyleControls and TEd(Editor).Ctl3D) and (TEd(Editor).BorderStyle = bsSingle) then
      begin
        Brush.Color := clWindowFrame;
        FrameRect(TEd(Editor).ClientRect);
      end;
      S := AText;
      LTextWidth := TextWidth(S);
      if PopupVisible then
        X := EditRect.Left
      else
      begin
        case AAlignment of
          taLeftJustify:
            X := EditRect.Left;
          taRightJustify:
            X := EditRect.Right - LTextWidth;
        else
          X := (EditRect.Right + EditRect.Left - LTextWidth) div 2;
        end;
      end;
      if SysLocale.MiddleEast then
        UpdateTextFlags;
      if not TEd(Editor).Enabled then
      begin
        // if PS.fErase then // (p3) fErase is not set to true when control is disabled
        TEd(Editor).Perform(WM_ERASEBKGND, ACanvas.Handle, 0);

        SaveDC(ACanvas.Handle);
        try
          ACanvas.Brush.Style := bsClear;
          ACanvas.Font.Color := DisabledTextColor;
          ACanvas.TextRect(EditRect, X, EditRect.Top, S);
        finally
          RestoreDC(ACanvas.Handle, -1);
        end;
      end
      else
      begin
        Brush.Color := TEd(Editor).Color;
        ACanvas.TextRect(EditRect, X, EditRect.Top, S);
      end;
    end;
  finally
    ACanvas.Handle := 0;
    if Msg.DC = 0 then
      EndPaint(TEd(Editor).Handle, PS);
  end;
end;
{$ENDIF VCL}

{$IFDEF VisualCLX}
{ PaintEdit (CLX) needs an implemented EM_GETRECT message handler. If no
  EM_GETTEXT handler exists or the edit control does not implement
  IComboEditHelper, it uses the ClientRect of the edit control. }

function PaintEdit(Editor: TCustomEdit; const AText: WideString;
  AAlignment: TAlignment; PopupVisible: Boolean;
  DisabledTextColor: TColor; StandardPaint: Boolean; Flat: Boolean;
  ACanvas: TCanvas): Boolean;
var
  LTextWidth, X: Integer;
  EditRect: TRect;
  S: WideString;
  ed: TCustomEditAccessProtected;
  SavedFont: TFontRecall;
  SavedBrush: TBrushRecall;
  Offset: Integer;
  R: TRect;
  EditHelperIntf: IComboEditHelper;
begin
  Result := True;
  if csDestroying in Editor.ComponentState then
    Exit;
  ed := TCustomEditAccessProtected(Editor);
  if StandardPaint and not (csPaintCopy in ed.ControlState) then
  begin
    Result := False;
    { return false if we need to use standard paint handler }
    Exit;
  end;
  SavedFont := TFontRecall.Create(ACanvas.Font);
  SavedBrush := TBrushRecall.Create(ACanvas.Brush);
  try
    ACanvas.Font := ed.Font;

    // paint Border
    R := ed.ClientRect;
    Offset := 0;
    if (ed.BorderStyle = bsSingle) then
    begin
      ACanvas.Start;
      QStyle_drawPanel(QWidget_style(Editor.Handle), ACanvas.Handle,
        R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top, QWidget_colorGroup(Editor.Handle),
        True, 2, nil);
      ACanvas.Stop;
      //QGraphics.DrawEdge(ACanvas, R, esLowered, esLowered, ebRect)
    end
    else
    begin
      if Flat then
        QGraphics.DrawEdge(ACanvas, R, esNone, esLowered, ebRect);
      Offset := 2;
    end;

    with ACanvas do
    begin
      if Supports(Editor, IComboEditHelper, EditHelperIntf) then
      begin
        EditRect := EditHelperIntf.GetEditorRect;
        EditHelperIntf := nil;
      end
      else
      begin
        EditRect := Rect(0, 0, 0, 0);
        SendMessage(Editor.Handle, EM_GETRECT, 0, Integer(@EditRect));
      end;
      if IsRectEmpty(EditRect) then
      begin
        EditRect := ed.ClientRect;
        if ed.BorderStyle = bsSingle then
          InflateRect(EditRect, -2, -2);
      end
      else
        InflateRect(EditRect, -Offset, -Offset);
      if Flat and (ed.BorderStyle = bsSingle) then
      begin
        Brush.Color := clWindowFrame;
        FrameRect(ACanvas, ed.ClientRect);
      end;
      S := AText;
      LTextWidth := TextWidth(S);
      if PopupVisible then
        X := EditRect.Left
      else
      begin
        case AAlignment of
          taLeftJustify:
            X := EditRect.Left;
          taRightJustify:
            X := EditRect.Right - LTextWidth;
        else
          X := (EditRect.Right + EditRect.Left - LTextWidth) div 2;
        end;
      end;
      if not ed.Enabled then
      begin
        if Supports(ed, IJvWinControlEvents) then
          (ed as IJvWinControlEvents).DoEraseBackground(ACanvas, 0);
        ACanvas.Brush.Style := bsClear;
        ACanvas.Font.Color := DisabledTextColor;
        ACanvas.TextRect(EditRect, X, EditRect.Top + 1, S);
      end
      else
      begin
        Brush.Color := ed.Color;
        DrawSelectedText(ACanvas, EditRect, X, EditRect.Top + 1, S,
          ed.SelStart, ed.SelLength,
          clHighlight, clHighlightText);
      end;
    end;
  finally
    SavedFont.Free;
    SavedBrush.Free;
  end;
end;
{$ENDIF VisualCLX}

{$IFDEF VCL}

//=== { TAutoCompleteSource } ================================================

constructor TAutoCompleteSource.Create(AComboEdit: TJvCustomComboEdit; const StartIndex: Integer);
begin
  inherited Create;
  FComboEdit := AComboEdit;
  FCurrentIndex := StartIndex;
end;

function TAutoCompleteSource.Clone(out enm: IEnumString): HRESULT;
begin
  { Save state }
  try
    enm := TAutoCompleteSource.Create(FComboEdit, FCurrentIndex);
    Result := S_OK;
  except
    Result := E_UNEXPECTED;
  end;
end;

{$IFDEF CLR}
function TAutoCompleteSource.Next(celt: Longint; rgelt: array of string; out pceltFetched: Longint): HResult;
var
  Fetched: Integer;
  S: string;
begin
  if Length(rgelt) = 0 then
  begin
    Result := E_FAIL;
    Exit;
  end;

  Fetched := 0;

  while (Fetched < celt) and (FCurrentIndex < FComboEdit.AutoCompleteItems.Count) do
  begin
    S := FComboEdit.AutoCompleteItems[FCurrentIndex];
    rgelt[Fetched] := S;
    Inc(FCurrentIndex);
    Inc(Fetched);
  end;

  if TObject(pceltFetched) <> nil then
    pceltFetched := Fetched;

  if Fetched = celt then
    Result := S_OK
  else
    Result := S_FALSE;
end;
{$ELSE}
function TAutoCompleteSource.Next(celt: Integer; out elt;
  pceltFetched: PLongint): HRESULT;
var
  Fetched: Integer;
  S: string;
  Ptr: POleStr;
  Size: Integer;
begin
  if Pointer(elt) = nil then
  begin
    Result := E_FAIL;
    Exit;
  end;

  Fetched := 0;

  while (Fetched < celt) and (FCurrentIndex < FComboEdit.AutoCompleteItems.Count) do
  begin
    S := FComboEdit.AutoCompleteItems[FCurrentIndex];
    Size := (Length(S) + 1) * SizeOf(WideChar);
    Ptr := CoTaskMemAlloc(Size);
    if Ptr = nil then
    begin
      Result := E_OUTOFMEMORY;
      Exit;
    end;
    StringToWideChar(S, Ptr, Size);

    TOleStrList(elt)[Fetched] := Ptr;

    Inc(FCurrentIndex);
    Inc(Fetched);
  end;

  if Assigned(pceltFetched) then
    pceltFetched^ := Fetched;

  if Fetched = celt then
    Result := S_OK
  else
    Result := S_FALSE;
end;
{$ENDIF CLR}

function TAutoCompleteSource.Reset: HRESULT;
begin
  FCurrentIndex := 0;
  Result := S_OK;
end;

function TAutoCompleteSource.Skip(celt: Integer): HRESULT;
begin
  Inc(FCurrentIndex, celt);
  if FCurrentIndex < FComboEdit.AutoCompleteItems.Count then
    Result := S_OK
  else
  begin
    Result := S_FALSE;
    FCurrentIndex := FComboEdit.AutoCompleteItems.Count;
  end;
end;

//=== { TDateHook } ==========================================================

procedure TDateHook.Add;
begin
  if FCount = 0 then
    Hook;
  Inc(FCount);
end;

procedure TDateHook.Delete;
begin
  if FCount > 0 then
    Dec(FCount);
  if FCount = 0 then
    UnHook;
end;

function TDateHook.FormatSettingsChange(var Msg: TMessage): Boolean;
begin
  Result := False;
  if (Msg.Msg = WM_WININICHANGE) and Application.UpdateFormatSettings then
  begin
    // Let the application obj do the changing; we receive the message
    // before the application obj, thus jump over it:
    PostMessage(Application.Handle, WM_NULL, 0, 0);
    FWinIniChangeReceived := True;
  end
  else
  if (Msg.Msg = WM_NULL) and FWinIniChangeReceived then
  begin
    FWinIniChangeReceived := False;
    DateFormatChanged;
  end;
end;

procedure TDateHook.Hook;
begin
  if FHooked then
    Exit;

  Application.HookMainWindow(FormatSettingsChange);
  FHooked := True;
end;

procedure TDateHook.UnHook;
begin
  if not FHooked then
    Exit;

  Application.UnhookMainWindow(FormatSettingsChange);
  FHooked := False;
end;

{$ENDIF VCL}

//=== { TJvCustomComboEditDataConnector } ====================================

constructor TJvCustomComboEditDataConnector.Create(AEdit: TJvCustomComboEdit);
begin
  inherited Create;
  FEdit := AEdit;
end;

procedure TJvCustomComboEditDataConnector.RecordChanged;
begin
  if Field.IsValid then
  begin
    FEdit.ReadOnly := not Field.CanModify;
    FEdit.Text := Field.AsString;
  end
  else
  begin
    FEdit.Text := '';
    FEdit.ReadOnly := True;
  end;
end;

procedure TJvCustomComboEditDataConnector.UpdateData;
begin
  Field.AsString := FEdit.Text;
  FEdit.Text := Field.AsString; // update to stored value
end;

//=== { TJvCustomComboEdit } =================================================

constructor TJvCustomComboEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDataConnector := CreateDataConnector;
  ControlStyle := ControlStyle + [csCaptureMouse];
  //  AutoSize := False;   // Polaris
  Height := 21;
  FDirectInput := True;
  FClickKey := scAltDown;
  FPopupAlign := epaRight;
  FBtnControl := TWinControl.Create(Self);
  with FBtnControl do
    ControlStyle := ControlStyle + [csReplicatable];
  FBtnControl.Width := DefEditBtnWidth;
  FBtnControl.Height := 17;
  FBtnControl.Visible := True;
  {$IFDEF VCL}
  FBtnControl.Parent := Self;
  {$IFDEF COMPILER6_UP}
  FBtnControl.Align := alCustom;
  {$ELSE}
  FBtnControl.Align := alRight;
  {$ENDIF COMPILER6_UP}
  {$ENDIF VCL}
  {$IFDEF VisualCLX}
  FBtnControl.Parent := Self.ClientArea;
  FBtnControl.Left := Self.ClientArea.Width - DefEditBtnWidth;
  FBtnControl.Anchors := [akRight, akTop, akBottom];
  {$ENDIF VisualCLX}
  FButton := TJvEditButton.Create(Self);
  FButton.SetBounds(0, 0, FBtnControl.Width, FBtnControl.Height);
  FButton.Visible := True;
  FButton.Align := alClient;
  FButton.OnClick := EditButtonClick;
  FButton.Parent := FBtnControl;

  FAlwaysEnableButton := False;
  (* ++ RDB ++ *)
  FDisabledColor := clWindow;
  FDisabledTextColor := clGrayText;
  FGroupIndex := -1;
  FStreamedButtonWidth := -1;
  FImageKind := ikCustom;
  FImageIndex := -1;
  FNumGlyphs := 1;
  {$IFDEF VCL}
  FAutoCompleteItems := TStringList.Create;
  FAutoCompleteOptions := [];
  CoInitialize(nil);
  {$ENDIF VCL}
  inherited OnKeyDown := LocalKeyDown;
  (* -- RDB -- *)
end;

destructor TJvCustomComboEdit.Destroy;
begin
  PopupCloseUp(Self, False);
  FButton.OnClick := nil;
  {$IFDEF VCL}
  DestroyAutoComplete;
  FAutoCompleteItems.Free;
  {$ENDIF VCL}
  FDataConnector.Free;
  inherited Destroy;
  {$IFDEF VCL}
  // call after WM_DESTROY
  CoUninitialize;
  {$ENDIF VCL}
end;

function TJvCustomComboEdit.AcceptPopup(var Value: Variant): Boolean;
begin
  Result := True;
end;

procedure TJvCustomComboEdit.AcceptValue(const Value: Variant);
begin
  if Text <> VarToStr(Value) then
  begin
    Text := Value;
    Modified := True;
    UpdatePopupVisible;
    //DoChange; (ahuser) "Text := Value" triggers Change;
  end;
end;

procedure TJvCustomComboEdit.ActionChange(Sender: TObject;
  CheckDefaults: Boolean);
begin
  if Sender is TCustomAction then
    with TCustomAction(Sender) do
    begin
      if not CheckDefaults or not Assigned(Self.Images) then
        Self.Images := TCustomImageList(ActionList.Images);
      if not CheckDefaults or Self.Enabled then
        Self.Enabled := Enabled;
      if not CheckDefaults or (Self.HelpContext = 0) then
        Self.HelpContext := HelpContext;
      if not CheckDefaults or (Self.Hint = '') then
        Self.ButtonHint := Hint;
      if not CheckDefaults or (Self.ImageIndex = -1) then
        Self.ImageIndex := ImageIndex;
      if not CheckDefaults or (Self.ClickKey = scNone) then
        Self.ClickKey := ShortCut;
      if not CheckDefaults or Self.Visible then
        Self.Visible := Visible;
      if not CheckDefaults or not Assigned(Self.OnButtonClick) then
        Self.OnButtonClick := OnExecute;
    end;
end;

procedure TJvCustomComboEdit.AdjustHeight;
var
  DC: HDC;
  SaveFont: HFONT;
  I: Integer;
  SysMetrics, Metrics: TTextMetric;
begin
  DC := GetDC(HWND_DESKTOP);
  GetTextMetrics(DC, SysMetrics);
  SaveFont := SelectObject(DC, Font.Handle);
  GetTextMetrics(DC, Metrics);
  SelectObject(DC, SaveFont);
  ReleaseDC(HWND_DESKTOP, DC);
  if NewStyleControls then
  begin
    if not Flat then
      I := 8
    else
      I := 6;
    I := GetSystemMetrics(SM_CYBORDER) * I;
  end
  else
  begin
    I := SysMetrics.tmHeight;
    if I > Metrics.tmHeight then
      I := Metrics.tmHeight;
    I := I div 4 + GetSystemMetrics(SM_CYBORDER) * 4;
  end;
  if Height < Metrics.tmHeight + I then
    Height := Metrics.tmHeight + I;
end;

procedure TJvCustomComboEdit.AdjustSize;
var
  MinHeight: Integer;
begin
  inherited AdjustSize;
  if not (csLoading in ComponentState) then
  begin
    MinHeight := GetMinHeight;
    { text edit bug: if size to less than MinHeight, then edit ctrl does
      not display the text }
    if Height < MinHeight then
    begin
      Height := MinHeight;
      Exit;
    end;
  end
  else
  begin
    if (FPopup <> nil) and (csDesigning in ComponentState) then
      FPopup.SetBounds(0, Height + 1, 10, 10);
  end;
  UpdateControls;
  UpdateMargins;
end;

procedure TJvCustomComboEdit.AsyncPopupCloseUp(Accept: Boolean);
begin
  PostMessage(Handle, CM_POPUPCLOSEUP, Ord(Accept), 0);
end;

function TJvCustomComboEdit.BtnWidthStored: Boolean;
begin
  if (FImageKind = ikDefault) and (DefaultImages <> nil) and (DefaultImageIndex >= 0) then
    Result := ButtonWidth <> Max(DefaultImages.Width + 6, DefEditBtnWidth)
  else
  if FImageKind = ikDropDown then
    Result := ButtonWidth <> GetSystemMetrics(SM_CXVSCROLL)
  else
    Result := ButtonWidth <> DefEditBtnWidth;
end;

procedure TJvCustomComboEdit.ButtonClick;
begin
  if Assigned(FOnButtonClick) then
    FOnButtonClick(Self);

  if (FPopup <> nil) and FPopupVisible then
    PopupCloseUp(FPopup, True)
  else
    PopupDropDown(True);
end;

procedure TJvCustomComboEdit.Change;
begin
  DataConnector.Modify;
  if not PopupVisible then
    DoChange
  else
    PopupChange;
end;

{$IFDEF VCL}

procedure TJvCustomComboEdit.CMBiDiModeChanged(var Msg: TMessage);
begin
  inherited;
  if FPopup <> nil then
    FPopup.BiDiMode := BiDiMode;
end;

procedure TJvCustomComboEdit.CMCancelMode(var Msg: TCMCancelMode);
begin
  if (Msg.Sender <> Self) and (Msg.Sender <> FPopup) and
    (Msg.Sender <> FButton) and ((FPopup <> nil) and
    not FPopup.ContainsControl(Msg.Sender)) then
    PopupCloseUp(FPopup, False);
end;

procedure TJvCustomComboEdit.CMCtl3DChanged(var Msg: TMessage);
begin
  inherited;
  DoCtl3DChanged;
end;

procedure TJvCustomComboEdit.CMPopupCloseup(var Msg: TMessage);
begin
  PopupCloseUp(Self, Boolean(Msg.WParam));
end;

procedure TJvCustomComboEdit.CMWantSpecialKey(var Msg: TCMWantSpecialKey);
begin
  inherited;
  { Ignore tabs when popup is visible }
  if PopupVisible and (Msg.CharCode = VK_TAB) then
    Msg.Result := 1;
end;

procedure TJvCustomComboEdit.CNCtlColor(var Msg: TMessage);
var
  TextColor: Longint;
begin
  inherited;
  if NewStyleControls then
  begin
    TextColor := ColorToRGB(Font.Color);
    if not Enabled and (ColorToRGB(Color) <> ColorToRGB(clGrayText)) then
      TextColor := ColorToRGB(clGrayText);
    SetTextColor(Msg.WParam, TextColor);
  end;
end;

procedure TJvCustomComboEdit.CreateAutoComplete;
begin
  if HandleAllocated and not (csDesigning in ComponentState) and
    {not Assigned(FAutoCompleteIntf) and} (AutoCompleteOptions <> []) then
  begin
    { Create the autocomplete object. }
    {$IFDEF CLR}
    FAutoCompleteIntf :=
      Activator.CreateInstance(System.Type.GetTypeFromCLSID(Guid.Create(CLSID_AutoComplete))) as IAutoComplete;
    if FAutoCompleteIntf <> nil then
    {$ELSE}
    if Succeeded(CoCreateInstance(CLSID_AutoComplete, nil, CLSCTX_INPROC_SERVER, IAutoComplete,
      FAutoCompleteIntf)) then
    {$ENDIF CLR}
    begin
      { Initialize the autocomplete object. }
      FAutoCompleteIntf.Init(Self.Handle, GetAutoCompleteSource, nil, nil);
    end
    else
      FAutoCompleteIntf := nil;
  end;
end;

procedure TJvCustomComboEdit.DestroyAutoComplete;
begin
  FAutoCompleteIntf := nil;
end;

procedure TJvCustomComboEdit.CreateParams(var Params: TCreateParams);
const
  Alignments: array [TAlignment] of LongWord = (ES_LEFT, ES_RIGHT, ES_CENTER);
begin
  inherited CreateParams(Params);
  Params.Style := Params.Style or
    ES_MULTILINE or WS_CLIPCHILDREN or Alignments[FAlignment];
end;

{$ENDIF VCL}

procedure TJvCustomComboEdit.CreatePopup;
begin
  { Notification }
end;

procedure TJvCustomComboEdit.CreateWnd;
begin
  inherited CreateWnd;
  UpdateControls;
  UpdateMargins;
  {$IFDEF VCL}
  if AutoCompleteOptions <> [] then
  begin
    CreateAutoComplete;
    UpdateAutoComplete;
  end;
  {$ENDIF VCL}
end;

{$IFDEF COMPILER6_UP}
{$IFDEF VCL}
procedure TJvCustomComboEdit.CustomAlignPosition(Control: TControl;
  var NewLeft, NewTop, NewWidth, NewHeight: Integer;
  var AlignRect: TRect; AlignInfo: TAlignInfo);
{$ENDIF VCL}
{$IFDEF VisualCLX}
procedure TJvCustomComboEdit.CustomAlignPosition(Control: TControl; var NewLeft,
      NewTop, NewWidth, NewHeight: Integer; var AlignRect: TRect);
{$ENDIF VisualCLX}
begin
  if Control = FBtnControl then
    UpdateBtnBounds(NewLeft, NewTop, NewWidth, NewHeight);
end;
{$ENDIF COMPILER6_UP}

class function TJvCustomComboEdit.DefaultImageIndex: TImageIndex;
begin
  Result := -1;
end;

class function TJvCustomComboEdit.DefaultImages: TCustomImageList;
begin
  if GDefaultComboEditImagesList = nil then
    GDefaultComboEditImagesList := TImageList.CreateSize(14, 12);
  Result := TCustomImageList(GDefaultComboEditImagesList);
end;

procedure TJvCustomComboEdit.DefineProperties(Filer: TFiler);
begin
  inherited DefineProperties(Filer);

  Filer.DefineProperty('GlyphKind', ReadGlyphKind, nil, False);
  {$IFDEF VCL}
  Filer.DefineProperty('Ctl3D', ReadCtl3D, nil, False);
  Filer.DefineProperty('ParentCtl3D', ReadParentCtl3D, nil, False);
  {$ENDIF VCL}
end;

{$IFDEF VCL}
procedure TJvCustomComboEdit.DestroyWnd;
begin
  inherited DestroyWnd;
  { Mantis #3642 }
  DestroyAutoComplete;
end;
{$ENDIF VCL}

procedure TJvCustomComboEdit.DoChange;
begin
  inherited Change;
end;

procedure TJvCustomComboEdit.DoClick;
begin
  EditButtonClick(Self);
end;

procedure TJvCustomComboEdit.WMClear(var Msg: TMessage);
begin
  Text := '';
end;

procedure TJvCustomComboEdit.WMCut(var Msg: TMessage);
begin
  if FDirectInput and not ReadOnly then
    inherited;
end;

procedure TJvCustomComboEdit.WMPaste(var Msg: TMessage);
begin
  if FDirectInput and not ReadOnly then
    inherited;
  UpdateGroup;
end;

procedure TJvCustomComboEdit.DoCtl3DChanged;
begin
  UpdateMargins;
  UpdateControls;
end;

procedure TJvCustomComboEdit.DoEnter;
begin
  if AutoSelect and not (csLButtonDown in ControlState) then
    SelectAll;
  inherited DoEnter;
end;

procedure TJvCustomComboEdit.DoExit;
begin
  DataConnector.UpdateRecord;
  inherited DoExit;
end;

{$IFDEF VisualCLX}
procedure TJvCustomComboEdit.DoFlatChanged;
begin
  inherited DoFlatChanged;
  UpdateControls;
  UpdateMargins;
end;
{$ENDIF VisualCLX}

procedure TJvCustomComboEdit.FocusKilled(NextWnd: THandle);
var
  Sender: TWinControl;
begin
  inherited FocusKilled(NextWnd);
  FFocused := Screen.ActiveControl <> Self;
  if not FFocused then
  begin
    Sender := FindControl(NextWnd);
    if (Sender <> Self) and (Sender <> FPopup) and
      {(Sender <> FButton)} ((FPopup <> nil) and
      not FPopup.ContainsControl(Sender)) then
    begin
      { MSDN : While processing this message (WM_KILLFOCUS), do not make any
               function calls that display or activate a window.
      }
      AsyncPopupCloseUp(False);
    end;
  end;
end;

function TJvCustomComboEdit.DoEraseBackground(Canvas: TCanvas; Param: Integer): Boolean;
begin
  Result := True;
  if csDestroying in ComponentState then
    { (rb) Implementation diffs; some return True other False }
    Exit;
  if Enabled then
    Result := inherited DoEraseBackground(Canvas, Param)
  else
  begin
    Canvas.Brush.Color := FDisabledColor;
    Canvas.Brush.Style := bsSolid;
    Canvas.FillRect(ClientRect);
  end;
end;

procedure TJvCustomComboEdit.FocusSet(PrevWnd: THandle);
begin
  inherited FocusSet(PrevWnd); // triggers OnExit and OnEnter => Focus could be changed
  FFocused := Screen.ActiveControl = Self;
  if FFocused then
    SetShowCaret;
end;

procedure TJvCustomComboEdit.EditButtonClick(Sender: TObject);
begin
  if (not FReadOnly) or AlwaysEnableButton then
    ButtonClick;
end;

function TJvCustomComboEdit.EditCanModify: Boolean;
begin
  Result := not FReadOnly;
end;

procedure TJvCustomComboEdit.EnabledChanged;
begin
  inherited EnabledChanged;
  Invalidate;
  FButton.Enabled := Enabled;
  if Assigned(FOnEnabledChanged) then
    FOnEnabledChanged(Self);
end;

procedure TJvCustomComboEdit.FontChanged;
begin
  inherited FontChanged;
  if HandleAllocated then
    UpdateMargins;
end;

function TJvCustomComboEdit.GetActionLinkClass: TControlActionLinkClass;
begin
  Result := TJvCustomComboEditActionLink;
end;

{$IFDEF VCL}
function TJvCustomComboEdit.GetAutoCompleteSource: IEnumString;
begin
  Result := TAutoCompleteSource.Create(Self, 0);
end;
{$ENDIF VCL}

function TJvCustomComboEdit.GetButtonFlat: Boolean;
begin
  Result := FButton.Flat;
end;

function TJvCustomComboEdit.GetButtonHint: string;
begin
  Result := FButton.Hint;
end;

function TJvCustomComboEdit.GetButtonWidth: Integer;
begin
  if ShowButton then
    Result := FButton.Width
  else
    Result := FSavedButtonWidth;
end;

function TJvCustomComboEdit.GetDirectInput: Boolean;
begin
  Result := FDirectInput;
end;

{$IFDEF VCL}

function TJvCustomComboEdit.GetFlat: Boolean;
begin
  Result := not Ctl3D;
end;

function TJvCustomComboEdit.GetParentFlat: Boolean;
begin
  Result := ParentCtl3D;
end;

procedure TJvCustomComboEdit.SetFlat(const Value: Boolean);
begin
  Ctl3D := not Value;
end;

procedure TJvCustomComboEdit.SetParentFlat(const Value: Boolean);
begin
  ParentCtl3D := Value;
end;

{$ENDIF VCL}

function TJvCustomComboEdit.GetGlyph: TBitmap;
begin
  Result := FButton.Glyph;
end;

function TJvCustomComboEdit.GetGlyphKind: TGlyphKind;
begin
  Result := TGlyphKind(FImageKind);
end;

procedure TJvCustomComboEdit.GetInternalMargins(var ALeft, ARight: Integer);
const
  CPixelsBetweenEditAndButton = 2;
begin
  ARight := ARight + FBtnControl.Width + CPixelsBetweenEditAndButton;
end;

function TJvCustomComboEdit.GetMinHeight: Integer;
var
  I: Integer;
begin
  I := GetTextHeight;
  if BorderStyle = bsSingle then
    I := I + GetSystemMetrics(SM_CYBORDER) * 4 + 1;
  Result := I;
end;

function TJvCustomComboEdit.GetNumGlyphs: TNumGlyphs;
begin
  if ImageKind <> ikCustom then
    Result := FNumGlyphs
  else
    Result := FButton.NumGlyphs;
end;

function TJvCustomComboEdit.GetPopupValue: Variant;
begin
  if FPopup is TJvPopupWindow then
    Result := TJvPopupWindow(FPopup).GetValue
  else
    Result := '';
end;

function TJvCustomComboEdit.GetPopupVisible: Boolean;
begin
  Result := (FPopup <> nil) and FPopupVisible;
end;

function TJvCustomComboEdit.GetReadOnly: Boolean;
begin
  Result := FReadOnly;
end;

function TJvCustomComboEdit.GetSettingCursor: Boolean;
begin
  {$IFDEF CLR}
  Result := Boolean(GetPrivateField(Self, 'FSettingCursor'));
  {$ELSE}
  Result := TCustomMaskEditAccessPrivate(Self).FSettingCursor;
  {$ENDIF CLR}
end;

function TJvCustomComboEdit.GetShowButton: Boolean;
begin
  Result := FBtnControl.Visible;
end;

function TJvCustomComboEdit.GetTextHeight: Integer;
var
  DC: HDC;
  SaveFont: HFONT;
  SysMetrics, Metrics: TTextMetric;
begin
  DC := GetDC(HWND_DESKTOP);
  try
    GetTextMetrics(DC, SysMetrics);
    SaveFont := SelectObject(DC, Font.Handle);
    GetTextMetrics(DC, Metrics);
    SelectObject(DC, SaveFont);
  finally
    ReleaseDC(HWND_DESKTOP, DC);
  end;
  //  Result := Min(SysMetrics.tmHeight, Metrics.tmHeight);  // Polaris
  Result := Metrics.tmHeight; // Polaris
end;

procedure TJvCustomComboEdit.HidePopup;
begin
  if FPopup is TJvPopupWindow then
  begin
    TJvPopupWindow(FPopup).Hide;
    if Assigned(FOnPopupHidden) then
      FOnPopupHidden(Self);
  end;
end;

function TJvCustomComboEdit.IsCustomGlyph: Boolean;
begin
  Result := Assigned(Glyph) and (ImageKind = ikCustom);
end;

{$IFDEF VCL}
function TJvCustomComboEdit.IsFlatStored: Boolean;
begin
  { Same as IsCtl3DStored }
  Result := not ParentCtl3D;
end;
{$ENDIF VCL}

function TJvCustomComboEdit.IsImageIndexStored: Boolean;
begin
  Result :=
    not (ActionLink is TJvCustomComboEditActionLink) or
    not (ActionLink as TJvCustomComboEditActionLink).IsImageIndexLinked;
end;

procedure TJvCustomComboEdit.KeyDown(var Key: Word; Shift: TShiftState);
//Polaris
var
  Form: TCustomForm;
begin
  UpdateGroup;

  //Polaris
  Form := GetParentForm(Self);
  if (ssCtrl in Shift) then
    case Key of
      VK_RETURN:
        if (Form <> nil) {and Form.KeyPreview} then
        begin
          {$IFDEF CLR}
          Form.GetType.InvokeMember('KeyDown',
            BindingFlags.Instance or BindingFlags.NonPublic or BindingFlags.InvokeMethod, nil, Form, [Key, Shift]);
          {$ELSE}
          TWinControlAccessProtected(Form).KeyDown(Key, Shift);
          {$ENDIF CLR}
          Key := 0;
        end;
      VK_TAB:
        if (Form <> nil) {and Form.KeyPreview} then
        begin
          {$IFDEF CLR}
          Form.GetType.InvokeMember('KeyDown',
            BindingFlags.Instance or BindingFlags.NonPublic or BindingFlags.InvokeMethod, nil, Form, [Key, Shift]);
          {$ELSE}
          TWinControlAccessProtected(Form).KeyDown(Key, Shift);
          {$ENDIF CLR}
          Key := 0;
        end;
    end;
  //Original
  inherited KeyDown(Key, Shift);
  if (FClickKey = ShortCut(Key, Shift)) and (ButtonWidth > 0) then
  begin
    EditButtonClick(Self);
    Key := 0;
  end;
end;

procedure TJvCustomComboEdit.KeyPress(var Key: Char);
var
  Form: TCustomForm;
begin
  Form := GetParentForm(Self);

  if (Key = Cr) or (Key = Esc) or ((Key = Lf) and PopupVisible) then
  begin
    if PopupVisible then
    begin
      //Polaris      PopupCloseUp(FPopup, Key = Char(VK_RETURN));
      PopupCloseUp(FPopup, Key <> Esc);
      Key := #0;
    end
    else
    begin
      { must catch and remove this, since is actually multi-line }
      {$IFDEF VCL}
      GetParentForm(Self).Perform(CM_DIALOGKEY, Byte(Key), 0);
      {$ENDIF VCL}
      {$IFDEF VisualCLX}
      TCustomFormAccessProtected(GetParentForm(Self)).NeedKey(Integer(Key), [], WideChar(Key));
      {$ENDIF VisualCLX}
      if Key = Cr then
      begin
        inherited KeyPress(Key);
        Key := #0;
        Exit;
      end;
    end;
  end;
  //Polaris
  if Key in [Tab, Lf] then
  begin
    Key := #0;
    { (rb) Next code has no use because Key = #0? }
    if (Form <> nil) {and Form.KeyPreview} then
      {$IFDEF CLR}
      Form.GetType.InvokeMember('KeyPress',
        BindingFlags.Instance or BindingFlags.NonPublic or BindingFlags.InvokeMethod, nil, Form, [Key]);
      {$ELSE}
      TWinControlAccessProtected(Form).KeyPress(Key);
      {$ENDIF CLR}
  end;
  //Polaris
  inherited KeyPress(Key);

  if (Key = #27) and DataConnector.Active then
  begin
    DataConnector.Reset;
    Key := #0;
  end;
end;

procedure TJvCustomComboEdit.Loaded;
begin
  inherited Loaded;
  if FStreamedButtonWidth >= 0 then
  begin
    SetButtonWidth(FStreamedButtonWidth);
    if FStreamedFixedWidth then
      with FButton do
        ControlStyle := ControlStyle + [csFixedWidth];
  end;

  UpdateControls;
  UpdateMargins;
end;

procedure TJvCustomComboEdit.LocalKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  UpdateGroup;
  if Assigned(FOnKeyDown) then
    FOnKeyDown(Sender, Key, Shift);
end;

procedure TJvCustomComboEdit.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if (FPopup <> nil) and (Button = mbLeft) then
  begin
    if CanFocus then
      SetFocus;
    if not FFocused then
      Exit;
    if FPopupVisible then
      PopupCloseUp(FPopup, False);
    {else
     if (not ReadOnly or AlwaysEnable) and (not DirectInput) then
       PopupDropDown(True);}
  end;
  inherited MouseDown(Button, Shift, X, Y);
end;

procedure TJvCustomComboEdit.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (AComponent = FImages) then
    Images := nil;
  if (Operation = opRemove) and (AComponent = FPopup) then
    FPopup := nil;
end;

{$IFDEF VisualCLX}
procedure TJvCustomComboEdit.Paint;
begin
  if Enabled then
    inherited Paint
  else
  begin
    if not PaintEdit(Self, Text, Alignment, PopupVisible,
      DisabledTextColor, Focused and not PopupVisible, {Flat:}False, Canvas) then
      inherited Paint;
  end;
end;
{$ENDIF VisualCLX}

procedure TJvCustomComboEdit.PopupChange;
begin
end;

procedure TJvCustomComboEdit.PopupCloseUp(Sender: TObject; Accept: Boolean);
var
  AValue: Variant;
begin
  if (FPopup <> nil) and FPopupVisible then
  begin
    {$IFDEF VCL}
    if GetCapture <> 0 then
      SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
    {$ENDIF VCL}
    {$IFDEF VisualCLX}
    if Mouse.Capture <> nil then
      Mouse.Capture := nil;
    {$ENDIF VisualCLX}
    AValue := GetPopupValue;
    HidePopup;
    try
      try
        if CanFocus and ParentFormVisible(Self) then
        begin
          SetFocus;
          if GetFocus = Handle then
            SetShowCaret;
        end;
      except
        { ignore exceptions }
      end;
      SetDirectInput(DirectInput);
      Invalidate;
      try
        if Accept and AcceptPopup(AValue) and EditCanModify then
        begin
          AcceptValue(AValue);
          if FFocused then
            inherited SelectAll;
        end
        else
          Reset;
      except
        Reset;
        raise;
      end;
    finally
      FPopupVisible := False;
    end;
  end;  
end;

procedure TJvCustomComboEdit.PopupDropDown(DisableEdit: Boolean);
var
  P: TPoint;
  Y: Integer;
  SR: TJvSizeRect;
  {$IFDEF VCL}
  Monitor: TMonitor;
  Rect: TRect;
  {$ENDIF VCL}
begin
  if not ((ReadOnly and not FAlwaysShowPopup) or FPopupVisible) then
  begin
    CreatePopup;
    if FPopup = nil then
      Exit;

    P := Parent.ClientToScreen(Point(Left, Top));
    {$IFDEF VCL}
    Monitor := FindMonitor(MonitorFromWindow(Handle, MONITOR_DEFAULTTONEAREST));
    Rect := GetWorkAreaRect(Monitor);
    SR.Top := Rect.Top;
    SR.Left := Rect.Left;
    SR.Width := Rect.Right - Rect.Left;
    SR.Height := Rect.Bottom - Rect.Top;
    {$ENDIF VCL}
    {$IFDEF VisualCLX}
    SR.Top := Screen.Top;
    SR.Left := Screen.Left;
    SR.Width := Screen.Width;
    SR.Height := Screen.Height;
    {$ENDIF VisualCLX}
    Y := P.Y + Height;
    if Y + FPopup.Height > SR.Top + SR.Height then
      Y := P.Y - FPopup.Height;
    case FPopupAlign of
      epaRight:
        begin
          Dec(P.X, FPopup.Width - Width);
          if P.X < SR.Left then
            Inc(P.X, FPopup.Width - Width);
        end;
      epaLeft:
        if P.X + FPopup.Width > SR.Left + SR.Width then
          Dec(P.X, FPopup.Width - Width);
    end;
    if P.X < SR.Left then
      P.X := SR.Left
    else
    if P.X + FPopup.Width > SR.Left + SR.Width then
      P.X := SR.Left + SR.Width - FPopup.Width;
    if Text <> '' then
      SetPopupValue(Text)
    else
      SetPopupValue(Null);
    if CanFocus then
      SetFocus;
    ShowPopup(Point(P.X, Y));
    FPopupVisible := True;
    if DisableEdit then
    begin
      inherited ReadOnly := True;
      HideCaret(Handle);
    end;
  end;
end;

{$IFDEF VCL}

procedure TJvCustomComboEdit.ReadCtl3D(Reader: TReader);
begin
  Flat := not Reader.ReadBoolean;
end;

procedure TJvCustomComboEdit.ReadParentCtl3D(Reader: TReader);
begin
  ParentFlat := Reader.ReadBoolean;
end;

{$ENDIF VCL}

procedure TJvCustomComboEdit.ReadGlyphKind(Reader: TReader);
const
  sEnumValues: array [TGlyphKind] of string[12] =
    ('gkCustom', 'gkDefault', 'gkDropDown', 'gkEllipsis');
var
  S: string;
  GlyphKind: TGlyphKind;
begin
  { No need to drag in TypInfo.pas }
  S := Reader.ReadIdent;
  for GlyphKind := Low(TGlyphKind) to High(TGlyphKind) do
    if SameText(S, sEnumValues[GlyphKind]) then
    begin
      ImageKind := TJvImageKind(GlyphKind);
      Break;
    end;
end;

procedure TJvCustomComboEdit.RecreateGlyph;
var
  NewGlyph: TBitmap;

  function CreateEllipsisGlyph: TBitmap;
  var
    W, g, I: Integer;
  begin
    Result := TBitmap.Create;
    with Result do
    try
      {$IFDEF VCL}
      Monochrome := True;
      {$ENDIF VCL}
      Width := Max(1, FButton.Width - 6);
      Height := 4;
      W := 2;
      g := (Result.Width - 3 * W) div 2;
      if g <= 0 then
        g := 1;
      if g > 3 then
        g := 3;
      I := (Width - 3 * W - 2 * g) div 2;
      {$IFDEF VisualCLX}
      Canvas.Start;
      {$ENDIF VisualCLX}
      PatBlt(Canvas.Handle, I, 1, W, W, BLACKNESS);
      PatBlt(Canvas.Handle, I + g + W, 1, W, W, BLACKNESS);
      PatBlt(Canvas.Handle, I + 2 * g + 2 * W, 1, W, W, BLACKNESS);
      {$IFDEF VisualCLX}
      Canvas.Stop;
      {$ENDIF VisualCLX}
    except
      Free;
      raise;
    end;
  end;

begin
  { Delay until button is shown }
  if not ShowButton then
    Exit;

  if FImageKind in [ikDropDown, ikEllipsis] then
  begin
    FButton.ImageIndex := -1;
    FButton.NumGlyphs := 1;
  end;
  {$IFDEF JVCLThemesEnabled}
  FButton.FDrawThemedDropDownBtn := FImageKind = ikDropDown;
  {$ENDIF JVCLThemesEnabled}

  case FImageKind of
    ikDropDown:
      begin
        {$IFDEF JVCLThemesEnabled}
        { When XP Themes are enabled, ButtonFlat = False, GlyphKind = gkDropDown then
          the glyph is the default themed dropdown button. When ButtonFlat = True, we
          can't use that default dropdown button (because we then use toolbar buttons,
          and there is no themed dropdown toolbar button) }
        FButton.FDrawThemedDropDownBtn :=
          ThemeServices.ThemesEnabled and not ButtonFlat;
        if FButton.FDrawThemedDropDownBtn then
        begin
          FButton.ButtonGlyph.Glyph := nil;
          FButton.Invalidate;
        end
        else
        {$ENDIF JVCLThemesEnabled}
        begin
          LoadDefaultBitmap(FButton.ButtonGlyph.Glyph, OBM_COMBO);
          FButton.Invalidate;
        end;
      end;
    ikEllipsis:
      begin
        NewGlyph := CreateEllipsisGlyph;
        try
          FButton.ButtonGlyph.Glyph := NewGlyph;
          FButton.Invalidate;
        finally
          NewGlyph.Destroy;
        end;
      end;
  else
//    FButton.ButtonGlyph.Glyph := nil;
    FButton.Invalidate;
  end;
end;

procedure TJvCustomComboEdit.SelectAll;
begin
  if DirectInput then
    inherited SelectAll;
end;

{$IFDEF VCL}

procedure TJvCustomComboEdit.SetAlignment(Value: TAlignment);
begin
  if FAlignment <> Value then
  begin
    FAlignment := Value;
    RecreateWnd;
  end;
end;

procedure TJvCustomComboEdit.SetAutoCompleteItems(Strings: TStrings);
begin
  FAutoCompleteItems.Assign(Strings);
end;

procedure TJvCustomComboEdit.SetAutoCompleteOptions(const Value: TJvAutoCompleteOptions);
begin
  if Value <> FAutoCompleteOptions then
  begin
    FAutoCompleteOptions := Value;

    if not Assigned(FAutoCompleteIntf) then
      CreateAutoComplete;
    UpdateAutoComplete;
  end;
end;

{$ENDIF VCL}

{$IFDEF VisualCLX}
procedure TJvCustomComboEdit.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
begin
  inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  UpdateControls;
  UpdateMargins;
end;
{$ENDIF VisualCLX}

procedure TJvCustomComboEdit.SetButtonFlat(const Value: Boolean);
begin
  FButton.Flat := Value;
  {$IFDEF JVCLThemesEnabled}
  { When XP Themes are enabled, ButtonFlat = False, GlyphKind = gkDropDown then
    the glyph is the default themed dropdown button. When ButtonFlat = True, we
    can't use that default dropdown button, so we have to recreate the glyph
    in this special case }
  if ThemeServices.ThemesEnabled and (ImageKind = ikDropDown) then
    RecreateGlyph;
  {$ENDIF JVCLThemesEnabled}
end;

procedure TJvCustomComboEdit.SetButtonHint(const Value: string);
begin
  FButton.Hint := Value;
end;

procedure TJvCustomComboEdit.SetButtonWidth(Value: Integer);
begin
  if csLoading in ComponentState then
  begin
    FStreamedButtonWidth := Value;
    FStreamedFixedWidth := False;
  end
  else
  if not ShowButton then
    FSavedButtonWidth := Value
  else
  if (ButtonWidth <> Value) {or ((Value > 0) <> ShowButton)} then
  begin
    if Value > 1 then
      FBtnControl.Visible := True
    else
    begin
      FSavedButtonWidth := ButtonWidth;
      FBtnControl.Visible := False;
    end;
    if csCreating in ControlState then
    begin
      FBtnControl.Width := Value;
      FButton.Width := Value;
      with FButton do
        ControlStyle := ControlStyle - [csFixedWidth];
      { Some glyphs are size dependant (ellipses), thus recreate on size changes }
      RecreateGlyph;
    end
      //else
      //if (Value <> ButtonWidth) and (Value < ClientWidth) then begin
      //Polaris
    else
    if (Value <> ButtonWidth) and
      ((Assigned(Parent) and (Value < ClientWidth)) or
      (not Assigned(Parent) and (Value < Width))) then
    begin
      FBtnControl.SetBounds(FBtnControl.Left + FBtnControl.Width - Value,
        FBtnControl.Top, Value, FBtnControl.Height);
      FButton.Width := Value;
      with FButton do
        ControlStyle := ControlStyle - [csFixedWidth];
      if HandleAllocated then
        {$IFDEF VCL}
        RecreateWnd;
        {$ENDIF VCL}
        {$IFDEF VisualCLX}
        Invalidate;
        {$ENDIF VisualCLX}
      { Some glyphs are size dependant (ellipses), thus recreate on size changes }
      RecreateGlyph;
    end;
  end;
end;

procedure TJvCustomComboEdit.SetClipboardCommands(const Value: TJvClipboardCommands);
begin
  if ClipboardCommands <> Value then
  begin
    inherited SetClipboardCommands(Value);
    if ReadOnly and not (ClipboardCommands <= [caCopy]) then
      ClipboardCommands := [caCopy];
  end;
end;

procedure TJvCustomComboEdit.SetDirectInput(Value: Boolean);
begin
  inherited ReadOnly := not Value or FReadOnly;
  FDirectInput := Value;
end;

procedure TJvCustomComboEdit.SetDisabledColor(const Value: TColor);
begin
  if FDisabledColor <> Value then
  begin
    FDisabledColor := Value;
    if not Enabled then
      Invalidate;
  end;
end;

procedure TJvCustomComboEdit.SetDisabledTextColor(const Value: TColor);
begin
  if FDisabledTextColor <> Value then
  begin
    FDisabledTextColor := Value;
    if not Enabled then
      Invalidate;
  end;
end;

procedure TJvCustomComboEdit.SetGlyph(Value: TBitmap);
begin
  ImageKind := ikCustom;
  FButton.Glyph := Value;
  FNumGlyphs := FButton.NumGlyphs;
end;

procedure TJvCustomComboEdit.SetGlyphKind(Value: TGlyphKind);
begin
  ImageKind := TJvImageKind(Value);
end;

procedure TJvCustomComboEdit.SetGroupIndex(const Value: Integer);
begin
  FGroupIndex := Value;
  UpdateGroup;
end;

procedure TJvCustomComboEdit.SetImageIndex(const Value: TImageIndex);
begin
  if FImageIndex <> Value then
  begin
    FImageIndex := Value;
    if FImageKind = ikCustom then
      FButton.ImageIndex := FImageIndex;
  end;
end;

procedure TJvCustomComboEdit.SetImageKind(const Value: TJvImageKind);
begin
  if FImageKind <> Value then
  begin
    FImageKind := Value;
    RecreateGlyph;
    case FImageKind of
      ikCustom:
        begin
          FButton.Images := FImages;
          FButton.ImageIndex := FImageIndex;
          FButton.NumGlyphs := FNumGlyphs;
        end;
      ikDefault:
        begin
          FButton.Images := DefaultImages;
          FButton.ImageIndex := DefaultImageIndex;
          { Default glyphs have a default width }
          if Assigned(FButton.Images) and (FButton.ImageIndex >= 0) then
            ButtonWidth := Max(FButton.Images.Width + 6, FButton.Width)
        end;
      ikDropDown:
        if csLoading in ComponentState then
        begin
          if (FStreamedButtonWidth < 0) or FStreamedFixedWidth then
          begin
            ButtonWidth := GetSystemMetrics(SM_CXVSCROLL);
            { Setting ButtonWidth will set FStreamedFixedWidth to False, thus
              reapply it. }
            FStreamedFixedWidth := True;
          end;
        end
        else
        begin
          ButtonWidth := GetSystemMetrics(SM_CXVSCROLL);
          { Setting ButtonWidth will remove the csFixedWidth flag, thus
            reapply it. }
          with FButton do
            ControlStyle := ControlStyle + [csFixedWidth];
        end;
      ikEllipsis: ;
    end;
  end;
end;

procedure TJvCustomComboEdit.SetImages(const Value: TCustomImageList);
begin
  FImages := Value;
  if FImages <> nil then
    FImages.FreeNotification(Self)
  else
    SetImageIndex(-1);
  if ImageKind = ikCustom then
  begin
    FButton.Images := FImages;
    FButton.ImageIndex := FImageIndex;
  end;
end;

procedure TJvCustomComboEdit.SetNumGlyphs(const Value: TNumGlyphs);
begin
  //if FGlyphKind in [gkDropDown, gkEllipsis] then
  //  FButton.NumGlyphs := 1
  //else
  //if FGlyphKind = gkDefault then
  //  FButton.NumGlyphs := FDefNumGlyphs
  //else
  FNumGlyphs := Value;
  if ImageKind = ikCustom then
    FButton.NumGlyphs := Value;
end;

procedure TJvCustomComboEdit.SetPopupValue(const Value: Variant);
begin
  if FPopup is TJvPopupWindow then
    TJvPopupWindow(FPopup).SetValue(Value);
end;

procedure TJvCustomComboEdit.SetReadOnly(Value: Boolean);
begin
  if Value <> FReadOnly then
  begin
    FReadOnly := Value;
    inherited ReadOnly := Value or not FDirectInput;
  end;
end;

procedure TJvCustomComboEdit.SetShowButton(const Value: Boolean);
begin
  if ShowButton <> Value then
  begin
    if Value then
    begin
      { FBtnControl needs to be visible first, otherwise only FSavedButtonWidth
        is changed when setting ButtonWidth }
      FBtnControl.Visible := True;
      ButtonWidth := FSavedButtonWidth
    end
    else
      ButtonWidth := 0;
  end;
end;

procedure TJvCustomComboEdit.SetDataConnector(const Value: TJvCustomComboEditDataConnector);
begin
  if Value <> FDataConnector then
    FDataConnector.Assign(Value);
end;

function TJvCustomComboEdit.CreateDataConnector: TJvCustomComboEditDataConnector;
begin
  Result := TJvCustomComboEditDataConnector.Create(Self);
end;

procedure TJvCustomComboEdit.SetShowCaret;
const
  CaretWidth: array [Boolean] of Integer = (1, 2);
begin
  CreateCaret(Handle, 0, CaretWidth[fsBold in Font.Style], GetTextHeight);
  ShowCaret(Handle);
end;

procedure TJvCustomComboEdit.ShowPopup(Origin: TPoint);
begin
  if FPopup is TJvPopupWindow then
  begin
    TJvPopupWindow(FPopup).Show(Origin);
    if Assigned(FOnPopupShown) then
      FOnPopupShown(Self);
  end;
end;

{$IFDEF VCL}
procedure TJvCustomComboEdit.UpdateAutoComplete;
const
  cAutoCompleteOptionValues: array [TJvAutoCompleteOption] of DWORD =
    (ACO_AUTOSUGGEST, ACO_AUTOAPPEND,
     ACO_SEARCH, ACO_FILTERPREFIXES, ACO_USETAB, ACO_UPDOWNKEYDROPSLIST,
     ACO_RTLREADING);
var
  Flags: DWORD;
  Option: TJvAutoCompleteOption;
  AutoComplete2: IAutoComplete2;
begin
  if HandleAllocated and not (csDesigning in ComponentState) then
  begin
    if Supports(FAutoCompleteIntf, IAutoComplete2, AutoComplete2) then
    begin
      { Set the options of the autocomplete object. }
      Flags := 0;
      for Option := Low(TJvAutoCompleteOption) to High(TJvAutoCompleteOption) do
        if Option in AutoCompleteOptions then
          Inc(Flags, cAutoCompleteOptionValues[Option]);

      AutoComplete2.SetOptions(Flags);
    end;
  end;
end;
{$ENDIF VCL}

{$IFDEF COMPILER6_UP}
procedure TJvCustomComboEdit.UpdateBtnBounds(var NewLeft, NewTop, NewWidth, NewHeight: Integer);
var
  BtnRect: TRect;
begin
  if NewStyleControls then
    {$IFDEF JVCLThemesEnabled}
    if ThemeServices.ThemesEnabled then
    begin
      if BorderStyle = bsSingle then
      begin
        if Ctl3D then
          BtnRect := Bounds(Width - FButton.Width - 2, 0,
            FButton.Width, Height - 2)
        else
          BtnRect := Bounds(Width - FButton.Width - 1, 1,
            FButton.Width, Height - 2);
      end
      else
        BtnRect := Bounds(Width - FButton.Width, 0,
          FButton.Width, Height);
    end
    else
    {$ENDIF JVCLThemesEnabled}
    begin
      if BorderStyle = bsSingle then
      begin
        if not Flat then
          BtnRect := Bounds(Width - FButton.Width - 4, 0,
            FButton.Width, Height - 4)
        else
          BtnRect := Bounds(Width - FButton.Width - 2, 2,
            FButton.Width, Height - 4)
      end
      else
        BtnRect := Bounds(Width - FButton.Width, 0,
          FButton.Width, Height);
    end
  else
    BtnRect := Bounds(Width - FButton.Width, 0, FButton.Width, Height);

  NewLeft := BtnRect.Left;
  NewTop := BtnRect.Top;
  NewWidth := BtnRect.Right - BtnRect.Left;
  NewHeight := BtnRect.Bottom - BtnRect.Top;
end;
{$ENDIF COMPILER6_UP}

procedure TJvCustomComboEdit.UpdateControls;
begin
  { Notification }
end;

procedure TJvCustomComboEdit.UpdateGroup;
var
  I: Integer;
begin
  if (FGroupIndex <> -1) and (Owner <> nil) then
    for I := 0 to Owner.ComponentCount - 1 do
      if Owner.Components[I] is TJvCustomComboEdit then
        with TJvCustomComboEdit(Owner.Components[I]) do
          if (Name <> Self.Name) and (FGroupIndex = Self.FGroupIndex) then
            Clear;
end;

procedure TJvCustomComboEdit.UpdateMargins;
var
  LLeft, LRight, LTop: Integer;
  Loc: TRect;
begin
  { Delay until Loaded and Handle is created }
  if (csLoading in ComponentState) or not HandleAllocated then
    Exit;

  {UpdateMargins gets called whenever the layout of child controls changes.
   It uses GetInternalMargins to determine the left and right margins of the
   actual text area.}

  AdjustHeight;

  LTop := 0;
  LLeft := 0;
  LRight := 0;
  {$IFDEF JVCLThemesEnabled}
  { If flat and themes are enabled, move the left edge of the edit rectangle
    to the right, otherwise the theme edge paints over the border }
  { (rb) This was for a specific font/language; check if this is still necessary }
  if ThemeServices.ThemesEnabled then
  begin
    if BorderStyle = bsSingle then
    begin
      if not Ctl3D then
        LLeft := 3
      else
      begin
        LLeft := 1;
        LTop := 1;
      end;
    end;
  end;
  if ThemeServices.ThemesEnabled then
  begin
  if BorderStyle = bsSingle then
    if Ctl3D then
      LRight := 1
    else
      LRight := -1;
  end
  else
  {$ENDIF JVCLThemesEnabled}
  if (BorderStyle = bsSingle) and not Flat then
    LTop := 2;

  GetInternalMargins(LLeft, LRight);

  {$IFDEF VCL}
  SetRect(Loc, LLeft, LTop, Width - LRight-3, ClientHeight - 1);
  SendRectMessage(Handle, EM_SETRECTNP, 0, Loc);
  // (rb) EM_SETMARGINS necessary?
  //SendMessage(Handle, EM_SETMARGINS, EC_RIGHTMARGIN or EC_LEFTMARGIN, MakeLong(LLeft, LRight));
  {$ENDIF VCL}
  {$IFDEF VisualCLX}
  SetRect(Loc, LLeft, LTop, Width - LRight - LTop-2, Height - 2 * LTop);
  SetEditorRect(@Loc);
  FBtnControl.Left := Loc.Right + 2;
  FBtnControl.Height := Height - 2 * LTop;
  {$ENDIF VisualCLX}
end;

procedure TJvCustomComboEdit.UpdatePopupVisible;
begin
  FPopupVisible := (FPopup <> nil) and FPopup.Visible;
end;

{$IFDEF JVCLThemesEnabled}
procedure TJvCustomComboEdit.WMNCCalcSize(var Msg: TWMNCCalcSize);
begin
  if ThemeServices.ThemesEnabled and Ctl3D and (BorderStyle = bsSingle) then
    with Msg.CalcSize_Params^ do
      InflateRect(rgrc[0], 1, 1);
  inherited;
end;
{$ENDIF JVCLThemesEnabled}

{$IFDEF VCL}
procedure TJvCustomComboEdit.WMNCHitTest(var Msg: TWMNCHitTest);
var
  P: TPoint;
begin
  inherited;
  if (Msg.Result = HTCLIENT) and not (csDesigning in ComponentState) and ShowButton then
  begin
    P := Point(FBtnControl.Left, FBtnControl.Top);
    Windows.ClientToScreen(Handle, P);
    if Msg.XPos > P.X then
      Msg.Result := HTBORDER; {HTCAPTION;}
  end;
end;
{$ENDIF VCL}

{$IFDEF JVCLThemesEnabled}
procedure TJvCustomComboEdit.WMNCPaint(var Msg: TWMNCPaint);
var
  DC: HDC;
  DrawRect: TRect;
  Details: TThemedElementDetails;
begin
  if ThemeServices.ThemesEnabled and Ctl3D and (BorderStyle = bsSingle) then
  begin
    DC := GetWindowDC(Handle);
    try
      GetWindowRect(Handle, DrawRect);
      OffsetRect(DrawRect, -DrawRect.Left, -DrawRect.Top);
      with DrawRect do
        ExcludeClipRect(DC, Left + 1, Top + 1, Right - 1, Bottom - 1);

      Details := ThemeServices.GetElementDetails(teEditTextNormal);
      ThemeServices.DrawElement(DC, Details, DrawRect);
    finally
      ReleaseDC(Handle, DC);
    end;
    Msg.Result := 0;
  end
  else
    inherited;
end;
{$ENDIF JVCLThemesEnabled}

{$IFDEF VCL}
procedure TJvCustomComboEdit.WMPaint(var Msg: TWMPaint);
var
  Canvas: TControlCanvas;
begin
  if csDestroying in ComponentState then
    Exit;
  if Enabled then
    inherited
  else
  begin
    Canvas := nil;
    if not PaintEdit(Self, Text, FAlignment, PopupVisible,
      DisabledTextColor, Focused and not PopupVisible, Canvas, Msg) then
      inherited;
    Canvas.Free;
  end;
end;
{$ENDIF VCL}

{$IFDEF VCL}
procedure TJvCustomComboEdit.WndProc(var Msg: TMessage);
begin
  if (((Msg.Msg >= WM_KEYFIRST) and (Msg.Msg <= WM_KEYLAST)) or (Msg.Msg = WM_CONTEXTMENU)) and
     not SettingCursor and PopupVisible and
    (FPopup is TJvPopupWindow) and Assigned(TJvPopupWindow(FPopup).ActiveControl) then
  begin
    with Msg do
      Result := TJvPopupWindow(FPopup).ActiveControl.Perform(Msg, WParam, LParam);

    if Msg.Result = 0 then
      Exit;
  end;

  { The AutoComplete functionality sends a WM_SETTEXT. But only SetTextBuf()
    generates the required CM_TEXTCHANGED message after the WM_SETTEXT which is
    now missing in this case. The following code ignores the SetTextBuf()
    generated CM_TEXTCHANGE and performs it's own CM_TEXTCHANGE message after
    each WM_SETTEXT. }
  if (Msg.Msg = CM_TEXTCHANGED) and FTextChanged then // ignore the message generated by TControl.SetTextBuf()
  begin
    FTextChanged := False;
    Exit;
  end;

  inherited WndProc(Msg);
  
  if Msg.Msg = WM_SETTEXT then
  begin
    FTextChanged := False;
    Perform(CM_TEXTCHANGED, 0, 0); // generate our own CM_TEXTCHANGED message
    FTextChanged := True;
  end;
end;
{$ENDIF VCL}

//=== { TJvCustomComboEditActionLink } =======================================

function TJvCustomComboEditActionLink.IsCaptionLinked: Boolean;
begin
  Result := False;
end;

function TJvCustomComboEditActionLink.IsHintLinked: Boolean;
begin
  Result := (Action is TCustomAction) and (FClient is TJvCustomComboEdit) and
    ((FClient as TJvCustomComboEdit).ButtonHint = (Action as TCustomAction).Hint);
end;

function TJvCustomComboEditActionLink.IsImageIndexLinked: Boolean;
begin
  Result := inherited IsImageIndexLinked and (FClient is TJvCustomComboEdit) and
    ((FClient as TJvCustomComboEdit).ImageIndex = (Action as TCustomAction).ImageIndex);
end;

function TJvCustomComboEditActionLink.IsOnExecuteLinked: Boolean;
begin
  Result := (Action is TCustomAction) and (FClient is TJvCustomComboEdit) and
    (@(FClient as TJvCustomComboEdit).OnButtonClick = @Action.OnExecute);
end;

function TJvCustomComboEditActionLink.IsShortCutLinked: Boolean;
begin
  Result := inherited IsImageIndexLinked and (FClient is TJvCustomComboEdit) and
    ((FClient as TJvCustomComboEdit).ClickKey = (Action as TCustomAction).ShortCut);
end;

procedure TJvCustomComboEditActionLink.SetHint(const Value: THintString);
begin
  if IsHintLinked then
    (FClient as TJvCustomComboEdit).ButtonHint := Value;
end;

procedure TJvCustomComboEditActionLink.SetImageIndex(Value: Integer);
begin
  if IsImageIndexLinked then
    (FClient as TJvCustomComboEdit).ImageIndex := Value;
end;

procedure TJvCustomComboEditActionLink.SetOnExecute(Value: TNotifyEvent);
begin
  if IsOnExecuteLinked then
    (FClient as TJvCustomComboEdit).OnButtonClick := Value;
end;

procedure TJvCustomComboEditActionLink.SetShortCut(Value: TShortCut);
begin
  if IsShortCutLinked then
    (FClient as TJvCustomComboEdit).ClickKey := Value;
end;

//=== { TJvCustomDateEditDataConnector } =====================================

procedure TJvCustomDateEditDataConnector.Assign(Source: TPersistent);
begin
  inherited Assign(Source);
  if Source is TJvCustomDateEditDataConnector then
  begin
    FDefaultDate := TJvCustomDateEditDataConnector(Source).FDefaultDate;
    FDefaultDateIsNow := TJvCustomDateEditDataConnector(Source).DefaultDateIsNow;
  end;
end;

function TJvCustomDateEditDataConnector.IsDefaultDateStored: Boolean;
begin
  Result := FDefaultDate <> 0;
end;

procedure TJvCustomDateEditDataConnector.RecordChanged;
begin
  if Field.IsValid then
  begin
    Control.ReadOnly := not Field.CanModify;
    TJvCustomDateEdit(Control).Date := Field.AsDataTime;
  end
  else
    inherited RecordChanged;
end;

procedure TJvCustomDateEditDataConnector.SetDefaultDateIsNow(const Value: Boolean);
begin
  if Value <> FDefaultDateIsNow then
    FDefaultDateIsNow := Value;
end;

procedure TJvCustomDateEditDataConnector.UpdateData;
begin
  if TJvCustomDateEdit(Control).Date = 0 then
  begin
    if DefaultDateIsNow then
      Field.AsDataTime := Now
    else
    if NullDate <> 0 then
      Field.AsDataTime := DefaultDate
    else
      Field.Clear;
  end
  else
    Field.AsDataTime := TJvCustomDateEdit(Control).Date;
  TJvCustomDateEdit(Control).Date := Field.AsDataTime; // update
end;

//=== { TJvCustomDateEdit } ==================================================

constructor TJvCustomDateEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  // Polaris
  FDateAutoBetween := True;
  FMinDate := NullDate;
  FMaxDate := NullDate;

  FBlanksChar := ' ';
  FTitle := RsDateDlgCaption;
  {$IFDEF VCL}
  FPopupColor := clMenu;
  {$ENDIF VCL}
  {$IFDEF VisualCLX}
  FPopupColor := clWindow;
  {$ENDIF VisualCLX}
  //  FDefNumGlyphs := 2;
  FStartOfWeek := Mon;
  FWeekends := [Sun];
  FWeekendColor := clRed;
  FYearDigits := dyDefault;
  FCalendarHints := TStringList.Create;
  FCalendarHints.OnChange := CalendarHintsChanged;
  {$IFDEF VCL}
  DateHook.Add;
  {$ENDIF VCL}
  FCustomDateFormat := GetDefaultDateFormat;
  FDateFormatPreferred := GetDefaultDateFormatPreferred;

  ControlState := ControlState + [csCreating];
  try
    UpdateFormat;
    {$IFDEF DEFAULT_POPUP_CALENDAR}
    FPopup := TJvPopupWindow(CreatePopupCalendar(Self,
      {$IFDEF VCL} BiDiMode, {$ENDIF}{$IFDEF VisualCLX} bdLeftToRight, {$ENDIF}
      // Polaris
      FMinDate, FMaxDate));
    TJvPopupWindow(FPopup).OnCloseUp := PopupCloseUp;
    TJvPopupWindow(FPopup).Color := FPopupColor;
    {$ENDIF DEFAULT_POPUP_CALENDAR}
    ImageKind := ikDefault; { force update }
  finally
    ControlState := ControlState - [csCreating];
  end;
end;

destructor TJvCustomDateEdit.Destroy;
begin
  {$IFDEF VCL}
  DateHook.Delete;
  {$ENDIF VCL}

  if FPopup is TJvPopupWindow then
  begin
    TJvPopupWindow(FPopup).OnCloseUp := nil;
    FPopup.Parent := nil;
  end;
  FPopup.Free;
  FPopup := nil;
  FCalendarHints.OnChange := nil;
  FCalendarHints.Free;
  FCalendarHints := nil;
  inherited Destroy;
end;

function TJvCustomDateEdit.CreateDataConnector: TJvCustomComboEditDataConnector;
begin
  Result := TJvCustomDateEditDataConnector.Create(Self);
end;

function TJvCustomDateEdit.AcceptPopup(var Value: Variant): Boolean;
var
  D: TDateTime;
begin
  Result := True;
  if Assigned(FOnAcceptDate) then
  begin
    if VarIsNull(Value) or VarIsEmpty(Value) then
      D := NullDate
    else
    try
      D := VarToDateTime(Value);
    except
      if DefaultToday then
        D := SysUtils.Date
      else
        D := NullDate;
    end;
    FOnAcceptDate(Self, D, Result);
    if Result then
      Value := VarFromDateTime(D);
  end;
end;

procedure TJvCustomDateEdit.AcceptValue(const Value: Variant);
begin
  SetDate(VarToDateTime(Value));
  UpdatePopupVisible;
  if Modified then
    inherited Change;
end;

procedure TJvCustomDateEdit.ApplyDate(Value: TDateTime);
begin
  SetDate(Value);
  SelectAll;
end;

procedure TJvCustomDateEdit.CalendarHintsChanged(Sender: TObject);
begin
  FCalendarHints.OnChange := nil;
  try
    while CalendarHints.Count > 4 do
      CalendarHints.Delete(CalendarHints.Count - 1);
  finally
    FCalendarHints.OnChange := CalendarHintsChanged;
  end;
  if not (csDesigning in ComponentState) then
    UpdatePopup;
end;

procedure TJvCustomDateEdit.Change;
begin
  if not FFormatting then
    inherited Change;
end;

// Polaris

procedure TJvCustomDateEdit.CheckValidDate;
var
  ADate: TDateTime;
begin
  if TextStored then
  try
    FFormatting := True;
    try
      SetDate(StrToDateFmt(FDateFormat, Text));
    finally
      FFormatting := False;
    end;
  except
    if FDateFormat2 <> '' then
    try
      FFormatting := True;
      try
        SetDate(StrToDateFmt(FDateFormat2, Text));
      finally
        FFormatting := False;
      end;
    except
      if CanFocus then
        SetFocus;
      ADate := Self.Date;
      if DoInvalidDate(Text,ADate) then
        Self.Date := ADate
      else
        raise;
    end
    else
    begin
      if CanFocus then
        SetFocus;
      ADate := Self.Date;
      if DoInvalidDate(Text,ADate) then
        Self.Date := ADate
      else
        raise;
    end;
  end;
end;

{$IFDEF VisualCLX}
procedure TJvCustomDateEdit.CreateWidget;
begin
  inherited CreateWidget;
  if HandleAllocated then
    UpdateMask;
end;
{$ENDIF VisualCLX}

{$IFDEF VCL}
procedure TJvCustomDateEdit.CreateWindowHandle(const Params: TCreateParams);
begin
  inherited CreateWindowHandle(Params);
  if Handle <> 0 then
    UpdateMask;
end;
{$ENDIF VCL}

class function TJvCustomDateEdit.DefaultImageIndex: TImageIndex;
var
  Bmp: TBitmap;
begin
  if GDateImageIndex < 0 then
  begin
    Bmp := TBitmap.Create;
    try
      Bmp.LoadFromResourceName(HInstance, sDateBmp);
      GDateImageIndex := DefaultImages.AddMasked(Bmp, clFuchsia);
    finally
      Bmp.Free;
    end;
  end;

  Result := GDateImageIndex;
end;

procedure TJvCustomDateEdit.DoExit;
begin
  if not (csDesigning in ComponentState) and CheckOnExit then
    CheckValidDate;
  inherited DoExit;
end;

function TJvCustomDateEdit.DoInvalidDate(const DateString: string; var ANewDate: TDateTime): Boolean;
begin
  Result := False;
  if Assigned(FOnInvalidDate) then
    FOnInvalidDate(Self, DateString, ANewDate, Result);
end;

function TJvCustomDateEdit.FourDigitYear: Boolean;
begin
  Result := (FYearDigits = dyFour) or ((FYearDigits = dyDefault) and IsFourDigitYear);
end;

function TJvCustomDateEdit.GetCalendarHints: TStrings;
begin
  Result := FCalendarHints;
end;

function TJvCustomDateEdit.GetCalendarStyle: TCalendarStyle;
begin
  if FPopup <> nil then
    Result := csPopup
  else
    Result := csDialog;
end;

function TJvCustomDateEdit.GetDate: TDateTime;
begin
  if DefaultToday then
    Result := SysUtils.Date
  else
    Result := NullDate;
  Result := StrToDateFmtDef(FDateFormat, Text, Result);
end;

function TJvCustomDateEdit.GetDateFormat: string;
begin
  Result := FDateFormat;
end;

function TJvCustomDateEdit.GetDateMask: string;
begin
  Result := DefDateMask(FBlanksChar, FourDigitYear);
end;

function TJvCustomDateEdit.GetDialogTitle: string;
begin
  Result := FTitle;
end;

function TJvCustomDateEdit.GetPopupColor: TColor;
begin
  if FPopup is TJvPopupWindow then
    Result := TJvPopupWindow(FPopup).Color
  else
    Result := FPopupColor;
end;

function TJvCustomDateEdit.IsCustomTitle: Boolean;
begin
  {$IFDEF CLR}
  Result := (CompareStr(RsDateDlgCaption, DialogTitle) <> 0) and (DialogTitle <> ''); // Polaris
  {$ELSE}
  Result := (AnsiCompareStr(RsDateDlgCaption, DialogTitle) <> 0) and (DialogTitle <> ''); // Polaris
  {$ENDIF CLR}
end;

function TJvCustomDateEdit.IsDateStored: Boolean;
begin
  Result := not DefaultToday;
end;

procedure TJvCustomDateEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
  if not ReadOnly then
  begin
    if IsInWordArray(Key, [VK_PRIOR, VK_NEXT, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN,
      VK_ADD, VK_SUBTRACT, VK_RETURN]) and PopupVisible then
    begin
      if FPopup is TJvPopupWindow then
        TJvPopupWindow(FPopup).KeyDown(Key, Shift);
      Key := 0;
    end
    else
    if (Shift = []) and DirectInput then
    begin
      case Key of
        VK_ADD:
          begin
            ApplyDate(NvlDate(Date, Now) + 1);
            Key := 0;
          end;
        VK_SUBTRACT:
          begin
            ApplyDate(NvlDate(Date, Now) - 1);
            Key := 0;
          end;
      end;
    end;
  end;
  inherited KeyDown(Key, Shift);
end;

procedure TJvCustomDateEdit.KeyPress(var Key: Char);
begin
  if not ReadOnly then
  begin
    if (Key in ['T', 't', '+', '-']) and PopupVisible then
    begin
      if FPopup is TJvPopupWindow then
        TJvPopupWindow(FPopup).KeyPress(Key);
      Key := #0;
    end
    else
    if DirectInput then
      case Key of
        'T', 't':
          begin
            ApplyDate(Trunc(Now));
            Key := #0;
          end;
        '+', '-':
          Key := #0;
      end;
  end;
  inherited KeyPress(Key);
end;

procedure TJvCustomDateEdit.PopupDropDown(DisableEdit: Boolean);
var
  D: TDateTime;
  Action: Boolean;
begin
  if CalendarStyle = csDialog then
  begin
    D := Self.Date;
    Action := SelectDate(Self, D, DialogTitle, StartOfWeek, Weekends, // Polaris (Self added)
      WeekendColor, CalendarHints, MinDate, MaxDate); // Polaris
    if CanFocus then
      SetFocus;
    if Action then
    begin
      if Assigned(FOnAcceptDate) then
        FOnAcceptDate(Self, D, Action);
      if Action then
      begin
        Self.Date := D;
        if FFocused then
          inherited SelectAll;
      end;
    end;
  end
  else
    inherited PopupDropDown(DisableEdit);
end;

procedure TJvCustomDateEdit.SetParent(AParent: TWinControl);
begin
  // This is here to help debugging parenting issues such as Mantis 3042
  inherited SetParent(AParent);
end;

procedure TJvCustomDateEdit.SetBlanksChar(Value: Char);
begin
  if Value <> FBlanksChar then
  begin
    if Value < ' ' then
      Value := ' ';
    FBlanksChar := Value;
    UpdateMask;
  end;
end;

procedure TJvCustomDateEdit.SetCalendarHints(Value: TStrings);
begin
  FCalendarHints.Assign(Value);
end;

procedure TJvCustomDateEdit.SetCalendarStyle(Value: TCalendarStyle);
begin
  if Value <> CalendarStyle then
    case Value of
      csPopup:
        begin
          if FPopup = nil then
            FPopup := TJvPopupWindow(CreatePopupCalendar(Self,
              {$IFDEF VCL} BiDiMode, {$ENDIF}{$IFDEF VisualCLX} bdLeftToRight, {$ENDIF}
              FMinDate, FMaxDate)); // Polaris
          TJvPopupWindow(FPopup).OnCloseUp := PopupCloseUp;
          TJvPopupWindow(FPopup).Color := FPopupColor;
          UpdatePopup;
        end;
      csDialog:
        FreeAndNil(FPopup);
    end;
end;

// Polaris

procedure TJvCustomDateEdit.SetDate(Value: TDateTime);
var
  D: TDateTime;
  SavedModified: Boolean;
begin
  if not ValidDate(Value) or (Value = NullDate) then
    if DefaultToday then
      Value := SysUtils.Date
    else
      Value := NullDate;
  D := Self.Date;
  SavedModified := Modified;
  TestDateBetween(Value); // Polaris
  if Value = NullDate then
    Text := ''
  else
    Text := FormatDateTime(FDateFormat, Value);
  Modified := SavedModified or (D <> Self.Date);
end;

procedure TJvCustomDateEdit.SetDateAutoBetween(Value: Boolean);
var
  D: TDateTime;
begin
  if Value <> FDateAutoBetween then
  begin
    FDateAutoBetween := Value;
    if Value then
    begin
      D := Date;
      TestDateBetween(D);
      if D <> Date then
        Date := D;
    end;
    Invalidate;
  end;
end;

procedure TJvCustomDateEdit.SetDialogTitle(const Value: string);
begin
  FTitle := Value;
end;

procedure TJvCustomDateEdit.SetMaxDate(Value: TDateTime);
begin
  if Value <> FMaxDate then
  begin
    //Check unacceptable MaxDate < MinDate
    if (Value <> NullDate) and (FMinDate <> NullDate) and (Value < FMinDate) then
      if FDateAutoBetween then
        SetMinDate(Value)
      else
        {$IFDEF CLR}
        raise EJVCLException.CreateFmt(RsEDateMaxLimit, [DateToStr(FMinDate)]);
        {$ELSE}
        raise EJVCLException.CreateResFmt(@RsEDateMaxLimit, [DateToStr(FMinDate)]);
        {$ENDIF CLR}
    FMaxDate := Value;
    UpdatePopup;
    if FDateAutoBetween then
      SetDate(Date);
  end;
end;

procedure TJvCustomDateEdit.SetMinDate(Value: TDateTime);
begin
  if Value <> FMinDate then
  begin
    //!!!!! Necessarily check

    // Check unacceptable MinDate > MaxDate [Translated]
    if (Value <> NullDate) and (FMaxDate <> NullDate) and (Value > FMaxDate) then
      if FDateAutoBetween then
        SetMaxDate(Value)
      else
        {$IFDEF CLR}
        raise EJVCLException.CreateFmt(RsEDateMinLimit, [DateToStr(FMaxDate)]);
        {$ELSE}
        raise EJVCLException.CreateResFmt(@RsEDateMinLimit, [DateToStr(FMaxDate)]);
        {$ENDIF CLR}
    FMinDate := Value;
    UpdatePopup;
    if FDateAutoBetween then
      SetDate(Date);
  end;
end;

procedure TJvCustomDateEdit.SetPopupColor(Value: TColor);
begin
  if Value <> PopupColor then
  begin
    if FPopup is TJvPopupWindow then
      TJvPopupWindow(FPopup).Color := Value;
    FPopupColor := Value;
  end;
end;

procedure TJvCustomDateEdit.SetPopupValue(const Value: Variant);
begin
  inherited SetPopupValue(StrToDateFmtDef(FDateFormat, VarToStr(Value), SysUtils.Date));
end;

procedure TJvCustomDateEdit.SetStartOfWeek(Value: TDayOfWeekName);
begin
  if Value <> FStartOfWeek then
  begin
    FStartOfWeek := Value;
    UpdatePopup;
  end;
end;

procedure TJvCustomDateEdit.SetWeekendColor(Value: TColor);
begin
  if Value <> FWeekendColor then
  begin
    FWeekendColor := Value;
    UpdatePopup;
  end;
end;

procedure TJvCustomDateEdit.SetWeekends(Value: TDaysOfWeek);
begin
  if Value <> FWeekends then
  begin
    FWeekends := Value;
    UpdatePopup;
  end;
end;

function TJvCustomDateEdit.GetDefaultDateFormat: string;
begin
  Result := '';
end;

function TJvCustomDateEdit.IsDateFormatStored: Boolean;
begin
  Result := (FCustomDateFormat <> GetDefaultDateFormat);
end;

function TJvCustomDateEdit.GetDefaultDateFormatPreferred: TPreferredDateFormat;
begin
  Result := pdLocaleOnly;
end;

function TJvCustomDateEdit.IsDateFormatPreferredStored: Boolean;
begin
  Result := (FDateFormatPreferred <> GetDefaultDateFormatPreferred);
end;

procedure TJvCustomDateEdit.SetDateFormatPreferred(Value: TPreferredDateFormat);
begin
  if FDateFormatPreferred <> Value then
  begin
    FDateFormatPreferred := Value;
    if not (csLoading in ComponentState) then
      UpdateMask;
  end;
end;

procedure TJvCustomDateEdit.SetCustomDateFormat(const Value: string);
begin
  if FCustomDateFormat <> Value then
  begin
    FCustomDateFormat := Value;
    if not (csLoading in ComponentState) then
    begin
      if FDateFormatPreferred in [pdCustom, pdCustomOnly] then
        UpdateMask
      else
        UpdateFormat;
    end;
  end;
end;

procedure TJvCustomDateEdit.SetYearDigits(Value: TYearDigits);
begin
  if FYearDigits <> Value then
  begin
    FYearDigits := Value;
    UpdateMask;
  end;
end;

function TJvCustomDateEdit.StoreMaxDate: Boolean;
begin
  Result := FMaxDate <> NullDate;
end;

function TJvCustomDateEdit.StoreMinDate: Boolean;
begin
  Result := FMinDate <> NullDate;
end;

procedure TJvCustomDateEdit.TestDateBetween(var Value: TDateTime);
begin
  if FDateAutoBetween then
  begin
    if (FMinDate <> NullDate) and (Value <> NullDate) and (Value < FMinDate) then
      Value := FMinDate;
    if (FMaxDate <> NullDate) and (Value <> NullDate) and (Value > FMaxDate) then
      Value := FMaxDate;
  end;
end;

function TJvCustomDateEdit.TextStored: Boolean;
begin
  {$IFDEF CLR}
  Result := not IsEmptyStr(Text, [#0, ' ', AnsiChar(DateSeparator[1]), AnsiChar(FBlanksChar)]);
  {$ELSE}
  Result := not IsEmptyStr(Text, [#0, ' ', DateSeparator, FBlanksChar]);
  {$ENDIF CLR}
end;

procedure TJvCustomDateEdit.UpdateFormat;
begin
  if (FDateFormatPreferred in [pdLocale, pdLocaleOnly]) or (FCustomDateFormat = '') then
  begin
    FDateFormat := DefDateFormat(FourDigitYear);
    if FDateFormatPreferred = pdLocale then
      FDateFormat2 := FCustomDateFormat
    else
      FDateFormat2 := '';
  end
  else
  begin
    FDateFormat := FCustomDateFormat;
    if FDateFormatPreferred = pdCustom then
      FDateFormat2 := DefDateFormat(FourDigitYear)
    else
      FDateFormat2 := '';
  end;
end;

procedure TJvCustomDateEdit.UpdateMask;
var
  DateValue: TDateTime;
  OldFormat: string[10];
begin
  DateValue := GetDate;
  OldFormat := FDateFormat;
  UpdateFormat;
  if (GetDateMask <> EditMask) or (OldFormat <> FDateFormat) then
  begin
    { force update }
    EditMask := '';
    EditMask := GetDateMask;
  end;
  UpdatePopup;
  SetDate(DateValue);
end;

procedure TJvCustomDateEdit.UpdatePopup;
begin
  if FPopup <> nil then
    SetupPopupCalendar(FPopup, StartOfWeek,
      Weekends, WeekendColor, CalendarHints, FourDigitYear,
      MinDate, MaxDate); // Polaris
end;

procedure TJvCustomDateEdit.ValidateEdit;
begin
  if TextStored then
    CheckValidDate;
end;

{$IFDEF VCL}
procedure TJvCustomDateEdit.WMContextMenu(var Msg: TWMContextMenu);
begin
  if not PopupVisible then
    inherited;
end;
{$ENDIF VCL}

//=== { TJvDateEdit } ========================================================

// (rom) unusual not to have it implemented in the Custom base class

constructor TJvDateEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  UpdateMask;
end;

procedure TJvDateEdit.SetDate(Value: TDateTime);
begin
  if not FDateAutoBetween then
    if Value <> NullDate then
    begin
      if ((FMinDate <> NullDate) and (FMaxDate <> NullDate) and
        ((Value < FMinDate) or (Value > FMaxDate))) then
        {$IFDEF CLR}
        raise EJVCLException.CreateFmt(RsEDateOutOfRange, [FormatDateTime(FDateFormat, Value),
        {$ELSE}
        raise EJVCLException.CreateResFmt(@RsEDateOutOfRange, [FormatDateTime(FDateFormat, Value),
        {$ENDIF CLR}
          FormatDateTime(FDateFormat, FMinDate), FormatDateTime(FDateFormat, FMaxDate)])
      else
      if (FMinDate <> NullDate) and (Value < FMinDate) then
        {$IFDEF CLR}
        raise EJVCLException.CreateFmt(RsEDateOutOfMin, [FormatDateTime(FDateFormat, Value),
        {$ELSE}
        raise EJVCLException.CreateResFmt(@RsEDateOutOfMin, [FormatDateTime(FDateFormat, Value),
        {$ENDIF CLR}
          FormatDateTime(FDateFormat, FMinDate)])
      else
      if (FMaxDate <> NullDate) and (Value > FMaxDate) then
        {$IFDEF CLR}
        raise EJVCLException.CreateFmt(RsEDateOutOfMax, [FormatDateTime(FDateFormat, Value),
        {$ELSE}
        raise EJVCLException.CreateResFmt(@RsEDateOutOfMax, [FormatDateTime(FDateFormat, Value),
        {$ENDIF CLR}
          FormatDateTime(FDateFormat, FMaxDate)]);
    end;
  inherited SetDate(Value);
end;

//=== { TJvDirectoryEdit } ===================================================

constructor TJvDirectoryEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  {$IFDEF VCL}
  FOptions := [sdAllowCreate];
  FAutoCompleteFileOptions := [acfFileSystem, acfFileSysDirs];
  {$ENDIF VCL}
  FDialogKind := dkWin32;
end;

class function TJvDirectoryEdit.DefaultImageIndex: TImageIndex;
var
  Bmp: TBitmap;
begin
  {$IFDEF JVCLThemesEnabled}
  if ThemeServices.ThemesEnabled then
  begin
    if GDirImageIndexXP < 0 then
    begin
      Bmp := TBitmap.Create;
      try
        Bmp.LoadFromResourceName(HInstance, sDirXPBmp);
        GDirImageIndexXP := DefaultImages.AddMasked(Bmp, clFuchsia);
      finally
        Bmp.Free;
      end;
    end;
    Result := GDirImageIndexXP;
    Exit;
  end;
  {$ENDIF JVCLThemesEnabled}

  if GDirImageIndex < 0 then
  begin
    Bmp := TBitmap.Create;
    try
      Bmp.LoadFromResourceName(HInstance, sDirBmp);
      GDirImageIndex := DefaultImages.AddMasked(Bmp, clFuchsia);
    finally
      Bmp.Free;
    end;
  end;
  Result := GDirImageIndex;
end;

function TJvDirectoryEdit.GetLongName: string;
var
  Temp: string;
  Pos: Integer;
begin
  if not MultipleDirs then
    Result := ShortToLongPath(Text)
  else
  begin
    Result := '';
    Pos := 1;
    while Pos <= Length(Text) do
    begin
      Temp := ShortToLongPath(ExtractSubstr(Text, Pos, [PathSep]));
      if (Result <> '') and (Temp <> '') then
        Result := Result + PathSep;
      Result := Result + Temp;
    end;
  end;
end;

function TJvDirectoryEdit.GetShortName: string;
var
  Temp: string;
  Pos: Integer;
begin
  if not MultipleDirs then
    Result := LongToShortPath(Text)
  else
  begin
    Result := '';
    Pos := 1;
    while Pos <= Length(Text) do
    begin
      Temp := LongToShortPath(ExtractSubstr(Text, Pos, [PathSep]));
      if (Result <> '') and (Temp <> '') then
        Result := Result + PathSep;
      Result := Result + Temp;
    end;
  end;
end;

procedure TJvDirectoryEdit.PopupDropDown(DisableEdit: Boolean);
var
  Temp: string;
  {$IFDEF VisualCLX}
  TempW: WideString;
  {$ENDIF VisualCLX}
  Action: Boolean;
begin
  Temp := Text;
  Action := True;
  DoBeforeDialog(Temp, Action);
  if not Action then
    Exit;
  if Temp = '' then
  begin
    if InitialDir <> '' then
      Temp := InitialDir
    else
      Temp := PathDelim;
  end;
  if not DirectoryExists(Temp) then
    Temp := PathDelim;
  DisableSysErrors;
  try
    {$IFDEF VCL}
    {$IFNDEF CLR}
    if NewStyleControls and (DialogKind = dkWin32) then
      Action := BrowseForFolder(FDialogText, sdAllowCreate in DialogOptions, Temp, Self.HelpContext)
    else
    {$ENDIF !CLR}
      Action := SelectDirectory(Temp, FOptions, Self.HelpContext);
    {$ENDIF VCL}
    {$IFDEF VisualCLX}
    begin
      Action := SelectDirectory(FDialogText, Temp, TempW);
      Temp := TempW;
    end;
    {$ENDIF VisualCLX}
  finally
    EnableSysErrors;
  end;
  if CanFocus then
    SetFocus;
  DoAfterDialog(Temp, Action);
  if Action then
  begin
    SelText := '';
    if (Text = '') or not MultipleDirs then
      Text := Temp
    else
      Text := Text + PathSep + Temp;
    if (Temp <> '') and DirectoryExists(Temp) then
      InitialDir := Temp;
  end;
end;

procedure TJvDirectoryEdit.ReceptFileDir(const AFileName: string);
var
  Temp: string;
begin
  if FileExists(AFileName) then
    Temp := ExtractFilePath(AFileName)
  else
    Temp := AFileName;
  if (Text = '') or not MultipleDirs then
    Text := Temp
  else
    Text := Text + PathSep + Temp;
end;

//=== { TJvEditButton } ======================================================

constructor TJvEditButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FStandard := True; // Polaris
  ControlStyle := ControlStyle + [csReplicatable];
  ParentShowHint := True;
end;

procedure TJvEditButton.Click;
begin
  if not FNoAction then
    inherited Click
  else
    FNoAction := False;
end;

function TJvEditButton.GetGlyph: TBitmap;
begin
  Result := ButtonGlyph.Glyph;
end;

function TJvEditButton.GetNumGlyphs: TJvNumGlyphs;
begin
  Result := ButtonGlyph.NumGlyphs;
end;

function TJvEditButton.GetUseGlyph: Boolean;
begin
  Result := not Assigned(Images) or (ImageIndex < 0);
end;

procedure TJvEditButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  inherited MouseDown(Button, Shift, X, Y);
  if (Button = mbLeft) and (Owner <> nil) then
    with TJvCustomComboEdit(Owner) do
    begin
      FNoAction := (FPopup <> nil) and FPopupVisible;
      if not FPopupVisible then
      begin
        if TabStop and CanFocus and (GetFocus <> Handle) then
          SetFocus;
      end
      else
        PopupCloseUp(FPopup, FStandard); // Polaris
    end;
end;

procedure TJvEditButton.Paint;
{$IFDEF JVCLThemesEnabled}
var
  ThemedState: TThemedComboBox;
  Details: TThemedElementDetails;
  R: TRect;
{$ENDIF JVCLThemesEnabled}
begin
  {$IFDEF JVCLThemesEnabled}
  if ThemeServices.ThemesEnabled then
  begin
    if FDrawThemedDropDownBtn then
    begin
      if not Enabled then
        ThemedState := tcDropDownButtonDisabled
      else
      if FState in [rbsDown, rbsExclusive] then
        ThemedState := tcDropDownButtonPressed
      else
      if MouseOver or IsDragging then
        ThemedState := tcDropDownButtonHot
      else
        ThemedState := tcDropDownButtonNormal;
      R := ClientRect;
      Details := ThemeServices.GetElementDetails(ThemedState);
      ThemeServices.DrawElement(Canvas.Handle, Details, R);
    end
    else
      inherited Paint;
  end
  else
  {$ENDIF JVCLThemesEnabled}
  begin
     inherited Paint;
    if FState <> rbsDown then
      with Canvas do
      begin
        if NewStyleControls then
          Pen.Color := clBtnFace
        else
          Pen.Color := clBtnShadow;
        MoveTo(0, 0);
        LineTo(0, Self.Height - 1);
        Pen.Color := clBtnHighlight;
        MoveTo(1, 1);
        LineTo(1, Self.Height - 2);
      end;
  end;
end;

procedure TJvEditButton.PaintImage(Canvas: TCanvas; ARect: TRect;
  const Offset: TPoint; AState: TJvButtonState; DrawMark: Boolean);
begin
  if UseGlyph then
    ButtonGlyph.Draw(Canvas, ARect, Offset, '', Layout,
      Margin, Spacing, False, AState, 0)
  else
    inherited PaintImage(Canvas, ARect, Offset, AState, DrawMark);
end;

procedure TJvEditButton.SetGlyph(const Value: TBitmap);
begin
  ButtonGlyph.Glyph := Value;
  Invalidate;
end;

procedure TJvEditButton.SetNumGlyphs(Value: TJvNumGlyphs);
begin
  if Value < 0 then
    Value := 1
  else
  if Value > Ord(High(TJvButtonState)) + 1 then
    Value := Ord(High(TJvButtonState)) + 1;
  if Value <> ButtonGlyph.NumGlyphs then
  begin
    ButtonGlyph.NumGlyphs := Value;
    Invalidate;
  end;
end;

{$IFDEF VCL}
procedure TJvEditButton.WMContextMenu(var Msg: TWMContextMenu);
begin
  { (rb) Without this, we get 2 context menu's (1 from the form, another from
         the combo edit; don't know exactly what is causing this. (I guess
         it's related to FBtnControl being a TWinControl) }
  Msg.Result := 1;
end;
{$ENDIF VCL}

//=== { TJvFileDirEdit } =====================================================

constructor TJvFileDirEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  {$IFDEF VCL}
  OEMConvert := True;
  FAcceptFiles := True;
  FAutoCompleteOptions := [acoAutoSuggest];
  {$ENDIF VCL}
  ControlState := ControlState + [csCreating];
  try
    ImageKind := ikDefault; { force update }
  finally
    ControlState := ControlState - [csCreating];
  end;
end;

procedure TJvFileDirEdit.Change;
var
  Ps: Integer;
begin
  // The control becomes confused when the Text property has a #10 or #13 in it.
  Ps := Pos(#10, Text);
  if Ps = 0 then
    Ps := Pos(#13, Text);
  if Ps > 0 then
    Text := Copy(Text, 1, Ps - 1)
  else
    inherited Change;
end;

procedure TJvFileDirEdit.ClearFileList;
begin
end;

{$IFDEF JVCLThemesEnabled}
procedure TJvFileDirEdit.CMSysColorChange(var Msg: TMessage);
begin
  inherited;
  // We use this event to respond to theme changes (no WM_THEMECHANGED are broadcasted
  // to the components)
  // Note that there is a bug in TApplication.WndProc, so the application will not
  // change from non-themed to themed.
  if ImageKind = ikDefault then
    Button.ImageIndex := DefaultImageIndex;
end;
{$ENDIF JVCLThemesEnabled}

{$IFDEF VCL}

procedure TJvFileDirEdit.CreateHandle;
begin
  inherited CreateHandle;

  if FAcceptFiles then
    SetDragAccept(True);
end;

procedure TJvFileDirEdit.DestroyWindowHandle;
begin
  SetDragAccept(False);
  inherited DestroyWindowHandle;
end;

{$ENDIF VCL}

procedure TJvFileDirEdit.DisableSysErrors;
begin
  {$IFDEF MSWINDOWS}
  FErrMode := SetErrorMode(SEM_NOOPENFILEERRORBOX or SEM_FAILCRITICALERRORS);
  {$ENDIF MSWINDOWS}
end;

procedure TJvFileDirEdit.DoAfterDialog(var FileName: string; var Action: Boolean);
begin
  if Assigned(FOnAfterDialog) then
    FOnAfterDialog(Self, FileName, Action);
end;

procedure TJvFileDirEdit.DoBeforeDialog(var FileName: string; var Action: Boolean);
begin
  if Assigned(FOnBeforeDialog) then
    FOnBeforeDialog(Self, FileName, Action);
end;

procedure TJvFileDirEdit.EnableSysErrors;
begin
  {$IFDEF MSWINDOWS}
  SetErrorMode(FErrMode);
  {$ENDIF MSWINDOWS}
  FErrMode := 0;
end;

{$IFDEF VCL}

function TJvFileDirEdit.GetAutoCompleteSource: IEnumString;
begin
  {$IFDEF CLR}
  FAutoCompleteSourceIntf :=
    Activator.CreateInstance(System.Type.GetTypeFromCLSID(Guid.Create(CLSID_ACLMulti))) as IEnumString;
  {$ELSE}
  if Failed(CoCreateInstance(CLSID_ACLMulti, nil, CLSCTX_INPROC_SERVER, IEnumString, FAutoCompleteSourceIntf)) then
    FAutoCompleteSourceIntf := nil;
  {$ENDIF CLR}
  Result := FAutoCompleteSourceIntf;
end;

procedure TJvFileDirEdit.SetAcceptFiles(Value: Boolean);
begin
  if FAcceptFiles <> Value then
  begin
    SetDragAccept(Value);
    FAcceptFiles := Value;
  end;
end;

procedure TJvFileDirEdit.SetAutoCompleteFileOptions(const Value: TJvAutoCompleteFileOptions);
begin
  if FAutoCompleteFileOptions <> Value then
  begin
    FAutoCompleteFileOptions := Value;
    if not (csDesigning in ComponentState) then
      UpdateAutoComplete;
  end;
end;

procedure TJvFileDirEdit.SetDragAccept(Value: Boolean);
begin
  if not (csDesigning in ComponentState) and (Handle <> 0) then
    DragAcceptFiles(Handle, Value);
end;

procedure TJvFileDirEdit.DestroyAutoComplete;
begin
  // Mantis 3112: We drop the references we get to the various interfaces
  // thus avoiding accesses to them triggered by the ancestor(s) destructor(s)
  FMRUList := nil;
  FHistoryList := nil;
  FFileSystemList:= nil;
  FAutoCompleteSourceIntf := nil;

  inherited DestroyAutoComplete;
end;

procedure TJvFileDirEdit.UpdateAutoComplete;
var
  ObjMgr: IObjMgr;
  List2: IACList2;
  Options: DWORD;
begin
  if Supports(FAutoCompleteSourceIntf, IObjMgr, ObjMgr) then
  begin
    if acfURLMRU in AutoCompleteFileOptions then
    begin
      if not Assigned(FMRUList) and
        {$IFDEF CLR}
        SucceededCom(FMRUList,
          Activator.CreateInstance(System.Type.GetTypeFromCLSID(Guid.Create(CLSID_ACLMRU)))) then
        {$ELSE}
        Succeeded(CoCreateInstance(CLSID_ACLMRU, nil, CLSCTX_INPROC_SERVER, IUnknown, FMRUList)) then
        {$ENDIF CLR}
      begin
        ObjMgr.Append(FMRUList);
      end
    end
    else
    if Assigned(FMRUList) then
    begin
      ObjMgr.Remove(FMRUList);
      FMRUList := nil;
    end;

    if acfURLHistory in AutoCompleteFileOptions then
    begin
      if not Assigned(FHistoryList) and
        {$IFDEF CLR}
        SucceededCom(FHistoryList,
          Activator.CreateInstance(System.Type.GetTypeFromCLSID(Guid.Create(CLSID_ACLHistory)))) then
        {$ELSE}
        Succeeded(CoCreateInstance(CLSID_ACLHistory, nil, CLSCTX_INPROC_SERVER, IUnknown, FHistoryList)) then
        {$ENDIF CLR}
      begin
        ObjMgr.Append(FHistoryList);
      end;
    end
    else
    if Assigned(FHistoryList) then
    begin
      ObjMgr.Remove(FHistoryList);
      FHistoryList := nil;
    end;

    if [acfFileSystem, acfFileSysDirs] * AutoCompleteFileOptions <> [] then
    begin
      if not Assigned(FFileSystemList) and
        {$IFDEF CLR}
        SucceededCom(FFileSystemList,
          Activator.CreateInstance(System.Type.GetTypeFromCLSID(Guid.Create(CLSID_ACListISF)))) then
        {$ELSE}
        Succeeded(CoCreateInstance(CLSID_ACListISF, nil, CLSCTX_INPROC_SERVER, IUnknown, FFileSystemList)) then
        {$ENDIF CLR}
      begin
        ObjMgr.Append(FFileSystemList);
      end;

      Options := ACLO_FILESYSONLY;
      if acfFileSysDirs in AutoCompleteFileOptions then
        Options := Options or ACLO_FILESYSDIRS;

      if Supports(FFileSystemList, IACList2, List2) then
        List2.SetOptions(Options);
    end
    else
    if Assigned(FFileSystemList) then
    begin
      ObjMgr.Remove(FFileSystemList);
      FFileSystemList := nil;
    end;
  end;

  inherited UpdateAutoComplete;
end;

procedure TJvFileDirEdit.WMDropFiles(var Msg: TWMDropFiles);
var
  {$IFDEF CLR}
  AFileName: StringBuilder;
  {$ELSE}
  AFileName: array [0..255] of Char;
  {$ENDIF CLR}
  I, Num: Cardinal;
begin
  Msg.Result := 0;
  try
    Num := DragQueryFile(Msg.Drop, $FFFFFFFF, nil, 0);
    if Num > 0 then
    begin
      ClearFileList;
      for I := 0 to Num - 1 do
      begin
        {$IFDEF CLR}
        AFileName := StringBuilder.Create(256);
        DragQueryFile(Msg.Drop, I, AFileName, 255);
        ReceptFileDir(AFileName.ToString());
        {$ELSE}
        DragQueryFile(Msg.Drop, I, PChar(@AFileName), Pred(SizeOf(AFileName)));
        ReceptFileDir(StrPas(AFileName));
        {$ENDIF CLR}
        if not FMultipleDirs then
          Break;
      end;
      if Assigned(FOnDropFiles) then
        FOnDropFiles(Self);
    end;
  finally
    DragFinish(Msg.Drop);
  end;
end;

{$ENDIF VCL}

//=== { TJvFilenameEdit } ====================================================

constructor TJvFilenameEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FAddQuotes := True;
  {$IFDEF VCL}
  FAutoCompleteFileOptions := [acfFileSystem];
  {$ENDIF VCL}
  CreateEditDialog;
end;

procedure TJvFilenameEdit.ClearFileList;
begin
  FDialog.Files.Clear;
end;

procedure TJvFilenameEdit.CreateEditDialog;
var
  NewDialog: TOpenDialog;
begin
  case FDialogKind of
    dkOpen:
      NewDialog := TOpenDialog.Create(Self);
    dkOpenPicture:
      NewDialog := TOpenPictureDialog.Create(Self);
    dkSavePicture:
      NewDialog := TSavePictureDialog.Create(Self);
  else { dkSave }
    NewDialog := TSaveDialog.Create(Self);
  end;
  try
    if FDialog <> nil then
    begin
      with NewDialog do
      begin
        DefaultExt := FDialog.DefaultExt;
        {$IFDEF VCL}
        FileEditStyle := FDialog.FileEditStyle;
        {$ENDIF VCL}
        FileName := FDialog.FileName;
        Filter := FDialog.Filter;
        FilterIndex := FDialog.FilterIndex;
        InitialDir := FDialog.InitialDir;
        HistoryList := FDialog.HistoryList;
        Files.Assign(FDialog.Files);
        Options := FDialog.Options;
        Title := FDialog.Title;
      end;
      FDialog.Free;
    end
    else
    begin
      NewDialog.Title := RsBrowseCaption;
      NewDialog.Filter := RsDefaultFilter;
      NewDialog.Options := [ofHideReadOnly];
    end;
  finally
    FDialog := NewDialog;
  end;
end;

class function TJvFilenameEdit.DefaultImageIndex: TImageIndex;
var
  Bmp: TBitmap;
begin
  {$IFDEF JVCLThemesEnabled}
  if ThemeServices.ThemesEnabled then
  begin
    if GFileImageIndexXP < 0 then
    begin
      Bmp := TBitmap.Create;
      try
        Bmp.LoadFromResourceName(HInstance, sFileXPBmp);
        GFileImageIndexXP := DefaultImages.AddMasked(Bmp, clFuchsia);
      finally
        Bmp.Free;
      end;
    end;
    Result := GFileImageIndexXP;
    Exit;
  end;
  {$ENDIF JVCLThemesEnabled}

  if GFileImageIndex < 0 then
  begin
    Bmp := TBitmap.Create;
    try
      Bmp.LoadFromResourceName(HInstance, sFileBmp);
      GFileImageIndex := DefaultImages.AddMasked(Bmp, clFuchsia);
    finally
      Bmp.Free;
    end;
  end;
  Result := GFileImageIndex;
end;

function TJvFilenameEdit.GetDefaultExt: TFileExt;
begin
  Result := FDialog.DefaultExt;
end;

function TJvFilenameEdit.GetDialogFiles: TStrings;
begin
  Result := FDialog.Files;
end;

function TJvFilenameEdit.GetDialogTitle: string;
begin
  Result := FDialog.Title;
end;

{$IFDEF VCL}
function TJvFilenameEdit.GetFileEditStyle: TFileEditStyle;
begin
  Result := FDialog.FileEditStyle;
end;
{$ENDIF VCL}

function TJvFilenameEdit.GetFileName: TFileName;
begin
  Result := ClipFilename(inherited Text, AddQuotes);
end;

function TJvFilenameEdit.GetFilter: string;
begin
  Result := FDialog.Filter;
end;

function TJvFilenameEdit.GetFilterIndex: Integer;
begin
  Result := FDialog.FilterIndex;
end;

function TJvFilenameEdit.GetHistoryList: TStrings;
begin
  Result := FDialog.HistoryList;
end;

function TJvFilenameEdit.GetInitialDir: string;
begin
  Result := FDialog.InitialDir;
end;

function TJvFilenameEdit.GetLongName: string;
begin
  Result := ShortToLongFileName(FileName);
end;

function TJvFilenameEdit.GetOptions: TOpenOptions;
begin
  Result := FDialog.Options;
end;

function TJvFilenameEdit.GetShortName: string;
begin
  Result := LongToShortFileName(FileName);
end;

function TJvFilenameEdit.IsCustomFilter: Boolean;
begin
  {$IFDEF CLR}
  Result := CompareStr(RsDefaultFilter, FDialog.Filter) <> 0;
  {$ELSE}
  Result := AnsiCompareStr(RsDefaultFilter, FDialog.Filter) <> 0;
  {$ENDIF CLR}
end;

function TJvFilenameEdit.IsCustomTitle: Boolean;
begin
  {$IFDEF CLR}
  Result := CompareStr(RsBrowseCaption, FDialog.Title) <> 0;
  {$ELSE}
  Result := AnsiCompareStr(RsBrowseCaption, FDialog.Title) <> 0;
  {$ENDIF CLR}
end;

procedure TJvFilenameEdit.PopupDropDown(DisableEdit: Boolean);
var
  Temp: string;
  Action: Boolean;
begin
  Action := True;
  Temp := FileName;
  DoBeforeDialog(Temp, Action);
  if not Action then
    Exit;
  if ValidFileName(Temp) then
  try
    if DirectoryExists(ExtractFilePath(Temp)) then
      SetInitialDir(ExtractFilePath(Temp));
    if (ExtractFileName(Temp) = '') or
      not ValidFileName(ExtractFileName(Temp)) then
      Temp := '';
    FDialog.FileName := Temp;
  except
    { ignore any exceptions }
  end;
  FDialog.HelpContext := Self.HelpContext;
  DisableSysErrors;
  try
    Action := FDialog.Execute;
  finally
    EnableSysErrors;
  end;
  if Action then
    Temp := FDialog.FileName;
  if CanFocus then
    SetFocus;
  DoAfterDialog(Temp, Action);
  if Action then
  begin
    if AddQuotes then
      inherited Text := ExtFilename(Temp)
    else
      inherited Text := Temp;
    SetInitialDir(ExtractFilePath(FDialog.FileName));
  end;
end;

procedure TJvFilenameEdit.ReceptFileDir(const AFileName: string);
begin
  if FMultipleDirs then
  begin
    if FDialog.Files.Count = 0 then
      SetFileName(AFileName);
    FDialog.Files.Add(AFileName);
  end
  else
    SetFileName(AFileName);
end;

procedure TJvFilenameEdit.SetDefaultExt(Value: TFileExt);
begin
  FDialog.DefaultExt := Value;
end;

procedure TJvFilenameEdit.SetDialogKind(Value: TFileDialogKind);
begin
  if FDialogKind <> Value then
  begin
    FDialogKind := Value;
    CreateEditDialog;
  end;
end;

procedure TJvFilenameEdit.SetDialogTitle(const Value: string);
begin
  FDialog.Title := Value;
end;

{$IFDEF VCL}
procedure TJvFilenameEdit.SetFileEditStyle(Value: TFileEditStyle);
begin
  FDialog.FileEditStyle := Value;
end;
{$ENDIF VCL}

procedure TJvFilenameEdit.SetFileName(const Value: TFileName);
begin
  if (Value = '') or ValidFileName(ClipFilename(Value, AddQuotes)) then
  begin
    if AddQuotes then
      inherited Text := ExtFilename(Value)
    else
      inherited Text := Value;
    ClearFileList;
  end
  else
    {$IFDEF CLR}
    raise EComboEditError.CreateFmt(SInvalidFilename, [Value]);
    {$ELSE}
    raise EComboEditError.CreateResFmt(@SInvalidFilename, [Value]);
    {$ENDIF CLR}
end;

procedure TJvFilenameEdit.SetFilter(const Value: string);
begin
  FDialog.Filter := Value;
end;

procedure TJvFilenameEdit.SetFilterIndex(Value: Integer);
begin
  FDialog.FilterIndex := Value;
end;

procedure TJvFilenameEdit.SetHistoryList(Value: TStrings);
begin
  FDialog.HistoryList := Value;
end;

procedure TJvFilenameEdit.SetInitialDir(const Value: string);
begin
  FDialog.InitialDir := Value;
end;

procedure TJvFilenameEdit.SetOptions(Value: TOpenOptions);
begin
  if Value <> FDialog.Options then
  begin
    FDialog.Options := Value;
    FMultipleDirs := ofAllowMultiSelect in FDialog.Options;
    if not FMultipleDirs then
      ClearFileList;
  end;
end;

//=== { TJvPopupWindow } =====================================================

constructor TJvPopupWindow.Create(AOwner: TComponent);
begin
  {$IFDEF VisualCLX}
  // (p3) have to use CreateNew for VCL as well since there is no dfm
  inherited CreateNew(AOwner);
  {$ELSE}
  inherited Create(AOwner);
  {$ENDIF VisualCLX}

  FEditor := AOwner as TWinControl;
  ControlStyle := ControlStyle + [csNoDesignVisible, csReplicatable];

  // If we were to add csAcceptsControls at design time, any attempt
  // to paste a component while a component using TJvPopupWindow is active
  // would lead to the parent of the pasted component being set to the
  // TJvPopupWindow instead of the parent of the selected component.
  // This was reported in issue 3042 and was seen in TJvCustomDateEdit
  // descendents
  if not (csDesigning in ComponentState) then
    ControlStyle := ControlStyle + [csAcceptsControls];
  Visible := False;
  {$IFDEF VCL}
  Ctl3D := False;
  ParentCtl3D := False;
  Parent := FEditor;
  // use same size on small and large font:
  //Scaled := False;
  {$ENDIF VCL}
end;

procedure TJvPopupWindow.CloseUp(Accept: Boolean);
begin
  if Assigned(FCloseUp) then
    FCloseUp(Self, Accept);
end;

{$IFDEF CLR}

{ Allow this unit to access protected members of anchestors. }
procedure TJvPopupWindow.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited KeyDown(Key, Shift);
end;

procedure TJvPopupWindow.KeyPress(var Key: Char);
begin
  inherited KeyPress(Key);
end;

{$ENDIF CLR}

{$IFDEF VCL}
procedure TJvPopupWindow.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do
  begin
    Style := WS_POPUP or WS_BORDER or WS_CLIPCHILDREN;
    ExStyle := WS_EX_TOOLWINDOW;
    WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  end;
end;
{$ENDIF VCL}

function TJvPopupWindow.GetPopupText: string;
begin
  Result := '';
end;

procedure TJvPopupWindow.Hide;
begin
  {$IFDEF VCL}
  SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
    SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
  {$ENDIF VCL}
  Visible := False;
end;

procedure TJvPopupWindow.InvalidateEditor;
var
  R: TRect;
begin
  if FEditor is TJvCustomComboEdit then
    with TJvCustomComboEdit(FEditor) do
      SetRect(R, 0, 0, ClientWidth - FBtnControl.Width {Polaris - 2}, ClientHeight + 1)
  else
    R := FEditor.ClientRect;
  {$IFDEF CLR}
  InvalidateRect(FEditor.Handle, R, False);
  {$ELSE}
  {$IFDEF VCL}
  InvalidateRect(FEditor.Handle, @R, False);
  {$ENDIF VCL}
  {$IFDEF VisualCLX}
  FEditor.InvalidateRect(R, False);
  {$ENDIF VisualCLX}
  {$ENDIF CLR}
  UpdateWindow(FEditor.Handle);
end;

procedure TJvPopupWindow.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited MouseUp(Button, Shift, X, Y);
  if Button = mbLeft then
    CloseUp(PtInRect(ClientRect, Point(X, Y)));
end;

{$IFDEF VisualCLX}
procedure TJvPopupWindow.SetParent(const Value: TWidgetControl);
var
  Pt: TPoint;
  R: TRect;
begin
  Pt := Point(Left, Top);
  R := BoundsRect;
  inherited SetParent(Value);
  if not (csDestroying in ComponentState) then
  begin
    QWidget_reparent(Handle, nil, 0, @Pt, Showing);
    BoundsRect := R;
  end;
end;
{$ENDIF VisualCLX}

procedure TJvPopupWindow.Show(Origin: TPoint);
begin
  SetBounds(Origin.X, Origin.Y, Width, Height);
  {$IFDEF VCL}
  SetWindowPos(Handle, HWND_TOP, Origin.X, Origin.Y, 0, 0,
    SWP_NOACTIVATE or SWP_SHOWWINDOW or SWP_NOSIZE);
  {$ENDIF VCL}
  Visible := True;
end;

{$IFDEF VisualCLX}
function TJvPopupWindow.WidgetFlags: Integer;
begin
  Result := Integer(WidgetFlags_WType_Popup) or // WS_POPUP
    Integer(WidgetFlags_WStyle_NormalBorder) or // WS_BORDER
    Integer(WidgetFlags_WStyle_Tool);  // WS_EX_TOOLWINDOW
end;
{$ENDIF VisualCLX}

{$IFDEF VCL}
procedure TJvPopupWindow.WMActivate(var Msg: TWMActivate);
begin
  inherited;
  if Msg.Active = WA_INACTIVE then
  begin
    if FEditor is TJvCustomComboEdit then
      TJvCustomComboEdit(FEditor).AsyncPopupCloseUp(False)
    else
      CloseUp(False);
  end;
end;
{$ENDIF VCL}

{$IFDEF VCL}
procedure TJvPopupWindow.WMMouseActivate(var Msg: TMessage);
begin
  if FIsFocusable then
    inherited
  else
    Msg.Result := MA_NOACTIVATE;
end;
{$ENDIF VCL}

initialization
  {$IFDEF UNITVERSIONING}
  RegisterUnitVersion(HInstance, UnitVersioning);
  {$ENDIF UNITVERSIONING}

finalization
  {$IFNDEF CLR}
  {$IFDEF VCL}
  FreeAndNil(GDateHook);
  {$ENDIF VCL}
  FreeAndNil(GDefaultComboEditImagesList);
  {$ENDIF !CLR}
  {$IFDEF UNITVERSIONING}
  UnregisterUnitVersion(HInstance);
  {$ENDIF UNITVERSIONING}

end.
