home *** CD-ROM | disk | FTP | other *** search
/ Delphi 5 for Professionals / DELPHI5.iso / AddOns / Components / Essentials / SETUP.EXE / %MAINDIR% / EsDbEd.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-11-28  |  27.1 KB  |  1,096 lines

  1. {*********************************************************}
  2. {*                   ESDBED.PAS 1.05                     *}
  3. {*      Copyright (c) 1997-98 TurboPower Software Co     *}
  4. {*                 All rights reserved.                  *}
  5. {*********************************************************}
  6.  
  7. {$I ES.INC}
  8.  
  9. {$B-} {Complete Boolean Evaluation}
  10. {$I+} {Input/Output-Checking}
  11. {$P+} {Open Parameters}
  12. {$T-} {Typed @ Operator}
  13. {$W-} {Windows Stack Frame}
  14. {$X+} {Extended Syntax}
  15.  
  16. {$IFNDEF Win32}
  17.   {$G+} {286 Instructions}
  18.   {$N+} {Numeric Coprocessor}
  19.   {$C MOVEABLE,DEMANDLOAD,DISCARDABLE}
  20. {$ENDIF}
  21.  
  22. unit EsDbEd;
  23.   {-data-aware calculator and calendar popup edit controls}
  24.  
  25. interface
  26.  
  27. uses
  28.   {$IFDEF Win32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  29.   Classes, Controls, DB, DbCtrls, DBTables, Forms, Graphics, Menus,
  30.   Messages, StdCtrls,
  31.   EsBase, EsCal, EsCalc, EsEdCal, EsEdCalc, EsEdPop;
  32.  
  33. const
  34.   {field type supported by the number edit field}
  35.   NumFieldTypes : set of  TFieldType =
  36.     [ftSmallInt, ftInteger, ftWord, ftFloat, ftCurrency, ftBCD];
  37.   {field type supported by the date edit field}
  38.   DateFieldTypes : set of  TFieldType = [ftDate, ftDateTime];
  39.  
  40. type
  41.   TEsCustomDbNumberEdit = class(TEsCustomNumberEdit)
  42.   protected {private}
  43.     {.Z+}
  44.     FAlignment : TAlignment;
  45.     FCanvas    : TControlCanvas;
  46.     FDataLink  : TFieldDataLink;
  47.     FFocused   : Boolean;
  48.  
  49.     {property methods}
  50.     function GetDataField : string;
  51.     function GetDataSource : TDataSource;
  52.     function GetField : TField;
  53.     function GetReadOnly : Boolean;
  54.     procedure SetDataField(const Value : string);
  55.     procedure SetDataSource(Value : TDataSource);
  56.     procedure SetFocused(Value : Boolean);
  57.     procedure SetReadOnly(Value : Boolean);
  58.  
  59.     {internal methods}
  60.     procedure DataChange(Sender : TObject);
  61.     procedure EditingChange(Sender : TObject);
  62.     function GetTextMargins : TPoint;
  63.     procedure UpdateData(Sender : TObject);
  64.  
  65.     {message methods}
  66.     procedure WMCut(var Message : TMessage);
  67.       message WM_CUT;
  68.     procedure WMPaste(var Message : TMessage);
  69.       message WM_PASTE;
  70.     procedure WMPaint(var Message : TWMPaint);
  71.       message WM_PAINT;
  72.     procedure CMEnter(var Message : TCMEnter);
  73.       message CM_ENTER;
  74.     procedure CMExit(var Message : TCMExit);
  75.       message CM_EXIT;
  76.     {$IFDEF Win32}
  77.     procedure CMGetDataLink(var Message : TMessage);
  78.       message CM_GETDATALINK;
  79.     {$ENDIF Win32}
  80.     {.Z-}
  81.  
  82.   protected
  83.     {.Z+}
  84.     procedure Change;
  85.       override;
  86.     function GetButtonEnabled : Boolean;                               {!!.03}
  87.       override;
  88.     procedure KeyDown(var Key : Word; Shift : TShiftState);
  89.       override;
  90.     procedure KeyPress(var Key : Char);
  91.       override;
  92.     procedure Notification(AComponent : TComponent; Operation : TOperation);
  93.       override;
  94.     procedure PopupClose(Sender : TObject);
  95.       override;
  96.     {.Z-}
  97.  
  98.     {protected properties}
  99.     property DataField : string
  100.       read GetDataField
  101.       write SetDataField;
  102.  
  103.     property DataSource : TDataSource
  104.       read GetDataSource
  105.       write SetDataSource;
  106.  
  107.     property ReadOnly : Boolean {hides ancestor's ReadOnly property}
  108.       read GetReadOnly
  109.       write SetReadOnly
  110.       default False;
  111.  
  112.   public
  113.     {.Z+}
  114.     constructor Create(AOwner : TComponent);
  115.       override;
  116.     destructor Destroy;
  117.       override;
  118.     procedure PopupOpen;                                               {!!.05}
  119.       override;
  120.     {.Z-}
  121.  
  122.     {public properties}
  123.     property Field : TField
  124.       read GetField;
  125.   end;
  126.  
  127.   TEsDbNumberEdit = class(TEsCustomDbNumberEdit)
  128.   published
  129.     {properties}
  130.     property AllowIncDec;
  131.     property AutoSelect;
  132.     property AutoSize;
  133.     property BorderStyle;
  134.     property Color;
  135.     property Ctl3D;
  136.     property Cursor;
  137.     property DataField;
  138.     property DataSource;
  139.     property DragCursor;
  140.     property DragMode;
  141.     property Enabled;
  142.     property EsLabelInfo;
  143.     property Font;
  144.     property HideSelection;
  145.     property ParentColor;
  146.     property ParentCtl3D;
  147.     property ParentFont;
  148.     property ParentShowHint;
  149.     property PopupCalcColors;
  150.     property PopupCalcHeight;
  151.     property PopupCalcFont;                                            {!!.02}
  152.     property PopupCalcWidth;
  153.     property PopupMenu;
  154.     property ReadOnly;
  155.     property ShowButton;
  156.     property ShowHint;
  157.     property TabOrder;
  158.     property TabStop;
  159.     property Version;
  160.     property Visible;
  161.  
  162.     {events}
  163.     property OnChange;
  164.     property OnClick;
  165.     property OnDblClick;
  166.     property OnDragDrop;
  167.     property OnDragOver;
  168.     property OnEndDrag;
  169.     property OnEnter;
  170.     property OnExit;
  171.     property OnKeyDown;
  172.     property OnKeyPress;
  173.     property OnKeyUp;
  174.     property OnMouseDown;
  175.     property OnMouseMove;
  176.     property OnMouseUp;
  177.     {$IFDEF Win32}
  178.     property OnStartDrag;
  179.     {$ENDIF Win32}
  180.   end;
  181.  
  182.   TEsCustomDbDateEdit = class(TEsCustomDateEdit)
  183.   protected {private}
  184.     {.Z+}
  185.     FAlignment : TAlignment;
  186.     FCanvas    : TControlCanvas;
  187.     FDataLink  : TFieldDataLink;
  188.     FFocused   : Boolean;
  189.  
  190.     {property methods}
  191.     function GetDataField : string;
  192.     function GetDataSource : TDataSource;
  193.     function GetField : TField;
  194.     function GetReadOnly : Boolean;
  195.     procedure SetDataField(const Value : string);
  196.     procedure SetDataSource(Value : TDataSource);
  197.     procedure SetFocused(Value : Boolean);
  198.     procedure SetReadOnly(Value : Boolean);
  199.  
  200.     {internal methods}
  201.     procedure DataChange(Sender : TObject);
  202.     procedure EditingChange(Sender : TObject);
  203.     function GetTextMargins : TPoint;
  204.     procedure UpdateData(Sender : TObject);
  205.  
  206.     {message methods}
  207.     procedure WMCut(var Message : TMessage);
  208.       message WM_CUT;
  209.     procedure WMPaste(var Message : TMessage);
  210.       message WM_PASTE;
  211.     procedure WMPaint(var Message : TWMPaint);
  212.       message WM_PAINT;
  213.     procedure CMEnter(var Message : TCMEnter);
  214.       message CM_ENTER;
  215.     procedure CMExit(var Message : TCMExit);
  216.       message CM_EXIT;
  217.     {$IFDEF Win32}
  218.     procedure CMGetDataLink(var Message : TMessage);
  219.       message CM_GETDATALINK;
  220.     {$ENDIF Win32}
  221.     {.Z-}
  222.  
  223.   protected
  224.     {.Z+}
  225.     procedure Change;
  226.       override;
  227.     function GetButtonEnabled : Boolean;                               {!!.03}
  228.       override;
  229.     procedure KeyDown(var Key : Word; Shift : TShiftState);
  230.       override;
  231.     procedure KeyPress(var Key : Char);
  232.       override;
  233.     procedure Notification(AComponent : TComponent; Operation : TOperation);
  234.       override;
  235.     procedure PopupClose(Sender : TObject);
  236.       override;
  237.     {.Z-}
  238.  
  239.     {protected properties}
  240.     property DataField : string
  241.       read GetDataField
  242.       write SetDataField;
  243.  
  244.     property DataSource : TDataSource
  245.       read GetDataSource
  246.       write SetDataSource;
  247.  
  248.     property ReadOnly : Boolean {hides ancestor's ReadOnly property}
  249.       read GetReadOnly
  250.       write SetReadOnly
  251.       default False;
  252.  
  253.   public
  254.     {.Z+}
  255.     constructor Create(AOwner : TComponent);
  256.       override;
  257.     destructor Destroy;
  258.       override;
  259.     procedure PopupOpen;                                               {!!.05}
  260.       override;
  261.     {.Z-}
  262.  
  263.     {public properties}
  264.     property Field : TField
  265.       read GetField;
  266.   end;
  267.  
  268.   TEsDbDateEdit = class(TEsCustomDbDateEdit)
  269.   published
  270.     {properties}
  271.     property AllowIncDec;
  272.     property AutoSelect;
  273.     property AutoSize;
  274.     property BorderStyle;
  275.     property CharCase;
  276.     property Color;
  277.     property Ctl3D;
  278.     property Cursor;
  279.     property DataField;
  280.     property DataSource;
  281.     property DragCursor;
  282.     property DragMode;
  283.     property Enabled;
  284.     property Epoch;                                                    {!!.04}
  285.     property EsLabelInfo;
  286.     property Font;
  287.     property ForceCentury;                                             {!!.04}
  288.     property HideSelection;
  289.     property ParentColor;
  290.     property ParentCtl3D;
  291.     property ParentFont;
  292.     property ParentShowHint;
  293.     property PopupMenu;
  294.     property PopupCalColors;
  295.     property PopupCalHeight;
  296.     property PopupCalFont;                                             {!!.02}
  297.     property PopupCalWidth;
  298.     property ReadOnly;
  299.     property RequiredFields;
  300.     property ShowButton;
  301.     property ShowHint;
  302.     property TabOrder;
  303.     property TabStop;
  304.     property TodayString;
  305.     property Version;
  306.     property Visible;
  307.     property WeekStarts;                                               {!!.02}
  308.  
  309.     {events}
  310.     property OnChange;
  311.     property OnClick;
  312.     property OnDblClick;
  313.     property OnDragDrop;
  314.     property OnDragOver;
  315.     property OnEndDrag;
  316.     property OnEnter;
  317.     property OnExit;
  318.     property OnKeyDown;
  319.     property OnKeyPress;
  320.     property OnKeyUp;
  321.     property OnMouseDown;
  322.     property OnMouseMove;
  323.     property OnMouseUp;
  324.     {$IFDEF Win32}
  325.     property OnStartDrag;
  326.     {$ENDIF Win32}
  327.   end;
  328.  
  329.  
  330. implementation
  331.  
  332.  
  333. {$IFDEF TRIALRUN}
  334. uses
  335.   EsTrial;
  336. {$I ESTRIALF.INC}
  337. {$ENDIF}
  338.  
  339.  
  340. {*** TEsCustomDbNumberEdit ***}
  341.  
  342. procedure TEsCustomDbNumberEdit.Change;
  343. begin
  344.   FDataLink.Modified;
  345.  
  346.   inherited Change;
  347. end;
  348.  
  349. procedure TEsCustomDbNumberEdit.CMEnter(var Message : TCMEnter);
  350. begin
  351.   SetFocused(True);
  352.  
  353.   inherited;
  354. end;
  355.  
  356. procedure TEsCustomDbNumberEdit.CMExit(var Message : TCMExit);
  357. begin
  358.   if PopupActive then
  359.     Exit;
  360.  
  361.   try
  362.     if Modified then                                                   {!!.04}
  363.       FDataLink.UpdateRecord;
  364.   except
  365.     SelectAll;
  366.     SetFocus;
  367.     raise;
  368.   end;
  369.   SetFocused(False);
  370.   DoExit;
  371. end;
  372.  
  373. {$IFDEF Win32}
  374. procedure TEsCustomDbNumberEdit.CMGetDataLink(var Message : TMessage);
  375. begin
  376.   Message.Result := Integer(FDataLink);
  377. end;
  378. {$ENDIF Win32}
  379.  
  380. constructor TEsCustomDbNumberEdit.Create(AOwner : TComponent);
  381. {$IFDEF TRIALRUN}
  382. var
  383.   X : Integer;
  384. {$ENDIF}
  385. begin
  386.   inherited Create(AOwner);
  387.  
  388.   inherited ReadOnly := True;
  389.  
  390.   {$IFDEF Win32}
  391.   ControlStyle := ControlStyle + [csReplicatable];
  392.   {$ENDIF Win32}
  393.  
  394.   FDataLink := TFieldDataLink.Create;
  395.   FDataLink.Control := Self;
  396.   FDataLink.OnDataChange := DataChange;
  397.   FDataLink.OnEditingChange := EditingChange;
  398.   FDataLink.OnUpdateData := UpdateData;
  399.  
  400. {$IFDEF TRIALRUN}
  401.   X := _CC_;
  402.   if (X < ccRangeLow) or (X > ccRangeHigh) then Halt;
  403.   X := _VC_;
  404.   if (X < ccRangeLow) or (X > ccRangeHigh) then Halt;
  405. {$ENDIF}
  406. end;
  407.  
  408. procedure TEsCustomDbNumberEdit.DataChange(Sender : TObject);
  409. var
  410.   P : Integer;
  411.   S : string[80];
  412. begin
  413.   if FDataLink.Field <> nil then begin
  414.     if FAlignment <> FDataLink.Field.Alignment then begin
  415.       FAlignment := FDataLink.Field.Alignment;
  416.       Text := '';
  417.     end;
  418.     if FDataLink.Field.DataType in NumFieldTypes then begin
  419.       if FFocused and FDataLink.CanModify then
  420.         Text := FDataLink.Field.Text
  421.       else
  422.         Text := FDataLink.Field.DisplayText;
  423.     end else begin
  424.       S := FDataLink.Field.ClassName;
  425.       S[1] := '(';
  426.       P := Pos('Field', S);
  427.       if P > 0 then begin
  428.         S[P] := ')';
  429.         S[0] := Char(P);
  430.       end else
  431.         S := Concat(S, ')');
  432.       Text := S;
  433.     end;
  434.   end else begin
  435.     FAlignment := taLeftJustify;
  436.     if csDesigning in ComponentState then
  437.       Text := Name
  438.     else
  439.       Text := '';
  440.   end;
  441. end;
  442.  
  443. destructor TEsCustomDbNumberEdit.Destroy;
  444. begin
  445.   FDataLink.Free;
  446.   FDataLink := nil;
  447.  
  448.   FCanvas.Free;
  449.   FCanvas := nil;
  450.  
  451.   inherited Destroy;
  452. end;
  453.  
  454. procedure TEsCustomDbNumberEdit.EditingChange(Sender : TObject);
  455. begin
  456.   inherited ReadOnly := not FDataLink.Editing;
  457.   FButton.Enabled := GetButtonEnabled;                                 {!!.03}
  458. end;
  459.  
  460. {!!.03}
  461. function TEsCustomDbNumberEdit.GetButtonEnabled : Boolean;
  462. begin
  463.   Result := (FDataLink <> nil) and (FDataLink.DataSource <> nil) and
  464.     (FDataLink.Editing or FDataLink.DataSource.AutoEdit) or
  465.     (csDesigning in ComponentState);
  466. end;
  467.  
  468. function TEsCustomDbNumberEdit.GetDataField : string;
  469. begin
  470.   Result := FDataLink.FieldName;
  471. end;
  472.  
  473. function TEsCustomDbNumberEdit.GetDataSource : TDataSource;
  474. begin
  475.   Result := FDataLink.DataSource;
  476. end;
  477.  
  478. function TEsCustomDbNumberEdit.GetField : TField;
  479. begin
  480.   Result := FDataLink.Field;
  481. end;
  482.  
  483. function TEsCustomDbNumberEdit.GetReadOnly : Boolean;
  484. begin
  485.   Result := FDataLink.ReadOnly;
  486.   if FDataLink.Field <> nil then
  487.     if not (FDataLink.Field.DataType in NumFieldTypes) then
  488.       Result := True;
  489. end;
  490.  
  491. function TEsCustomDbNumberEdit.GetTextMargins : TPoint;
  492. var
  493.   DC         : HDC;
  494.   SaveFont   : HFont;
  495.   I          : Integer;
  496.   SysMetrics : TTextMetric;
  497.   Metrics    : TTextMetric;
  498. begin
  499.   if NewStyleControls then begin
  500.     if BorderStyle = bsNone then
  501.       I := 0
  502.     else if Ctl3D then
  503.       I := 1
  504.     else
  505.       I := 2;
  506.     {$IFDEF Win32}
  507.     Result.X := SendMessage(Handle, EM_GETMARGINS, 0, 0) and $0000FFFF + I;
  508.     {$ELSE}
  509.     Result.X := 2;
  510.     {$ENDIF Win32}
  511.     Result.Y := I;
  512.   end else begin
  513.     if BorderStyle = bsNone then
  514.       I := 0
  515.     else begin
  516.       DC := GetDC(0);
  517.       GetTextMetrics(DC, SysMetrics);
  518.       SaveFont := SelectObject(DC, Font.Handle);
  519.       GetTextMetrics(DC, Metrics);
  520.       SelectObject(DC, SaveFont);
  521.       ReleaseDC(0, DC);
  522.       I := SysMetrics.tmHeight;
  523.       if I > Metrics.tmHeight then
  524.         I := Metrics.tmHeight;
  525.       I := I div 4;
  526.     end;
  527.     Result.X := I;
  528.     Result.Y := I;
  529.   end;
  530. end;
  531.  
  532. procedure TEsCustomDbNumberEdit.KeyDown(var Key : Word; Shift : TShiftState);
  533. begin
  534.   inherited KeyDown(Key, Shift);
  535.  
  536.   {start edit mdoe if cutting or pasting}
  537.   if (Key = VK_DELETE) or ((Key = VK_INSERT) and (ssShift in Shift)) then
  538.     FDataLink.Edit;
  539. end;
  540.  
  541. procedure TEsCustomDbNumberEdit.KeyPress(var Key : Char);
  542. begin
  543.   if AllowIncDec and (Key in ['+', '-']) then
  544.     FDataLink.Edit;
  545.  
  546.   inherited KeyPress(Key);
  547.  
  548.   if (Key in [#32..#255]) and (FDataLink.Field <> nil) and
  549.      not FDataLink.Field.IsValidChar(Key) then begin
  550.     MessageBeep(0);
  551.     Key := #0;
  552.   end;
  553.  
  554.   case Key of
  555.     ^H, ^V, ^X, #32..#255 :
  556.       FDataLink.Edit;
  557.     #27:
  558.       begin
  559.         FDataLink.Reset;
  560.         SelectAll;
  561.         Key := #0;
  562.       end;
  563.   end;
  564. end;
  565.  
  566. procedure TEsCustomDbNumberEdit.Notification(AComponent : TComponent; Operation : TOperation);
  567. begin
  568.   inherited Notification(AComponent, Operation);
  569.  
  570.   if (Operation = opRemove) and (FDataLink <> nil) and (AComponent = DataSource) then
  571.     DataSource := nil;
  572. end;
  573.  
  574. procedure TEsCustomDbNumberEdit.PopupClose(Sender : TObject);
  575. begin
  576.   inherited PopupClose(Sender);
  577.  
  578.   {allow control to see focus change that was blocked when popup became active}
  579.   if not Focused then
  580.     Perform(CM_EXIT, 0, 0);
  581. end;
  582.  
  583. {!!.03}
  584. procedure TEsCustomDbNumberEdit.PopupOpen;
  585. begin
  586.   if FDataLink.Edit then  {enter edit mode}
  587.     inherited PopupOpen
  588.   else begin
  589.     MessageBeep(0);
  590.     SetFocus;
  591.   end;
  592. end;
  593.  
  594. procedure TEsCustomDbNumberEdit.SetDataField(const Value : string);
  595. begin
  596.   try
  597.     FDataLink.FieldName := Value;
  598.   except
  599.     FDataLink.FieldName := '';
  600.     raise;
  601.   end;
  602. end;
  603.  
  604. procedure TEsCustomDbNumberEdit.SetDataSource(Value : TDataSource);
  605. begin
  606.   FDataLink.DataSource := Value;
  607.   {$IFDEF Win32}
  608.   if Value <> nil then
  609.     Value.FreeNotification(Self);
  610.   {$ENDIF Win32}
  611. end;
  612.  
  613. procedure TEsCustomDbNumberEdit.SetFocused(Value : Boolean);
  614. begin
  615.   if FFocused <> Value then begin
  616.     FFocused := Value;
  617.     if (FAlignment <> taLeftJustify) then
  618.       Invalidate;
  619.     FDataLink.Reset;
  620.   end;
  621. end;
  622.  
  623. procedure TEsCustomDbNumberEdit.SetReadOnly(Value : Boolean);
  624. begin
  625.   FDataLink.ReadOnly := Value;
  626. end;
  627.  
  628. procedure TEsCustomDbNumberEdit.UpdateData(Sender : TObject);
  629. begin
  630.   FDataLink.Field.Text := Text;
  631. end;
  632.  
  633. procedure TEsCustomDbNumberEdit.WMCut(var Message : TMessage);
  634. begin
  635.   FDataLink.Edit;
  636.  
  637.   inherited;
  638. end;
  639.  
  640. procedure TEsCustomDbNumberEdit.WMPaint(var Message : TWMPaint);
  641. var
  642.   Left    : Integer;
  643.   Margins : TPoint;
  644.   R       : TRect;
  645.   DC      : HDC;
  646.   PS      : TPaintStruct;
  647.   S       : string;
  648. begin
  649.   {$IFDEF Win32}
  650.   if ((FAlignment = taLeftJustify) or FFocused) and not (csPaintCopy in ControlState) then begin
  651.   {$ELSE}
  652.   if ((FAlignment = taLeftJustify) or FFocused) then begin
  653.   {$ENDIF Win32}
  654.     inherited;
  655.     Exit;
  656.   end;
  657.  
  658.   {draw right and center justify manually unless the edit has the focus}
  659.   if FCanvas = nil then begin
  660.     FCanvas := TControlCanvas.Create;
  661.     FCanvas.Control := Self;
  662.   end;
  663.   DC := Message.DC;
  664.   if DC = 0 then
  665.     DC := BeginPaint(Handle, PS);
  666.   FCanvas.Handle := DC;
  667.   try
  668.     FCanvas.Font := Font;
  669.     with FCanvas do begin
  670.       R := ClientRect;
  671.       if not (NewStyleControls and Ctl3D) and (BorderStyle = bsSingle) then begin
  672.         Brush.Color := clWindowFrame;
  673.         FrameRect(R);
  674.         InflateRect(R, -1, -1);
  675.       end;
  676.       Brush.Color := Color;
  677.       {$IFDEF Win32}
  678.       if (csPaintCopy in ControlState) and (FDataLink.Field <> nil) then begin
  679.         S := FDataLink.Field.DisplayText;
  680.       end else
  681.       {$ENDIF Win32}
  682.         S := Text;
  683.       if PasswordChar <> #0 then FillChar(S[1], Length(S), PasswordChar);
  684.       Margins := GetTextMargins;
  685.       case FAlignment of
  686.         taLeftJustify  : Left := Margins.X;
  687.         taRightJustify : Left := ClientWidth - TextWidth(S) - Margins.X - 2 - GetButtonWidth;
  688.       else
  689.         Left := (ClientWidth - TextWidth(S)) div 2;
  690.       end;
  691.       TextRect(R, Left, Margins.Y, S);
  692.     end;
  693.   finally
  694.     FCanvas.Handle := 0;
  695.     if Message.DC = 0 then
  696.       EndPaint(Handle, PS);
  697.   end;
  698. end;
  699.  
  700. procedure TEsCustomDbNumberEdit.WMPaste(var Message : TMessage);
  701. begin
  702.   FDataLink.Edit;
  703.  
  704.   inherited;
  705. end;
  706.  
  707.  
  708. {*** TEsCustomDbDateEdit ***}
  709.  
  710. procedure TEsCustomDbDateEdit.Change;
  711. begin
  712.   FDataLink.Modified;
  713.  
  714.   inherited Change;
  715. end;
  716.  
  717. procedure TEsCustomDbDateEdit.CMEnter(var Message : TCMEnter);
  718. begin
  719.   SetFocused(True);
  720.  
  721.   inherited;
  722. end;
  723.  
  724. procedure TEsCustomDbDateEdit.CMExit(var Message : TCMExit);
  725. var                                                                    {!!.05}
  726.   WasModified : Boolean;                                               {!!.05}
  727. begin
  728.   if PopupActive then
  729.     Exit;
  730.  
  731.   WasModified := Modified;                                             {!!.05}
  732.   DoExit;    {force update of date}                                   
  733.   try
  734.     if WasModified then                                                {!!.05}
  735.       FDataLink.UpdateRecord;
  736.   except
  737.     SelectAll;
  738.     SetFocus;
  739.     raise;
  740.   end;
  741.   SetFocused(False);
  742. end;
  743.  
  744. {$IFDEF Win32}
  745. procedure TEsCustomDbDateEdit.CMGetDataLink(var Message : TMessage);
  746. begin
  747.   Message.Result := Integer(FDataLink);
  748. end;
  749. {$ENDIF Win32}
  750.  
  751. constructor TEsCustomDbDateEdit.Create(AOwner : TComponent);
  752. {$IFDEF TRIALRUN}
  753. var
  754.   X : Integer;
  755. {$ENDIF}
  756. begin
  757.   inherited Create(AOwner);
  758.  
  759.   inherited ReadOnly := True;
  760.  
  761.   {$IFDEF Win32}
  762.   ControlStyle := ControlStyle + [csReplicatable];
  763.   {$ENDIF Win32}
  764.  
  765.   FDataLink := TFieldDataLink.Create;
  766.   FDataLink.Control := Self;
  767.   FDataLink.OnDataChange := DataChange;
  768.   FDataLink.OnEditingChange := EditingChange;
  769.   FDataLink.OnUpdateData := UpdateData;
  770.  
  771. {$IFDEF TRIALRUN}
  772.   X := _CC_;
  773.   if (X < ccRangeLow) or (X > ccRangeHigh) then Halt;
  774.   X := _VC_;
  775.   if (X < ccRangeLow) or (X > ccRangeHigh) then Halt;
  776. {$ENDIF}
  777. end;
  778.  
  779. procedure TEsCustomDbDateEdit.DataChange(Sender : TObject);
  780. var
  781.   P  : Integer;
  782.   DT : TDateTime;
  783.   S  : string[80];
  784. begin
  785.   if FDataLink.Field <> nil then begin
  786.     if FAlignment <> FDataLink.Field.Alignment then begin
  787.       FAlignment := FDataLink.Field.Alignment;
  788.       Text := '';
  789.     end;
  790.     if FDataLink.Field.DataType in DateFieldTypes then begin
  791.       DT := FDataLink.Field.AsDateTime;                                {!!.04}
  792.       FDate := Trunc(DT);                                              {!!.04}
  793.       if FFocused and FDataLink.CanModify then                         {!!.04}
  794.         SetDate(Trunc(DT))                                             {!!.04}
  795.       else
  796.         Text := FDataLink.Field.DisplayText;
  797.     end else begin
  798.       S := FDataLink.Field.ClassName;
  799.       S[1] := '(';
  800.       P := Pos('Field', S);
  801.       if P > 0 then begin
  802.         S[P] := ')';
  803.         S[0] := Char(P);
  804.       end else
  805.         S := Concat(S, ')');
  806.       Text := S;
  807.     end;
  808.   end else begin
  809.     FAlignment := taLeftJustify;
  810.     if csDesigning in ComponentState then
  811.       Text := Name
  812.     else
  813.       Text := '';
  814.   end;
  815. end;
  816.  
  817. destructor TEsCustomDbDateEdit.Destroy;
  818. begin
  819.   FDataLink.Free;
  820.   FDataLink := nil;
  821.  
  822.   FCanvas.Free;
  823.   FCanvas := nil;
  824.  
  825.   inherited Destroy;
  826. end;
  827.  
  828. procedure TEsCustomDbDateEdit.EditingChange(Sender : TObject);
  829. begin
  830.   inherited ReadOnly := not FDataLink.Editing;
  831.   FButton.Enabled := GetButtonEnabled;                                 {!!.03}
  832. end;
  833.  
  834. {!!.03}
  835. function TEsCustomDbDateEdit.GetButtonEnabled : Boolean;
  836. begin
  837.   Result := (FDataLink <> nil) and (FDataLink.DataSource <> nil) and
  838.     (FDataLink.Editing or FDataLink.DataSource.AutoEdit) or
  839.     (csDesigning in ComponentState);
  840. end;
  841.  
  842. function TEsCustomDbDateEdit.GetDataField : string;
  843. begin
  844.   Result := FDataLink.FieldName;
  845. end;
  846.  
  847. function TEsCustomDbDateEdit.GetDataSource : TDataSource;
  848. begin
  849.   Result := FDataLink.DataSource;
  850. end;
  851.  
  852. function TEsCustomDbDateEdit.GetField : TField;
  853. begin
  854.   Result := FDataLink.Field;
  855. end;
  856.  
  857. function TEsCustomDbDateEdit.GetReadOnly : Boolean;
  858. begin
  859.   Result := FDataLink.ReadOnly;
  860.   if FDataLink.Field <> nil then
  861.     if not (FDataLink.Field.DataType in DateFieldTypes) then
  862.       Result := True;
  863. end;
  864.  
  865. function TEsCustomDbDateEdit.GetTextMargins : TPoint;
  866. var
  867.   DC         : HDC;
  868.   SaveFont   : HFont;
  869.   I          : Integer;
  870.   SysMetrics : TTextMetric;
  871.   Metrics    : TTextMetric;
  872. begin
  873.   if NewStyleControls then begin
  874.     if BorderStyle = bsNone then
  875.       I := 0
  876.     else if Ctl3D then
  877.       I := 1
  878.     else
  879.       I := 2;
  880.     {$IFDEF Win32}
  881.     Result.X := SendMessage(Handle, EM_GETMARGINS, 0, 0) and $0000FFFF + I;
  882.     {$ELSE}
  883.     Result.X := 2;
  884.     {$ENDIF Win32}
  885.     Result.Y := I;
  886.   end else begin
  887.     if BorderStyle = bsNone then
  888.       I := 0
  889.     else begin
  890.       DC := GetDC(0);
  891.       GetTextMetrics(DC, SysMetrics);
  892.       SaveFont := SelectObject(DC, Font.Handle);
  893.       GetTextMetrics(DC, Metrics);
  894.       SelectObject(DC, SaveFont);
  895.       ReleaseDC(0, DC);
  896.       I := SysMetrics.tmHeight;
  897.       if I > Metrics.tmHeight then
  898.         I := Metrics.tmHeight;
  899.       I := I div 4;
  900.     end;
  901.     Result.X := I;
  902.     Result.Y := I;
  903.   end;
  904. end;
  905.  
  906. procedure TEsCustomDbDateEdit.KeyDown(var Key : Word; Shift : TShiftState);
  907. begin
  908.   inherited KeyDown(Key, Shift);
  909.  
  910.   {start edit mdoe if cutting or pasting}
  911.   if (Key = VK_DELETE) or ((Key = VK_INSERT) and (ssShift in Shift)) then
  912.     FDataLink.Edit;
  913. end;
  914.  
  915. procedure TEsCustomDbDateEdit.KeyPress(var Key : Char);
  916. begin
  917.   if AllowIncDec and (Key in ['+', '-']) then
  918.     FDataLink.Edit;
  919.  
  920.   inherited KeyPress(Key);
  921.  
  922.   if (Key in [#32..#255]) and (FDataLink.Field <> nil) and
  923.      not FDataLink.Field.IsValidChar(Key) then begin
  924.     MessageBeep(0);
  925.     Key := #0;
  926.   end;
  927.  
  928.   case Key of
  929.     ^H, ^V, ^X, #32..#255 :
  930.       FDataLink.Edit;
  931.     #27:
  932.       begin
  933.         FDataLink.Reset;
  934.         SelectAll;
  935.         Key := #0;
  936.       end;
  937.   end;
  938. end;
  939.  
  940. procedure TEsCustomDbDateEdit.Notification(AComponent : TComponent; Operation : TOperation);
  941. begin
  942.   inherited Notification(AComponent, Operation);
  943.  
  944.   if (Operation = opRemove) and (FDataLink <> nil) and (AComponent = DataSource) then
  945.     DataSource := nil;
  946. end;
  947.  
  948. procedure TEsCustomDbDateEdit.PopupClose(Sender : TObject);
  949. begin
  950.   inherited PopupClose(Sender);
  951.  
  952.   {allow control to see focus change that was blocked when popup became active}
  953.   if not Focused then
  954.     Perform(CM_EXIT, 0, 0);
  955. end;
  956.  
  957. {!!.03}
  958. procedure TEsCustomDbDateEdit.PopupOpen;
  959. begin
  960.   if FDataLink.Edit then  {enter edit mode}
  961.     inherited PopupOpen
  962.   else begin
  963.     MessageBeep(0);
  964.     SetFocus;
  965.   end;
  966. end;
  967.  
  968. procedure TEsCustomDbDateEdit.SetDataField(const Value : string);
  969. begin
  970.   try
  971.     FDataLink.FieldName := Value;
  972.   except
  973.     FDataLink.FieldName := '';
  974.     raise;
  975.   end;
  976. end;
  977.  
  978. procedure TEsCustomDbDateEdit.SetDataSource(Value : TDataSource);
  979. begin
  980.   FDataLink.DataSource := Value;
  981.   {$IFDEF Win32}
  982.   if Value <> nil then
  983.     Value.FreeNotification(Self);
  984.   {$ENDIF Win32}
  985. end;
  986.  
  987. procedure TEsCustomDbDateEdit.SetFocused(Value : Boolean);
  988. begin
  989.   if FFocused <> Value then begin
  990.     FFocused := Value;
  991.     if (FAlignment <> taLeftJustify) then
  992.       Invalidate;
  993.     FDataLink.Reset;
  994.   end;
  995. end;
  996.  
  997. procedure TEsCustomDbDateEdit.SetReadOnly(Value : Boolean);
  998. begin
  999.   FDataLink.ReadOnly := Value;
  1000. end;
  1001.  
  1002. {!!.04}
  1003. procedure TEsCustomDbDateEdit.UpdateData(Sender : TObject);
  1004. var
  1005.   DT : TDateTime;
  1006. begin
  1007.   if FDataLink.Field.DataType in DateFieldTypes then begin
  1008.     DT := FDataLink.Field.AsDateTime;
  1009.     if Text = '' then begin {save just the time portion}
  1010.       if (FDataLink.Field.DataType = ftDateTime) and (Frac(DT) <> 0) then
  1011.         FDataLink.Field.AsDateTime := Frac(DT)
  1012.       else
  1013.         FDataLink.Field.Clear;
  1014.     end else begin
  1015.       DoExit;  {validate field and translate date}
  1016.       FDataLink.Field.AsDateTime := Date + Frac(DT);
  1017.     end;
  1018.   end else
  1019.     FDataLink.Field.Text := Text;
  1020. end;
  1021.  
  1022. procedure TEsCustomDbDateEdit.WMCut(var Message : TMessage);
  1023. begin
  1024.   FDataLink.Edit;
  1025.  
  1026.   inherited;
  1027. end;
  1028.  
  1029. procedure TEsCustomDbDateEdit.WMPaint(var Message : TWMPaint);
  1030. var
  1031.   Left    : Integer;
  1032.   Margins : TPoint;
  1033.   R       : TRect;
  1034.   DC      : HDC;
  1035.   PS      : TPaintStruct;
  1036.   S       : string;
  1037. begin
  1038.   {$IFDEF Win32}
  1039.   if ((FAlignment = taLeftJustify) or FFocused) and not (csPaintCopy in ControlState) then begin
  1040.   {$ELSE}
  1041.   if ((FAlignment = taLeftJustify) or FFocused) then begin
  1042.   {$ENDIF Win32}
  1043.     inherited;
  1044.     Exit;
  1045.   end;
  1046.  
  1047.   {draw right and center justify manually unless the edit has the focus}
  1048.   if FCanvas = nil then begin
  1049.     FCanvas := TControlCanvas.Create;
  1050.     FCanvas.Control := Self;
  1051.   end;
  1052.   DC := Message.DC;
  1053.   if DC = 0 then
  1054.     DC := BeginPaint(Handle, PS);
  1055.   FCanvas.Handle := DC;
  1056.   try
  1057.     FCanvas.Font := Font;
  1058.     with FCanvas do begin
  1059.       R := ClientRect;
  1060.       if not (NewStyleControls and Ctl3D) and (BorderStyle = bsSingle) then begin
  1061.         Brush.Color := clWindowFrame;
  1062.         FrameRect(R);
  1063.         InflateRect(R, -1, -1);
  1064.       end;
  1065.       Brush.Color := Color;
  1066.       {$IFDEF Win32}
  1067.       if (csPaintCopy in ControlState) and (FDataLink.Field <> nil) then begin
  1068.         S := FDataLink.Field.DisplayText;
  1069.       end else
  1070.       {$ENDIF Win32}
  1071.         S := Text;
  1072.       if PasswordChar <> #0 then FillChar(S[1], Length(S), PasswordChar);
  1073.       Margins := GetTextMargins;
  1074.       case FAlignment of
  1075.         taLeftJustify  : Left := Margins.X;
  1076.         taRightJustify : Left := ClientWidth - TextWidth(S) - Margins.X - 2 - GetButtonWidth;
  1077.       else
  1078.         Left := (ClientWidth - TextWidth(S)) div 2;
  1079.       end;
  1080.       TextRect(R, Left, Margins.Y, S);
  1081.     end;
  1082.   finally
  1083.     FCanvas.Handle := 0;
  1084.     if Message.DC = 0 then
  1085.       EndPaint(Handle, PS);
  1086.   end;
  1087. end;
  1088.  
  1089. procedure TEsCustomDbDateEdit.WMPaste(var Message : TMessage);
  1090. begin
  1091.   FDataLink.Edit;
  1092.  
  1093.   inherited;
  1094. end;
  1095.  
  1096. end.