You've already forked lazarus-ccr
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2850 8e941d3f-bd1b-0410-a28a-d453659cc2b4
499 lines
12 KiB
ObjectPascal
499 lines
12 KiB
ObjectPascal
{ jdblabeleddateedit
|
|
|
|
Copyright (C) 2011 Julio Jiménez Borreguero
|
|
Contact: jujibo at gmail dot com
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the same terms as the Lazarus Component Library (LCL)
|
|
|
|
See the file license-jujiboutils.txt and COPYING.LGPL, included in this distribution,
|
|
for details about the license.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
}
|
|
|
|
unit jdblabeleddateedit;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, LResources, Controls, ExtCtrls, DB, DBCtrls, LMessages, LCLType, Dialogs,
|
|
SysUtils, jinputconsts, CalendarPopup, Calendar, Buttons;
|
|
|
|
type
|
|
|
|
{ TJDBLabeledDateEdit }
|
|
|
|
TJDBLabeledDateEdit = class(TCustomLabeledEdit)
|
|
private
|
|
fFormat: string;
|
|
FDataLink: TFieldDataLink;
|
|
|
|
FButton: TSpeedButton;
|
|
FButtonNeedsFocus: boolean;
|
|
function GetButtonWidth: integer;
|
|
procedure SetButtonWidth(AValue: integer);
|
|
procedure WMSetFocus(var Message: TLMSetFocus); message LM_SETFOCUS;
|
|
procedure WMKillFocus(var Message: TLMKillFocus); message LM_KILLFOCUS;
|
|
|
|
procedure DataChange(Sender: TObject);
|
|
procedure UpdateData(Sender: TObject);
|
|
procedure FocusRequest(Sender: TObject);
|
|
|
|
function GetDataField: string;
|
|
function GetDataSource: TDataSource;
|
|
function GetField: TField;
|
|
|
|
function IsReadOnly: boolean;
|
|
|
|
function getFormat: string;
|
|
procedure setFormat(const AValue: string);
|
|
procedure formatInput;
|
|
|
|
procedure SetDataField(const Value: string);
|
|
procedure SetDataSource(Value: TDataSource);
|
|
procedure CMGetDataLink(var Message: TLMessage); message CM_GETDATALINK;
|
|
|
|
function IsValidCurrency(const Value: string): boolean;
|
|
|
|
protected
|
|
procedure Loaded; override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure ActiveChange(Sender: TObject); virtual;
|
|
procedure KeyDown(var Key: word; Shift: TShiftState); override;
|
|
procedure KeyPress(var Key: char); override;
|
|
procedure DoEnter; override;
|
|
function GetReadOnly: boolean; override;
|
|
procedure SetReadOnly(Value: boolean); override;
|
|
|
|
procedure SetParent(AParent: TWinControl); override;
|
|
procedure DoPositionButton; virtual;
|
|
procedure CheckButtonVisible;
|
|
procedure CMVisibleChanged(var Msg: TLMessage); message CM_VISIBLECHANGED;
|
|
procedure CMEnabledChanged(var Msg: TLMessage); message CM_ENABLEDCHANGED;
|
|
procedure CMBiDiModeChanged(var Message: TLMessage); message CM_BIDIMODECHANGED;
|
|
procedure ShowCalendar(Sender: TObject);
|
|
procedure CalendarPopupReturnDate(Sender: TObject; const ADate: TDateTime);
|
|
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure EditingDone; override;
|
|
property Field: TField read GetField;
|
|
|
|
published
|
|
property DisplayFormat: string read getFormat write setFormat;
|
|
property DataField: string read GetDataField write SetDataField;
|
|
property DataSource: TDataSource read GetDataSource write SetDataSource;
|
|
property ReadOnly: boolean read GetReadOnly write SetReadOnly default False;
|
|
|
|
property Button: TSpeedButton read FButton;
|
|
property ButtonWidth: integer read GetButtonWidth write SetButtonWidth;
|
|
|
|
property Action;
|
|
property Align;
|
|
property Alignment;
|
|
property Anchors;
|
|
property AutoSelect;
|
|
property AutoSize;
|
|
property BidiMode;
|
|
property BorderSpacing;
|
|
property BorderStyle;
|
|
property CharCase;
|
|
property Color;
|
|
property Constraints;
|
|
property DragCursor;
|
|
property DragMode;
|
|
property EditLabel;
|
|
property Enabled;
|
|
property Font;
|
|
property LabelPosition;
|
|
property LabelSpacing;
|
|
property MaxLength;
|
|
property ParentColor;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property PopupMenu;
|
|
property ShowHint;
|
|
property TabOrder;
|
|
property TabStop;
|
|
property Visible;
|
|
property OnChange;
|
|
property OnClick;
|
|
property OnDblClick;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnEditingDone;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnStartDrag;
|
|
property OnUTF8KeyPress;
|
|
end;
|
|
|
|
procedure Register;
|
|
|
|
implementation
|
|
|
|
uses
|
|
jcontrolutils, dateutils, jdbutils;
|
|
|
|
procedure Register;
|
|
begin
|
|
{$I ldatedbicon.lrs}
|
|
RegisterComponents('JujiboDB', [TJDBLabeledDateEdit]);
|
|
end;
|
|
|
|
{ TJDBLabeledDateEdit }
|
|
|
|
function TJDBLabeledDateEdit.GetButtonWidth: integer;
|
|
begin
|
|
Result := FButton.Width;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.SetButtonWidth(AValue: integer);
|
|
begin
|
|
FButton.Width := AValue;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.WMSetFocus(var Message: TLMSetFocus);
|
|
begin
|
|
CheckButtonVisible;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.WMKillFocus(var Message: TLMKillFocus);
|
|
begin
|
|
CheckButtonVisible;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.DataChange(Sender: TObject);
|
|
begin
|
|
if FDataLink.Field <> nil then
|
|
begin
|
|
if not Focused then
|
|
formatInput
|
|
else
|
|
Caption := FDataLink.Field.AsString;
|
|
end
|
|
else
|
|
Text := '';
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.UpdateData(Sender: TObject);
|
|
var
|
|
theValue: string;
|
|
begin
|
|
if FDataLink.Field <> nil then
|
|
begin
|
|
theValue := NormalizeDate(Text, FDataLink.Field.AsDateTime);
|
|
if Text = '' then
|
|
FDataLink.Field.Text := Text
|
|
else
|
|
if IsValidDateString(theValue) then
|
|
begin
|
|
FDataLink.Field.Text := theValue;
|
|
end
|
|
else
|
|
begin
|
|
ShowMessage(Format(SInvalidDate, [Caption]));
|
|
Caption := FDataLink.Field.AsString;
|
|
SelectAll;
|
|
SetFocus;
|
|
end;
|
|
end
|
|
else
|
|
Text := '';
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.FocusRequest(Sender: TObject);
|
|
begin
|
|
SetFocus;
|
|
end;
|
|
|
|
function TJDBLabeledDateEdit.GetDataField: string;
|
|
begin
|
|
Result := FDataLink.FieldName;
|
|
end;
|
|
|
|
function TJDBLabeledDateEdit.GetDataSource: TDataSource;
|
|
begin
|
|
Result := FDataLink.DataSource;
|
|
end;
|
|
|
|
function TJDBLabeledDateEdit.GetField: TField;
|
|
begin
|
|
Result := FDataLink.Field;
|
|
end;
|
|
|
|
function TJDBLabeledDateEdit.IsReadOnly: boolean;
|
|
begin
|
|
if FDatalink.Active then
|
|
Result := not FDatalink.CanModify
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function TJDBLabeledDateEdit.getFormat: string;
|
|
begin
|
|
Result := fFormat;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.setFormat(const AValue: string);
|
|
begin
|
|
fFormat := AValue;
|
|
if not Focused then
|
|
formatInput;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.formatInput;
|
|
begin
|
|
if FDataLink.Field <> nil then
|
|
//FDataLink.Field.DisplayText -> formatted (tdbgridcolumns/persistent field DisplayFormat
|
|
if (fFormat <> '') and (not FDataLink.Field.IsNull) then
|
|
Caption := FormatDateTime(fFormat, FDataLink.Field.AsDateTime)
|
|
else
|
|
Caption := FDataLink.Field.DisplayText
|
|
else
|
|
Caption := 'nil';
|
|
end;
|
|
|
|
function TJDBLabeledDateEdit.GetReadOnly: boolean;
|
|
begin
|
|
Result := FDataLink.ReadOnly;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.SetReadOnly(Value: boolean);
|
|
begin
|
|
inherited;
|
|
FDataLink.ReadOnly := Value;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.SetParent(AParent: TWinControl);
|
|
begin
|
|
inherited SetParent(AParent);
|
|
if FButton <> nil then
|
|
begin
|
|
DoPositionButton;
|
|
CheckButtonVisible;
|
|
end;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.DoPositionButton;
|
|
begin
|
|
if FButton = nil then
|
|
exit;
|
|
FButton.Parent := Parent;
|
|
FButton.Visible := True;
|
|
if BiDiMode = bdLeftToRight then
|
|
FButton.AnchorToCompanion(akLeft, 0, Self)
|
|
else
|
|
FButton.AnchorToCompanion(akRight, 0, Self);
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.CheckButtonVisible;
|
|
begin
|
|
if Assigned(FButton) then
|
|
FButton.Visible := True;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.CMVisibleChanged(var Msg: TLMessage);
|
|
begin
|
|
inherited CMVisibleChanged(Msg);
|
|
CheckButtonVisible;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.CMEnabledChanged(var Msg: TLMessage);
|
|
begin
|
|
inherited CMEnabledChanged(Msg);
|
|
if (FButton <> nil) then
|
|
FButton.Enabled := True;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.CMBiDiModeChanged(var Message: TLMessage);
|
|
begin
|
|
inherited;
|
|
DoPositionButton;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.ShowCalendar(Sender: TObject);
|
|
var
|
|
PopupOrigin: TPoint;
|
|
ADate: TDateTime;
|
|
begin
|
|
if (not Assigned(FDataLink.Field)) or IsReadOnly then
|
|
exit;
|
|
PopupOrigin := Self.ControlToScreen(Point(0, Self.Height));
|
|
if FDataLink.Field.IsNull then
|
|
ADate := now
|
|
else
|
|
ADate := FDataLink.Field.AsDateTime;
|
|
ShowCalendarPopup(PopupOrigin, ADate, [dsShowHeadings, dsShowDayNames],
|
|
@CalendarPopupReturnDate, nil);
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.CalendarPopupReturnDate(Sender: TObject;
|
|
const ADate: TDateTime);
|
|
var
|
|
bufdate: TDateTime;
|
|
begin
|
|
if not (DataSource.State in [dsEdit, dsInsert]) then
|
|
DataSource.Edit;
|
|
if FDataLink.Field.IsNull then
|
|
bufdate := now
|
|
else
|
|
bufdate := FDataLink.Field.AsDateTime;
|
|
FDataLink.Field.AsDateTime :=
|
|
EncodeDateTime(YearOf(ADate), MonthOf(ADate), DayOf(ADate),
|
|
HourOf(bufdate), MinuteOf(bufdate), SecondOf(bufdate), MilliSecondOf(bufdate));
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.SetDataField(const Value: string);
|
|
begin
|
|
FDataLink.FieldName := Value;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.SetDataSource(Value: TDataSource);
|
|
begin
|
|
if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
|
|
ChangeDataSource(Self, FDataLink, Value);
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.CMGetDataLink(var Message: TLMessage);
|
|
begin
|
|
Message.Result := PtrUInt(FDataLink); // Delphi dbctrls compatibility?
|
|
end;
|
|
|
|
function TJDBLabeledDateEdit.IsValidCurrency(const Value: string): boolean;
|
|
begin
|
|
if StrToCurrDef(Value, MaxCurrency) = MaxCurrency then
|
|
Result := False
|
|
else
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.Loaded;
|
|
begin
|
|
inherited Loaded;
|
|
DoPositionButton;
|
|
CheckButtonVisible;
|
|
if (csDesigning in ComponentState) then
|
|
DataChange(Self);
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if (AComponent = FButton) and (Operation = opRemove) then
|
|
FButton := nil;
|
|
// clean up
|
|
if (Operation = opRemove) then
|
|
begin
|
|
if (FDataLink <> nil) and (AComponent = DataSource) then
|
|
DataSource := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.ActiveChange(Sender: TObject);
|
|
begin
|
|
if FDatalink.Active then
|
|
datachange(Sender)
|
|
else
|
|
Text := '';
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.KeyDown(var Key: word; Shift: TShiftState);
|
|
begin
|
|
inherited KeyDown(Key, Shift);
|
|
if (ssAlt in Shift) and (key = 40) then
|
|
ShowCalendar(Self);
|
|
if Key = VK_ESCAPE then
|
|
begin
|
|
FDataLink.Reset;
|
|
SelectAll;
|
|
Key := VK_UNKNOWN;
|
|
end
|
|
else
|
|
if Key in [VK_DELETE, VK_BACK] then
|
|
begin
|
|
if not IsReadOnly then
|
|
FDatalink.Edit
|
|
else
|
|
Key := VK_UNKNOWN;
|
|
end;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.KeyPress(var Key: char);
|
|
begin
|
|
if not FieldIsEditable(Field) or not FDatalink.Edit then
|
|
Key := #0;
|
|
if not (Key in ['0'..'9', #8, #9, '.', '-', '/']) then
|
|
Key := #0;
|
|
inherited KeyPress(Key);
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.DoEnter;
|
|
begin
|
|
if not FieldIsEditable(Field) or IsReadOnly then
|
|
exit;
|
|
if FDataLink.Field <> nil then
|
|
Caption := FDataLink.Field.AsString;
|
|
inherited DoEnter;
|
|
end;
|
|
|
|
constructor TJDBLabeledDateEdit.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
ControlStyle := ControlStyle + [csReplicatable];
|
|
FDataLink := TFieldDataLink.Create;
|
|
FDataLink.Control := Self;
|
|
FDataLink.OnDataChange := @DataChange;
|
|
FDataLink.OnUpdateData := @UpdateData;
|
|
FDataLInk.OnActiveChange := @ActiveChange;
|
|
|
|
FButton := TSpeedButton.Create(self);
|
|
FButton.Height := Self.Height;
|
|
FButton.FreeNotification(Self);
|
|
CheckButtonVisible;
|
|
FButton.Cursor := crArrow;
|
|
FButton.Flat := False;
|
|
|
|
FButton.OnClick := @ShowCalendar;
|
|
FButton.ControlStyle := FButton.ControlStyle + [csNoDesignSelectable];
|
|
FButton.LoadGlyphFromLazarusResource('JCalendarIcon');
|
|
ControlStyle := ControlStyle - [csSetCaption];
|
|
end;
|
|
|
|
destructor TJDBLabeledDateEdit.Destroy;
|
|
begin
|
|
FreeAndNil(FDataLink);
|
|
FreeAndNil(FButton);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJDBLabeledDateEdit.EditingDone;
|
|
begin
|
|
if not FieldIsEditable(Field) or IsReadOnly then
|
|
exit;
|
|
if DataSource.State in [dsEdit, dsInsert] then
|
|
UpdateData(self)
|
|
else
|
|
formatInput;
|
|
inherited EditingDone;
|
|
end;
|
|
|
|
end.
|