home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d6 / RX275D6.ZIP / Units / RXDBCOMB.PAS < prev    next >
Pascal/Delphi Source File  |  2001-06-24  |  17KB  |  623 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1997 Master-Bank                }
  6. {                                                       }
  7. {*******************************************************}
  8.  
  9. unit RxDBComb;
  10.  
  11. {$I RX.INC}
  12.  
  13. interface
  14.  
  15. uses Windows, DbCtrls, VDBConsts,
  16.   Messages, Menus, Graphics, Classes, Controls, DB, 
  17.   {$IFNDEF RX_D3} DBTables, {$ENDIF} StdCtrls, DBConsts;
  18.  
  19. type
  20.  
  21. { TCustomDBComboBox }
  22.  
  23.   TCustomDBComboBox = class(TCustomComboBox)
  24.   private
  25.     FDataLink: TFieldDataLink;
  26. {$IFDEF WIN32}
  27.     FPaintControl: TPaintControl;
  28. {$ENDIF}
  29.     procedure DataChange(Sender: TObject);
  30.     procedure EditingChange(Sender: TObject);
  31.     function GetDataField: string;
  32.     function GetDataSource: TDataSource;
  33.     function GetField: TField;
  34.     function GetReadOnly: Boolean;
  35.     procedure SetDataField(const Value: string);
  36.     procedure SetDataSource(Value: TDataSource);
  37.     procedure SetEditReadOnly;
  38.     procedure SetItems(Value: TStrings);
  39.     procedure SetReadOnly(Value: Boolean);
  40.     procedure UpdateData(Sender: TObject);
  41.     function GetComboText: string; virtual;
  42.     procedure SetComboText(const Value: string); virtual;
  43.     procedure CMExit(var Message: TCMExit); message CM_EXIT;
  44. {$IFDEF WIN32}
  45.     procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
  46.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  47. {$ELSE}
  48.     function GetStyle: TComboBoxStyle;
  49. {$ENDIF}
  50.   protected
  51.     procedure Change; override;
  52.     procedure Click; override;
  53.     procedure ComboWndProc(var Message: TMessage; ComboWnd: HWnd;
  54.       ComboProc: Pointer); override;
  55.     procedure CreateWnd; override;
  56.     procedure DropDown; override;
  57.     function GetPaintText: string; virtual;
  58.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  59.     procedure KeyPress(var Key: Char); override;
  60.     procedure Loaded; override;
  61.     procedure Notification(AComponent: TComponent;
  62.       Operation: TOperation); override;
  63.     procedure SetStyle(Value: TComboBoxStyle); {$IFDEF WIN32} override {$ELSE} virtual {$ENDIF};
  64.     procedure WndProc(var Message: TMessage); override;
  65.     property ComboText: string read GetComboText write SetComboText;
  66. {$IFNDEF WIN32}
  67.     property Style: TComboBoxStyle read GetStyle write SetStyle default csDropDown;
  68. {$ENDIF WIN32}
  69.     property DataField: string read GetDataField write SetDataField;
  70.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  71.     property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
  72.   public
  73.     constructor Create(AOwner: TComponent); override;
  74.     destructor Destroy; override;
  75. {$IFDEF RX_D4}
  76.     function ExecuteAction(Action: TBasicAction): Boolean; override;
  77.     function UpdateAction(Action: TBasicAction): Boolean; override;
  78.     function UseRightToLeftAlignment: Boolean; override;
  79. {$ENDIF}
  80.     property Field: TField read GetField;
  81.     property Items write SetItems;
  82.     property Text;
  83.   end;
  84.  
  85. { TRxDBComboBox }
  86.  
  87.   TRxDBComboBox = class(TCustomDBComboBox)
  88.   private
  89.     FValues: TStrings;
  90.     FEnableValues: Boolean;
  91.     procedure SetEnableValues(Value: Boolean);
  92.     procedure SetValues(Value: TStrings);
  93.     procedure ValuesChanged(Sender: TObject);
  94.   protected
  95.     procedure SetStyle(Value: TComboBoxStyle); override;
  96.     function GetComboText: string; override;
  97.     function GetPaintText: string; override;
  98.     procedure SetComboText(const Value: string); override;
  99.   public
  100.     constructor Create(AOwner: TComponent); override;
  101.     destructor Destroy; override;
  102.   published
  103.     property Style; { must be published before Items }
  104.     property Color;
  105.     property Ctl3D;
  106.     property DataField;
  107.     property DataSource;
  108.     property DragMode;
  109.     property DragCursor;
  110.     property DropDownCount;
  111.     property Enabled;
  112.     property EnableValues: Boolean read FEnableValues write SetEnableValues;
  113.     property Font;
  114. {$IFDEF RX_D4}
  115.     property Anchors;
  116.     property BiDiMode;
  117.     property Constraints;
  118.     property DragKind;
  119.     property ParentBiDiMode;
  120. {$ENDIF}
  121. {$IFDEF WIN32}
  122.   {$IFNDEF VER90}
  123.     property ImeMode;
  124.     property ImeName;
  125.   {$ENDIF}
  126. {$ENDIF}
  127.     property ItemHeight;
  128.     property Items;
  129.     property ParentColor;
  130.     property ParentCtl3D;
  131.     property ParentFont;
  132.     property ParentShowHint;
  133.     property PopupMenu;
  134.     property ReadOnly;
  135.     property ShowHint;
  136.     property Sorted;
  137.     property TabOrder;
  138.     property TabStop;
  139.     property Values: TStrings read FValues write SetValues;
  140.     property Visible;
  141.     property OnChange;
  142.     property OnClick;
  143.     property OnDblClick;
  144.     property OnDragDrop;
  145.     property OnDragOver;
  146.     property OnDrawItem;
  147.     property OnDropDown;
  148.     property OnEndDrag;
  149.     property OnEnter;
  150.     property OnExit;
  151.     property OnKeyDown;
  152.     property OnKeyPress;
  153.     property OnKeyUp;
  154.     property OnMeasureItem;
  155. {$IFDEF WIN32}
  156.     property OnStartDrag;
  157. {$ENDIF}
  158. {$IFDEF RX_D5}
  159.     property OnContextPopup;
  160. {$ENDIF}
  161. {$IFDEF RX_D4}
  162.     property OnEndDock;
  163.     property OnStartDock;
  164. {$ENDIF}
  165.   end;
  166.  
  167. implementation
  168.  
  169. uses DBUtils;
  170.  
  171. { TCustomDBComboBox }
  172.  
  173. constructor TCustomDBComboBox.Create(AOwner: TComponent);
  174. begin
  175.   inherited Create(AOwner);
  176. {$IFDEF WIN32}
  177.   ControlStyle := ControlStyle + [csReplicatable];
  178. {$ENDIF}
  179.   FDataLink := TFieldDataLink.Create;
  180.   FDataLink.Control := Self;
  181.   FDataLink.OnDataChange := DataChange;
  182.   FDataLink.OnUpdateData := UpdateData;
  183.   FDataLink.OnEditingChange := EditingChange;
  184. {$IFDEF WIN32}
  185.   FPaintControl := TPaintControl.Create(Self, 'COMBOBOX');
  186. {$ENDIF}
  187. end;
  188.  
  189. destructor TCustomDBComboBox.Destroy;
  190. begin
  191. {$IFDEF WIN32}
  192.   FPaintControl.Free;
  193. {$ENDIF}
  194.   FDataLink.OnDataChange := nil;
  195.   FDataLink.OnUpdateData := nil;
  196.   FDataLink.Free;
  197.   FDataLink := nil;
  198.   inherited Destroy;
  199. end;
  200.  
  201. procedure TCustomDBComboBox.Loaded;
  202. begin
  203.   inherited Loaded;
  204.   if (csDesigning in ComponentState) then DataChange(Self);
  205. end;
  206.  
  207. procedure TCustomDBComboBox.Notification(AComponent: TComponent;
  208.   Operation: TOperation);
  209. begin
  210.   inherited Notification(AComponent, Operation);
  211.   if (Operation = opRemove) and (FDataLink <> nil) and
  212.     (AComponent = DataSource) then DataSource := nil;
  213. end;
  214.  
  215. procedure TCustomDBComboBox.CreateWnd;
  216. begin
  217.   inherited CreateWnd;
  218.   SetEditReadOnly;
  219. end;
  220.  
  221. procedure TCustomDBComboBox.DataChange(Sender: TObject);
  222. begin
  223.   if DroppedDown then Exit;
  224.   if FDataLink.Field <> nil then ComboText := FDataLink.Field.Text
  225.   else if csDesigning in ComponentState then ComboText := Name
  226.   else ComboText := '';
  227. end;
  228.  
  229. procedure TCustomDBComboBox.UpdateData(Sender: TObject);
  230. begin
  231.   FDataLink.Field.Text := ComboText;
  232. end;
  233.  
  234. procedure TCustomDBComboBox.SetComboText(const Value: string);
  235. var
  236.   I: Integer;
  237.   Redraw: Boolean;
  238. begin
  239.   if Value <> ComboText then begin
  240.     if Style <> csDropDown then begin
  241.       Redraw := (Style <> csSimple) and HandleAllocated;
  242.       if Redraw then SendMessage(Handle, WM_SETREDRAW, 0, 0);
  243.       try
  244.         if Value = '' then I := -1 else I := Items.IndexOf(Value);
  245.         ItemIndex := I;
  246.       finally
  247.         if Redraw then begin
  248.           SendMessage(Handle, WM_SETREDRAW, 1, 0);
  249.           Invalidate;
  250.         end;
  251.       end;
  252.       if I >= 0 then Exit;
  253.     end;
  254.     if Style in [csDropDown, csSimple] then Text := Value;
  255.   end;
  256. end;
  257.  
  258. function TCustomDBComboBox.GetComboText: string;
  259. var
  260.   I: Integer;
  261. begin
  262.   if Style in [csDropDown, csSimple] then Result := Text
  263.   else begin
  264.     I := ItemIndex;
  265.     if I < 0 then Result := '' else Result := Items[I];
  266.   end;
  267. end;
  268.  
  269. procedure TCustomDBComboBox.Change;
  270. begin
  271.   FDataLink.Edit;
  272.   inherited Change;
  273.   FDataLink.Modified;
  274. end;
  275.  
  276. procedure TCustomDBComboBox.Click;
  277. begin
  278.   FDataLink.Edit;
  279.   inherited Click;
  280.   FDataLink.Modified;
  281. end;
  282.  
  283. procedure TCustomDBComboBox.DropDown;
  284. begin
  285. {$IFNDEF WIN32}
  286.   FDataLink.Edit;
  287. {$ENDIF}
  288.   inherited DropDown;
  289. end;
  290.  
  291. function TCustomDBComboBox.GetDataSource: TDataSource;
  292. begin
  293.   Result := FDataLink.DataSource;
  294. end;
  295.  
  296. procedure TCustomDBComboBox.SetDataSource(Value: TDataSource);
  297. begin
  298. {$IFDEF RX_D4}
  299.   if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
  300. {$ENDIF}
  301.     FDataLink.DataSource := Value;
  302. {$IFDEF WIN32}
  303.   if Value <> nil then Value.FreeNotification(Self);
  304. {$ENDIF}
  305. end;
  306.  
  307. function TCustomDBComboBox.GetDataField: string;
  308. begin
  309.   Result := FDataLink.FieldName;
  310. end;
  311.  
  312. procedure TCustomDBComboBox.SetDataField(const Value: string);
  313. begin
  314.   FDataLink.FieldName := Value;
  315. end;
  316.  
  317. function TCustomDBComboBox.GetReadOnly: Boolean;
  318. begin
  319.   Result := FDataLink.ReadOnly;
  320. end;
  321.  
  322. procedure TCustomDBComboBox.SetReadOnly(Value: Boolean);
  323. begin
  324.   FDataLink.ReadOnly := Value;
  325. end;
  326.  
  327. function TCustomDBComboBox.GetField: TField;
  328. begin
  329.   Result := FDataLink.Field;
  330. end;
  331.  
  332. procedure TCustomDBComboBox.KeyDown(var Key: Word; Shift: TShiftState);
  333. begin
  334.   inherited KeyDown(Key, Shift);
  335.   if Key in [VK_BACK, VK_DELETE, VK_UP, VK_DOWN, 32..255] then begin
  336.     if not FDataLink.Edit and (Key in [VK_UP, VK_DOWN]) then
  337.       Key := 0;
  338.   end;
  339. end;
  340.  
  341. procedure TCustomDBComboBox.KeyPress(var Key: Char);
  342. begin
  343.   inherited KeyPress(Key);
  344.   if (Key in [#32..#255]) and (FDataLink.Field <> nil) and
  345.     not FDataLink.Field.IsValidChar(Key) then
  346.   begin
  347.     MessageBeep(0);
  348.     Key := #0;
  349.   end;
  350.   case Key of
  351.     ^H, ^V, ^X, #32..#255:
  352.       FDataLink.Edit;
  353.     #27:
  354.       begin
  355.         FDataLink.Reset;
  356.         SelectAll;
  357. {$IFNDEF WIN32}
  358.         Key := #0;
  359. {$ENDIF}
  360.       end;
  361.   end;
  362. end;
  363.  
  364. procedure TCustomDBComboBox.EditingChange(Sender: TObject);
  365. begin
  366.   SetEditReadOnly;
  367. end;
  368.  
  369. procedure TCustomDBComboBox.SetEditReadOnly;
  370. begin
  371.   if (Style in [csDropDown, csSimple]) and HandleAllocated then
  372.     SendMessage({$IFDEF WIN32} EditHandle {$ELSE} FEditHandle {$ENDIF},
  373.       EM_SETREADONLY, Ord(not FDataLink.Editing), 0);
  374. end;
  375.  
  376. procedure TCustomDBComboBox.WndProc(var Message: TMessage);
  377. begin
  378.   if not (csDesigning in ComponentState) then
  379.     case Message.Msg of
  380.       WM_COMMAND:
  381.         if TWMCommand(Message).NotifyCode = CBN_SELCHANGE then
  382.           if not FDataLink.Edit then begin
  383.             if Style <> csSimple then
  384.               PostMessage(Handle, CB_SHOWDROPDOWN, 0, 0);
  385.             Exit;
  386.           end;
  387.       CB_SHOWDROPDOWN:
  388.         if Message.WParam <> 0 then FDataLink.Edit
  389.         else if not FDataLink.Editing then DataChange(Self); {Restore text}
  390. {$IFDEF WIN32}
  391.       WM_CREATE,
  392.       WM_WINDOWPOSCHANGED,
  393.       CM_FONTCHANGED:
  394.         FPaintControl.DestroyHandle;
  395. {$ENDIF}
  396.     end;
  397.   inherited WndProc(Message);
  398. end;
  399.  
  400. procedure TCustomDBComboBox.ComboWndProc(var Message: TMessage; ComboWnd: HWnd;
  401.   ComboProc: Pointer);
  402. begin
  403.   if not (csDesigning in ComponentState) then
  404.     case Message.Msg of
  405.       WM_LBUTTONDOWN:
  406. {$IFDEF WIN32}
  407.         if (Style = csSimple) and (ComboWnd <> EditHandle) then
  408. {$ELSE}
  409.         if (Style = csSimple) and (ComboWnd <> FEditHandle) then
  410. {$ENDIF}
  411.           if not FDataLink.Edit then Exit;
  412.     end;
  413.   inherited ComboWndProc(Message, ComboWnd, ComboProc);
  414. end;
  415.  
  416. procedure TCustomDBComboBox.CMExit(var Message: TCMExit);
  417. begin
  418.   try
  419.     FDataLink.UpdateRecord;
  420.   except
  421.     SelectAll;
  422.     if CanFocus then SetFocus;
  423.     raise;
  424.   end;
  425.   inherited;
  426. end;
  427.  
  428. {$IFDEF WIN32}
  429. procedure TCustomDBComboBox.CMGetDatalink(var Message: TMessage);
  430. begin
  431.   Message.Result := Longint(FDataLink);
  432. end;
  433.  
  434. procedure TCustomDBComboBox.WMPaint(var Message: TWMPaint);
  435. var
  436.   S: string;
  437.   R: TRect;
  438.   P: TPoint;
  439.   Child: HWND;
  440. begin
  441.   if csPaintCopy in ControlState then begin
  442.     S := GetPaintText;
  443.     if Style = csDropDown then begin
  444.       SendMessage(FPaintControl.Handle, WM_SETTEXT, 0, Longint(PChar(S)));
  445.       SendMessage(FPaintControl.Handle, WM_PAINT, Message.DC, 0);
  446.       Child := GetWindow(FPaintControl.Handle, GW_CHILD);
  447.       if Child <> 0 then begin
  448.         Windows.GetClientRect(Child, R);
  449.         Windows.MapWindowPoints(Child, FPaintControl.Handle, R.TopLeft, 2);
  450.         GetWindowOrgEx(Message.DC, P);
  451.         SetWindowOrgEx(Message.DC, P.X - R.Left, P.Y - R.Top, nil);
  452.         IntersectClipRect(Message.DC, 0, 0, R.Right - R.Left, R.Bottom - R.Top);
  453.         SendMessage(Child, WM_PAINT, Message.DC, 0);
  454.       end;
  455.     end
  456.     else begin
  457.       SendMessage(FPaintControl.Handle, CB_RESETCONTENT, 0, 0);
  458.       if Items.IndexOf(S) <> -1 then begin
  459.         SendMessage(FPaintControl.Handle, CB_ADDSTRING, 0, Longint(PChar(S)));
  460.         SendMessage(FPaintControl.Handle, CB_SETCURSEL, 0, 0);
  461.       end;
  462.       SendMessage(FPaintControl.Handle, WM_PAINT, Message.DC, 0);
  463.     end;
  464.   end
  465.   else inherited;
  466. end;
  467. {$ENDIF}
  468.  
  469. function TCustomDBComboBox.GetPaintText: string;
  470. begin
  471.   if FDataLink.Field <> nil then Result := FDataLink.Field.Text
  472.   else Result := '';
  473. end;
  474.  
  475. procedure TCustomDBComboBox.SetItems(Value: TStrings);
  476. begin
  477.   Items.Assign(Value);
  478.   DataChange(Self);
  479. end;
  480.  
  481. {$IFNDEF WIN32}
  482. function TCustomDBComboBox.GetStyle: TComboBoxStyle;
  483. begin
  484.   Result := inherited Style;
  485. end;
  486. {$ENDIF}
  487.  
  488. procedure TCustomDBComboBox.SetStyle(Value: TComboBoxStyle);
  489. begin
  490. {$IFDEF WIN32}
  491.   if (Value = csSimple) and Assigned(FDatalink) and FDatalink.DatasourceFixed then
  492.     _DBError(SNotReplicatable);
  493.   inherited SetStyle(Value);
  494. {$ELSE}
  495.   if Value = csSimple then ControlStyle := ControlStyle - [csFixedHeight]
  496.   else ControlStyle := ControlStyle + [csFixedHeight];
  497.   inherited Style := Value;
  498.   RecreateWnd;
  499. {$ENDIF}
  500. end;
  501.  
  502. {$IFDEF RX_D4}
  503. function TCustomDBComboBox.UseRightToLeftAlignment: Boolean;
  504. begin
  505.   Result := DBUseRightToLeftAlignment(Self, Field);
  506. end;
  507.  
  508. function TCustomDBComboBox.ExecuteAction(Action: TBasicAction): Boolean;
  509. begin
  510.   Result := inherited ExecuteAction(Action) or (FDataLink <> nil) and
  511.     FDataLink.ExecuteAction(Action);
  512. end;
  513.  
  514. function TCustomDBComboBox.UpdateAction(Action: TBasicAction): Boolean;
  515. begin
  516.   Result := inherited UpdateAction(Action) or (FDataLink <> nil) and
  517.     FDataLink.UpdateAction(Action);
  518. end;
  519. {$ENDIF}
  520.  
  521. { TRxDBComboBox }
  522.  
  523. constructor TRxDBComboBox.Create(AOwner: TComponent);
  524. begin
  525.   inherited Create(AOwner);
  526.   FValues := TStringList.Create;
  527.   TStringList(FValues).OnChange := ValuesChanged;
  528.   EnableValues := False;
  529. end;
  530.  
  531. destructor TRxDBComboBox.Destroy;
  532. begin
  533.   TStringList(FValues).OnChange := nil;
  534.   FValues.Free;
  535.   inherited Destroy;
  536. end;
  537.  
  538. procedure TRxDBComboBox.ValuesChanged(Sender: TObject);
  539. begin
  540.   if FEnableValues then DataChange(Self);
  541. end;
  542.  
  543. function TRxDBComboBox.GetPaintText: string;
  544. var
  545.   I: Integer;
  546. begin
  547.   Result := '';
  548.   if FDataLink.Field <> nil then begin
  549.     if FEnableValues then begin
  550.       I := Values.IndexOf(FDataLink.Field.Text);
  551.       if I >= 0 then Result := Items.Strings[I]
  552.     end
  553.     else Result := FDataLink.Field.Text;
  554.   end;
  555. end;
  556.  
  557. function TRxDBComboBox.GetComboText: string;
  558. var
  559.   I: Integer;
  560. begin
  561.   if (Style in [csDropDown, csSimple]) and (not FEnableValues) then
  562.     Result := Text
  563.   else begin
  564.     I := ItemIndex;
  565.     if (I < 0) or (FEnableValues and (FValues.Count < I + 1)) then
  566.       Result := ''
  567.     else
  568.       if FEnableValues then Result := FValues[I]
  569.       else Result := Items[I];
  570.   end;
  571. end;
  572.  
  573. procedure TRxDBComboBox.SetComboText(const Value: string);
  574. var
  575.   I: Integer;
  576.   Redraw: Boolean;
  577. begin
  578.   if Value <> ComboText then begin
  579.     if Style <> csDropDown then begin
  580.       Redraw := (Style <> csSimple) and HandleAllocated;
  581.       if Redraw then SendMessage(Handle, WM_SETREDRAW, 0, 0);
  582.       try
  583.         if Value = '' then I := -1 else
  584.           if FEnableValues then I := Values.IndexOf(Value)
  585.           else I := Items.IndexOf(Value);
  586.         if I >= Items.Count then I := -1;
  587.         ItemIndex := I;
  588.       finally
  589.         if Redraw then begin
  590.           SendMessage(Handle, WM_SETREDRAW, 1, 0);
  591.           Invalidate;
  592.         end;
  593.       end;
  594.       if I >= 0 then Exit;
  595.     end;
  596.     if Style in [csDropDown, csSimple] then Text := Value;
  597.   end;
  598. end;
  599.  
  600. procedure TRxDBComboBox.SetEnableValues(Value: Boolean);
  601. begin
  602.   if FEnableValues <> Value then begin
  603.     if Value and (Style in [csDropDown, csSimple]) then
  604.       Style := csDropDownList;
  605.     FEnableValues := Value;
  606.     DataChange(Self);
  607.   end;
  608. end;
  609.  
  610. procedure TRxDBComboBox.SetValues(Value: TStrings);
  611. begin
  612.   FValues.Assign(Value);
  613. end;
  614.  
  615. procedure TRxDBComboBox.SetStyle(Value: TComboboxStyle);
  616. begin
  617.   if (Value in [csSimple, csDropDown]) and FEnableValues then
  618.     Value := csDropDownList;
  619.   inherited SetStyle(Value);
  620. end;
  621.  
  622. end.
  623.