lazarus-ccr/components/rx/rxdbcomb.pas
2007-08-28 21:55:23 +00:00

521 lines
13 KiB
ObjectPascal

{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1997 Master-Bank }
{ }
{*******************************************************}
unit rxdbcomb;
{$I rx.inc}
interface
uses LCLType, LCLProc, LCLIntf, LMessages, Menus, Graphics, Classes, Controls,
DB, StdCtrls, DbCtrls;
type
{ TCustomDBComboBox }
TCustomDBComboBox = class(TCustomComboBox)
private
FDataLink: TFieldDataLink;
procedure DataChange(Sender: TObject);
procedure EditingChange(Sender: TObject);
function GetDataField: string;
function GetDataSource: TDataSource;
function GetField: TField;
function GetReadOnly: Boolean;
procedure SetDataField(const Value: string);
procedure SetDataSource(Value: TDataSource);
procedure SetEditReadOnly;
procedure SetItems(const Value: TStrings);
procedure SetReadOnly(Value: Boolean);
procedure UpdateData(Sender: TObject);
function GetComboText: string; virtual;
procedure SetComboText(const Value: string); virtual;
protected
procedure EditingDone; override;
procedure Change; override;
procedure Click; override;
procedure CreateWnd; override;
procedure DropDown; override;
function GetPaintText: string; virtual;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyPress(var Key: Char); override;
procedure Loaded; override;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
procedure SetStyle(Value: TComboBoxStyle); override;
procedure WndProc(var Message: TLMessage); override;
property ComboText: string read GetComboText write SetComboText;
property DataField: string read GetDataField write SetDataField;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function ExecuteAction(AAction: TBasicAction): Boolean; override;
function UpdateAction(AAction: TBasicAction): Boolean; override;
function UseRightToLeftAlignment: Boolean;
property Field: TField read GetField;
property Items write SetItems;
property Text;
end;
{ TRxDBComboBox }
TRxDBComboBox = class(TCustomDBComboBox)
private
FValues: TStrings;
FEnableValues: Boolean;
procedure SetEnableValues(Value: Boolean);
procedure SetValues(Value: TStrings);
procedure ValuesChanged(Sender: TObject);
protected
procedure SetStyle(Value: TComboBoxStyle); override;
function GetComboText: string; override;
function GetPaintText: string; override;
procedure SetComboText(const Value: string); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Anchors;
property ArrowKeysTraverseList;
property AutoDropDown;
property BorderSpacing;
property Style; { must be published before Items }
property Color;
property Ctl3D;
property DataField;
property DataSource;
property DragMode;
property DragCursor;
property DropDownCount;
property Enabled;
property EnableValues: Boolean read FEnableValues write SetEnableValues;
property Font;
property Constraints;
property DragKind;
property ItemHeight;
property Items;
property ItemWidth;
property MaxLength default -1;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ReadOnly;
property ShowHint;
property Sorted;
property TabOrder;
property TabStop;
property Values: TStrings read FValues write SetValues;
property Visible;
property OnChange;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDrawItem;
property OnDropDown;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMeasureItem;
property OnStartDrag;
property OnContextPopup;
property OnEndDock;
property OnStartDock;
end;
implementation
uses DBUtils;
{ TCustomDBComboBox }
constructor TCustomDBComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle + [csReplicatable];
FDataLink := TFieldDataLink.Create;
FDataLink.Control := Self;
FDataLink.OnDataChange := @DataChange;
FDataLink.OnUpdateData := @UpdateData;
FDataLink.OnEditingChange := @EditingChange;
end;
destructor TCustomDBComboBox.Destroy;
begin
FDataLink.OnDataChange := nil;
FDataLink.OnUpdateData := nil;
FDataLink.Free;
FDataLink := nil;
inherited Destroy;
end;
procedure TCustomDBComboBox.Loaded;
begin
inherited Loaded;
if (csDesigning in ComponentState) then DataChange(Self);
end;
procedure TCustomDBComboBox.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (FDataLink <> nil) and
(AComponent = DataSource) then DataSource := nil;
end;
procedure TCustomDBComboBox.CreateWnd;
begin
inherited CreateWnd;
SetEditReadOnly;
end;
procedure TCustomDBComboBox.DataChange(Sender: TObject);
begin
if DroppedDown then Exit;
if FDataLink.Field <> nil then ComboText := FDataLink.Field.AsString
else if csDesigning in ComponentState then ComboText := Name
else ComboText := '';
end;
procedure TCustomDBComboBox.UpdateData(Sender: TObject);
begin
FDataLink.Field.Text := ComboText;
FDataLink.Field.AsString := ComboText;
end;
procedure TCustomDBComboBox.SetComboText(const Value: string);
var
I: Integer;
Redraw: Boolean;
begin
if Value <> ComboText then
begin
if Style <> csDropDown then
begin
Redraw := (Style <> csSimple) and HandleAllocated;
// if Redraw then SendMessage(Handle, LM_SETREDRAW, 0, 0);
try
if Value = '' then I := -1 else I := Items.IndexOf(Value);
ItemIndex := I;
finally
if Redraw then
begin
// SendMessage(Handle, WM_SETREDRAW, 1, 0);
Invalidate;
end;
end;
if I >= 0 then Exit;
end;
if Style in [csDropDown, csSimple] then Text := Value;
end;
end;
function TCustomDBComboBox.GetComboText: string;
var
I: Integer;
begin
if Style in [csDropDown, csSimple] then Result := Text
else
begin
I := ItemIndex;
if I < 0 then Result := '' else Result := Items[I];
end;
end;
procedure TCustomDBComboBox.Change;
begin
FDataLink.Edit;
inherited Change;
FDataLink.Modified;
end;
procedure TCustomDBComboBox.Click;
begin
FDataLink.Edit;
inherited Click;
FDataLink.Modified;
end;
procedure TCustomDBComboBox.DropDown;
begin
FDataLink.Edit;
inherited DropDown;
end;
function TCustomDBComboBox.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
procedure TCustomDBComboBox.SetDataSource(Value: TDataSource);
begin
if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
FDataLink.DataSource := Value;
if Value <> nil then Value.FreeNotification(Self);
end;
function TCustomDBComboBox.GetDataField: string;
begin
Result := FDataLink.FieldName;
end;
procedure TCustomDBComboBox.SetDataField(const Value: string);
begin
FDataLink.FieldName := Value;
end;
function TCustomDBComboBox.GetReadOnly: Boolean;
begin
Result := FDataLink.ReadOnly;
end;
procedure TCustomDBComboBox.SetReadOnly(Value: Boolean);
begin
FDataLink.ReadOnly := Value;
end;
function TCustomDBComboBox.GetField: TField;
begin
Result := FDataLink.Field;
end;
procedure TCustomDBComboBox.KeyDown(var Key: Word; Shift: TShiftState);
begin
inherited KeyDown(Key, Shift);
if (Key = VK_BACK) or (Key = VK_DELETE) or (Key = VK_UP) or
(Key = VK_DOWN) or (Key in [32..255]) then
begin
if not FDataLink.Edit and (Key in [VK_UP, VK_DOWN]) then
Key := 0;
end;
end;
procedure TCustomDBComboBox.KeyPress(var Key: Char);
begin
inherited KeyPress(Key);
if (Key in [#32..#255]) and (FDataLink.Field <> nil) and
not FDataLink.Field.IsValidChar(Key) then
begin
// MessageBeep(0);
Key := #0;
end;
case Key of
^H, ^V, ^X, #32..#255:
FDataLink.Edit;
#27:
begin
FDataLink.Reset;
SelectAll;
end;
end;
end;
procedure TCustomDBComboBox.EditingChange(Sender: TObject);
begin
SetEditReadOnly;
end;
procedure TCustomDBComboBox.SetEditReadOnly;
begin
(* if (Style in [csDropDown, csSimple]) and HandleAllocated then
SendMessage({$IFDEF WIN32} EditHandle {$ELSE} FEditHandle {$ENDIF},
EM_SETREADONLY, Ord(not FDataLink.Editing), 0); *)
end;
procedure TCustomDBComboBox.WndProc(var Message: TLMessage);
begin
if not (csDesigning in ComponentState) then
case Message.Msg of
LM_COMMAND:
if TLMCommand(Message).NotifyCode = CBN_SELCHANGE then
if not FDataLink.Edit then begin
{ if Style <> csSimple then
PostMessage(Handle, LB_SHOWDROPDOWN, 0, 0);}
Exit;
end;
{ CB_SHOWDROPDOWN:
if Message.WParam <> 0 then FDataLink.Edit
else if not FDataLink.Editing then DataChange(Self); }{Restore text}
{$IFDEF WIN32}
{ LM_CREATE,
WM_WINDOWPOSCHANGED,
CM_FONTCHANGED:
FPaintControl.DestroyHandle;}
{$ENDIF}
end;
inherited WndProc(Message);
end;
procedure TCustomDBComboBox.EditingDone;
begin
if not(FDataLink.DataSet.State in [dsinsert,dsedit]) then exit;
try
FDataLink.UpdateRecord;
except
SelectAll;
if CanFocus then SetFocus;
raise;
end;
inherited EditingDone;
end;
function TCustomDBComboBox.GetPaintText: string;
begin
if FDataLink.Field <> nil then Result := FDataLink.Field.Text
else Result := '';
end;
procedure TCustomDBComboBox.SetItems(const Value: TStrings);
begin
Items.Assign(Value);
DataChange(Self);
end;
procedure TCustomDBComboBox.SetStyle(Value: TComboBoxStyle);
begin
if (Value = csSimple) and Assigned(FDatalink) and FDatalink.DatasourceFixed then
_DBError('SNotReplicatable');
inherited SetStyle(Value);
end;
function TCustomDBComboBox.UseRightToLeftAlignment: Boolean;
begin
// Result := DBUseRightToLeftAlignment(Self, Field);
end;
function TCustomDBComboBox.ExecuteAction(AAction: TBasicAction): Boolean;
begin
{ Result := inherited ExecuteAction(AAction) or (FDataLink <> nil) and
FDataLink.ExecuteAction(AAction);}
end;
function TCustomDBComboBox.UpdateAction(AAction: TBasicAction): Boolean;
begin
{ Result := inherited UpdateAction(AAction) or (FDataLink <> nil) and
FDataLink.UpdateAction(AAction);}
end;
{ TRxDBComboBox }
constructor TRxDBComboBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FValues := TStringList.Create;
TStringList(FValues).OnChange := @ValuesChanged;
EnableValues := False;
end;
destructor TRxDBComboBox.Destroy;
begin
TStringList(FValues).OnChange := nil;
FValues.Free;
inherited Destroy;
end;
procedure TRxDBComboBox.ValuesChanged(Sender: TObject);
begin
if FEnableValues then DataChange(Self);
end;
function TRxDBComboBox.GetPaintText: string;
var
I: Integer;
begin
Result := '';
if FDataLink.Field <> nil then begin
if FEnableValues then begin
I := Values.IndexOf(FDataLink.Field.Text);
if I >= 0 then Result := Items.Strings[I]
end
else Result := FDataLink.Field.Text;
end;
end;
function TRxDBComboBox.GetComboText: string;
var
I: Integer;
begin
if (Style in [csDropDown, csSimple]) and (not FEnableValues) then
Result := Text
else begin
I := ItemIndex;
if (I < 0) or (FEnableValues and (FValues.Count < I + 1)) then
Result := ''
else
if FEnableValues then Result := FValues[I]
else Result := Items[I];
end;
end;
procedure TRxDBComboBox.SetComboText(const Value: string);
var
I: Integer;
Redraw: Boolean;
begin
if Value <> ComboText then
begin
if Style <> csDropDown then
begin
Redraw := (Style <> csSimple) and HandleAllocated;
// if Redraw then SendMessage(Handle, WM_SETREDRAW, 0, 0);
try
if Value = '' then I := -1
else
if FEnableValues then I := Values.IndexOf(Value)
else I := Items.IndexOf(Value);
if I >= Items.Count then I := -1;
ItemIndex := I;
finally
if Redraw then
begin
// SendMessage(Handle, WM_SETREDRAW, 1, 0);
// Invalidate;
end;
end;
if I >= 0 then Exit;
end;
if Style in [csDropDown, csSimple] then Text := Value;
Invalidate;
end;
end;
procedure TRxDBComboBox.SetEnableValues(Value: Boolean);
begin
if FEnableValues <> Value then
begin
if Value and (Style in [csDropDown, csSimple]) then
Style := csDropDownList;
FEnableValues := Value;
DataChange(Self);
end;
end;
procedure TRxDBComboBox.SetValues(Value: TStrings);
begin
FValues.Assign(Value);
end;
procedure TRxDBComboBox.SetStyle(Value: TComboboxStyle);
begin
if (Value in [csSimple, csDropDown]) and FEnableValues then
Value := csDropDownList;
inherited SetStyle(Value);
end;
end.