diff --git a/components/jujiboutils/changes.txt b/components/jujiboutils/changes.txt index a5a58bed5..af00e573f 100644 --- a/components/jujiboutils/changes.txt +++ b/components/jujiboutils/changes.txt @@ -5,6 +5,7 @@ Note: Lazarus Trunk required Version pre-1.1 -------------------------------------------------- +2013-08-18 Added: Calendar to Date/Date Time components and grid controls. Bug fixes 2013-06-17 Added: TJDBImageBlob. Display raw images from blob fields (read only) 2013-04-29 Fixed: TJDBGridControl Focus issues 2013-01-03 Added: TJDbEnumCombo, like TDbComboBox but, uses itemindex instead of text diff --git a/components/jujiboutils/jujiboutils.lpk b/components/jujiboutils/jujiboutils.lpk index 97a925acc..7a8a6167a 100644 --- a/components/jujiboutils/jujiboutils.lpk +++ b/components/jujiboutils/jujiboutils.lpk @@ -1,4 +1,4 @@ - + @@ -23,38 +23,38 @@ db and non db controls."/> + + + + - - + + - - + + - - + + - - + + - - + + - - - - diff --git a/components/jujiboutils/jujiboutils.pas b/components/jujiboutils/jujiboutils.pas index 9d97edad5..37d1b0d1c 100644 --- a/components/jujiboutils/jujiboutils.pas +++ b/components/jujiboutils/jujiboutils.pas @@ -7,8 +7,8 @@ unit jujiboutils; interface uses - JDBGridControl, JDBLabeledEdit, jdblabeledintegeredit, JDBLabeledFloatEdit, - jdblabeledcurrencyedit, jdblabeleddateedit, jcontrolutils, + jcontrolutils, JDBGridControl, JDBLabeledEdit, jdblabeledintegeredit, + JDBLabeledFloatEdit, jdblabeledcurrencyedit, jdblabeleddateedit, JLabeledIntegerEdit, JLabeledFloatEdit, JLabeledCurrencyEdit, JLabeledDateEdit, jdbgridutils, JLabeledTimeEdit, JDBLabeledTimeEdit, JLabeledDateTimeEdit, JDBLabeledDateTimeEdit, jinputconsts, JDbEnumCombo, diff --git a/components/jujiboutils/src/jcontrolutils.pas b/components/jujiboutils/src/jcontrolutils.pas index 9daccc2d0..dd4047a96 100644 --- a/components/jujiboutils/src/jcontrolutils.pas +++ b/components/jujiboutils/src/jcontrolutils.pas @@ -22,7 +22,7 @@ unit jcontrolutils; interface uses - Classes, SysUtils, Dialogs; + Classes, SysUtils, Dialogs, LResources; function CountChar(const s: string; ch: char): integer; procedure Split(const Delimiter: char; Input: string; Strings: TStrings); @@ -259,5 +259,31 @@ begin Result := TryStrToDateTime(Value, bTime); end; +initialization + LazarusResources.Add('JCalendarIcon','PNG',[ + #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#16#0#0#0#16#8#6#0#0#0#31#243#255'a' + +#0#0#0#4'gAMA'#0#0#175#200'7'#5#138#233#0#0#0#25'tEXtSoftware'#0'Adobe Image' + +'Readyq'#201'e<'#0#0#1#206'IDAT8'#203#165#147#177'kTA'#16#135#191'w'#247#188 + +#20#167#133#16#13#136#24#21#130' &X'#5'!'#18#4'!`'#149'@'#210#8#150'ZD'#16'[' + +'+Q'#208#210#206'?A'#9'B'#130#130#157#160#16'='#177'Pl'#132' DL#Q'#137'E ' + +#228#240#237#236#204'X'#236'{'#151'w'#24#4#201#194#176#203'2|'#243#251#205 + +#236'f'#238#206'^V'#14#240#232#205#230'mw'#174#169#219'Q3C'#13#162#25#170#134 + +#154#19#213'j'#161'ht'#212#236#253#253'+#'#227'9'#128#185#223#152#29'?0'#248 + +'?'#149#239'<'#249'2'#214'S'#160'f'#131#0#237#165#235#224#14#26#193#20'D'#210 + +'9'#20' '#1#10#1#17#182'o'#189'BD'#7'j'#128#170#15#14'G'#14#129#197#20#30'KH' + +#1'R@'#12#176#242#29#0#137#186#211#3'U+'#1#25#172'o'#128'[Rb'#150#148'h'#181 + +#3'CC'#0#132': '#150#128#133#225'{\>'#127#248#159#222#23#223#173's!'#196'~'#5 + +#162#134#185#147'7S'#210#179'O'#139't'#214#150#185'zn'#158#207'?Wx'#185#250 + +#130#139'#S'#204#140#206'Q'#136#179#213#21#130'$@'#163#178#224'@'#222#204#0 + +#152#25#157#163#27#186#0#252#218#222#224#193#244'C:k'#203#0#20'Q'#9'b'#196'h' + +';'#0'Q'#195#13#242#198#223#146#187#161'K'#171#217#234#1#11#177#178#221'u@4' + +#220#157'}'#165#133#206#215'T'#237#227#183#15#28';8'#204#205#167#243'L'#157 + +#186'D'#149#11#208#30#200'kM'#180't'#217'l$'#11#19'''&'#153'89Y'#206'%c'#250 + +#204',Y'#150#245#1#170#201'%@'#140'x)'#231#241#235#31'ij'#238#136#130#168#18 + +#212#8#146#188#183#154'U1'#250#167#224#238#140#29#223#207'i'#173#222#190#247 + +#254#194'n'#203#204#173#246#144#252#237#221#133#213#179'A'#173'-Q'#145#168'h' + +'4D'#141#168'qW'#192#230#214#239#231#0#217'^'#191#243#31#2'<4&'#179'.'#211 + +#208#0#0#0#0'IEND'#174'B`'#130 +]); end. diff --git a/components/jujiboutils/src/jdbgridutils.pas b/components/jujiboutils/src/jdbgridutils.pas index 8b56ba2b5..f4e513990 100644 --- a/components/jujiboutils/src/jdbgridutils.pas +++ b/components/jujiboutils/src/jdbgridutils.pas @@ -23,7 +23,7 @@ interface uses Classes, SysUtils, Grids, Dialogs, LCLType, DBGrids, Controls, DB, - jcontrolutils, jinputconsts; + jcontrolutils, jinputconsts, CalendarPopup, Calendar, Buttons; type @@ -58,12 +58,16 @@ type theValue: TDateTime; fFormat: string; function getFormat: string; + function EditText: string; procedure myEditEnter(Sender: TObject); procedure myEditOnEditingDone(Sender: TObject); procedure formatInput; procedure setFormat(const AValue: string); procedure OnKeyPress(Sender: TObject; var key: char); procedure OnKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); + protected + procedure ShowCalendar(Sender: TObject); + procedure CalendarPopupReturnDate(Sender: TObject; const ADate: TDateTime); public CellEditor: TStringCellEditor; theGrid: TDBGrid; @@ -116,6 +120,9 @@ type procedure setFormat(const AValue: string); procedure OnKeyPress(Sender: TObject; var key: char); procedure OnKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); + protected + procedure ShowCalendar(Sender: TObject); + procedure CalendarPopupReturnDate(Sender: TObject; const ADate: TDateTime); public CellEditor: TStringCellEditor; theGrid: TDBGrid; @@ -178,7 +185,7 @@ type implementation uses - Math; + Math, dateutils; { TJDbGridStringCtrl } @@ -278,13 +285,22 @@ begin Result := fFormat; end; +function TJDbGridDateTimeCtrl.EditText: string; +begin + if Field.IsNull then + Result := '' + else + Result := FormatDateTime(ShortDateFormat, Field.AsDateTime) + ' ' + + FormatDateTime(ShortTimeFormat, Field.AsDateTime); +end; + procedure TJDbGridDateTimeCtrl.myEditEnter(Sender: TObject); begin Field := theGrid.SelectedField; if not Assigned(Field) then abort; CellEditor.BoundsRect := theGrid.SelectedFieldRect; - CellEditor.Text := Field.AsString; + CellEditor.Text := EditText; CellEditor.OnKeyPress := @OnKeyPress; // Recuperamos el control :-p CellEditor.OnKeyDown := @OnKeyDown; theValue := Field.AsDateTime; @@ -361,6 +377,11 @@ end; procedure TJDbGridDateTimeCtrl.OnKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin + if (ssAlt in Shift) and (key = 40) then + begin + ShowCalendar(Self); + key := 0; + end; if Length(CellEditor.Caption) = 0 then begin if Field.Value <> Null then @@ -417,6 +438,39 @@ begin end; end; +procedure TJDbGridDateTimeCtrl.ShowCalendar(Sender: TObject); +var + PopupOrigin: TPoint; + ADate: TDateTime; +begin + if (not Assigned(Field)) then + exit; + PopupOrigin := CellEditor.ControlToScreen(Point(0, CellEditor.Height)); + if Field.IsNull then + ADate := now + else + ADate := Field.AsDateTime; + ShowCalendarPopup(PopupOrigin, ADate, [dsShowHeadings, dsShowDayNames], + @CalendarPopupReturnDate, nil); +end; + +procedure TJDbGridDateTimeCtrl.CalendarPopupReturnDate(Sender: TObject; + const ADate: TDateTime); +var + bufdate: TDateTime; +begin + if not (Field.DataSet.State in [dsEdit, dsInsert]) then + Field.DataSet.Edit; + if Field.IsNull then + bufdate := now + else + bufdate := Field.AsDateTime; + Field.AsDateTime := + EncodeDateTime(YearOf(ADate), MonthOf(ADate), DayOf(ADate), + HourOf(bufdate), MinuteOf(bufdate), SecondOf(bufdate), MilliSecondOf(bufdate)); + CellEditor.Text := EditText; +end; + function TJDbGridDateTimeCtrl.isNull: boolean; begin Result := theValue = 0; @@ -741,6 +795,11 @@ end; procedure TJDbGridDateCtrl.OnKeyDown(Sender: TObject; var Key: word; Shift: TShiftState); begin + if (ssAlt in Shift) and (key = 40) then + begin + ShowCalendar(Self); + key := 0; + end; if Length(CellEditor.Caption) = 0 then begin if Field.Value <> null then @@ -797,6 +856,39 @@ begin end; end; +procedure TJDbGridDateCtrl.ShowCalendar(Sender: TObject); +var + PopupOrigin: TPoint; + ADate: TDateTime; +begin + if (not Assigned(Field)) then + exit; + PopupOrigin := CellEditor.ControlToScreen(Point(0, CellEditor.Height)); + if Field.IsNull then + ADate := now + else + ADate := Field.AsDateTime; + ShowCalendarPopup(PopupOrigin, ADate, [dsShowHeadings, dsShowDayNames], + @CalendarPopupReturnDate, nil); +end; + +procedure TJDbGridDateCtrl.CalendarPopupReturnDate(Sender: TObject; + const ADate: TDateTime); +var + bufdate: TDateTime; +begin + if not (Field.DataSet.State in [dsEdit, dsInsert]) then + Field.DataSet.Edit; + if Field.IsNull then + bufdate := now + else + bufdate := Field.AsDateTime; + Field.AsDateTime := + EncodeDateTime(YearOf(ADate), MonthOf(ADate), DayOf(ADate), + HourOf(bufdate), MinuteOf(bufdate), SecondOf(bufdate), MilliSecondOf(bufdate)); + CellEditor.Text := Field.AsString; +end; + function TJDbGridDateCtrl.isNull: boolean; begin diff --git a/components/jujiboutils/src/jdblabeleddateedit.pas b/components/jujiboutils/src/jdblabeleddateedit.pas index 31896d86a..c1d315dc6 100644 --- a/components/jujiboutils/src/jdblabeleddateedit.pas +++ b/components/jujiboutils/src/jdblabeleddateedit.pas @@ -23,7 +23,7 @@ interface uses Classes, LResources, Controls, ExtCtrls, DB, DBCtrls, LMessages, LCLType, Dialogs, - SysUtils, jinputconsts; + SysUtils, jinputconsts, CalendarPopup, Calendar, Buttons; type @@ -34,6 +34,13 @@ type 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); @@ -64,6 +71,15 @@ type 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; @@ -76,6 +92,9 @@ type 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; @@ -128,7 +147,7 @@ procedure Register; implementation uses - jcontrolutils; + jcontrolutils, dateutils; procedure Register; begin @@ -138,6 +157,28 @@ 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 @@ -240,6 +281,85 @@ begin 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; @@ -267,6 +387,8 @@ end; procedure TJDBLabeledDateEdit.Loaded; begin inherited Loaded; + DoPositionButton; + CheckButtonVisible; if (csDesigning in ComponentState) then DataChange(Self); end; @@ -275,6 +397,8 @@ 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 @@ -294,6 +418,8 @@ 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; @@ -312,6 +438,8 @@ end; procedure TJDBLabeledDateEdit.KeyPress(var Key: char); begin + if (not Assigned(FDataLink.Field)) or IsReadOnly then + key := #0; if not (Key in ['0'..'9', #8, #9, '.', '-', '/']) then Key := #0 else @@ -336,20 +464,32 @@ begin FDataLink.OnDataChange := @DataChange; FDataLink.OnUpdateData := @UpdateData; FDataLInk.OnActiveChange := @ActiveChange; - // Set default values - //fFormat := ShortDateFormat; + + 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 - FDataLink.Free; - FDataLink := nil; + FreeAndNil(FDataLink); + FreeAndNil(FButton); inherited Destroy; end; procedure TJDBLabeledDateEdit.EditingDone; begin inherited EditingDone; + if (not Assigned(FDataLink.Field)) or IsReadOnly then + exit; if DataSource.State in [dsEdit, dsInsert] then UpdateData(self) else @@ -357,4 +497,3 @@ begin end; end. - diff --git a/components/jujiboutils/src/jdblabeleddatetimeedit.pas b/components/jujiboutils/src/jdblabeleddatetimeedit.pas index 2070376b8..cf6892900 100644 --- a/components/jujiboutils/src/jdblabeleddatetimeedit.pas +++ b/components/jujiboutils/src/jdblabeleddatetimeedit.pas @@ -23,7 +23,7 @@ interface uses Classes, LResources, Controls, ExtCtrls, DB, DBCtrls, LMessages, LCLType, Dialogs, - SysUtils, jinputconsts; + SysUtils, jinputconsts, CalendarPopup, Calendar, Buttons; type @@ -34,6 +34,14 @@ type 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); @@ -44,6 +52,7 @@ type function IsReadOnly: boolean; + function EditText: string; function getFormat: string; procedure setFormat(const AValue: string); procedure formatInput; @@ -62,6 +71,15 @@ type 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; @@ -74,6 +92,9 @@ type 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; + // From TEdit property Action; property Align; @@ -133,7 +154,7 @@ procedure Register; implementation uses - jcontrolutils; + jcontrolutils, dateutils; procedure Register; begin @@ -141,6 +162,28 @@ begin RegisterComponents('Data Controls', [TJDBLabeledDateTimeEdit]); end; +function TJDBLabeledDateTimeEdit.GetButtonWidth: integer; +begin + Result := FButton.Width; +end; + +procedure TJDBLabeledDateTimeEdit.SetButtonWidth(AValue: integer); +begin + FButton.Width := AValue; +end; + +procedure TJDBLabeledDateTimeEdit.WMSetFocus(var Message: TLMSetFocus); +begin + CheckButtonVisible; + inherited; +end; + +procedure TJDBLabeledDateTimeEdit.WMKillFocus(var Message: TLMKillFocus); +begin + CheckButtonVisible; + inherited; +end; + procedure TJDBLabeledDateTimeEdit.DataChange(Sender: TObject); begin if FDataLink.Field <> nil then @@ -148,7 +191,7 @@ begin if not Focused then formatInput else - Caption := FDataLink.Field.AsString; + Caption := EditText; end else Text := ''; @@ -171,7 +214,7 @@ begin else begin ShowMessage(Format(SInvalidDateTime, [Caption])); - Caption := FDataLink.Field.AsString; + Caption := EditText; SelectAll; SetFocus; end; @@ -208,6 +251,15 @@ begin Result := False; end; +function TJDBLabeledDateTimeEdit.EditText: string; +begin + if Field.IsNull then + Result := '' + else + Result := FormatDateTime(ShortDateFormat, FDataLink.Field.AsDateTime) + + ' ' + FormatDateTime(ShortTimeFormat, FDataLink.Field.AsDateTime); +end; + function TJDBLabeledDateTimeEdit.getFormat: string; begin Result := fFormat; @@ -226,7 +278,7 @@ begin if (fFormat <> '') and (not FDataLink.Field.IsNull) then Caption := FormatDateTime(fFormat, FDataLink.Field.AsDateTime) else - Caption := FDataLink.Field.DisplayText + Caption := EditText else Caption := 'nil'; end; @@ -242,6 +294,85 @@ begin FDataLink.ReadOnly := Value; end; +procedure TJDBLabeledDateTimeEdit.SetParent(AParent: TWinControl); +begin + inherited SetParent(AParent); + if FButton <> nil then + begin + DoPositionButton; + CheckButtonVisible; + end; +end; + +procedure TJDBLabeledDateTimeEdit.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 TJDBLabeledDateTimeEdit.CheckButtonVisible; +begin + if Assigned(FButton) then + FButton.Visible := True; +end; + +procedure TJDBLabeledDateTimeEdit.CMVisibleChanged(var Msg: TLMessage); +begin + inherited CMVisibleChanged(Msg); + CheckButtonVisible; +end; + +procedure TJDBLabeledDateTimeEdit.CMEnabledChanged(var Msg: TLMessage); +begin + inherited CMEnabledChanged(Msg); + if (FButton <> nil) then + FButton.Enabled := True; +end; + +procedure TJDBLabeledDateTimeEdit.CMBiDiModeChanged(var Message: TLMessage); +begin + inherited; + DoPositionButton; +end; + +procedure TJDBLabeledDateTimeEdit.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 TJDBLabeledDateTimeEdit.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 TJDBLabeledDateTimeEdit.SetDataField(const Value: string); begin FDataLink.FieldName := Value; @@ -261,6 +392,8 @@ end; procedure TJDBLabeledDateTimeEdit.Loaded; begin inherited Loaded; + DoPositionButton; + CheckButtonVisible; if (csDesigning in ComponentState) then DataChange(Self); end; @@ -269,6 +402,8 @@ procedure TJDBLabeledDateTimeEdit.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 @@ -288,6 +423,8 @@ end; procedure TJDBLabeledDateTimeEdit.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; @@ -306,6 +443,8 @@ end; procedure TJDBLabeledDateTimeEdit.KeyPress(var Key: char); begin + if (not Assigned(FDataLink.Field)) or IsReadOnly then + key := #0; if not (Key in ['0'..'9', #8, #9, '.', '-', '/', ',', ':', ' ']) then Key := #0 else @@ -317,7 +456,7 @@ end; procedure TJDBLabeledDateTimeEdit.DoEnter; begin if FDataLink.Field <> nil then - Caption := FDataLink.Field.AsString; + Caption := EditText; inherited DoEnter; end; @@ -330,20 +469,32 @@ begin FDataLink.OnDataChange := @DataChange; FDataLink.OnUpdateData := @UpdateData; FDataLInk.OnActiveChange := @ActiveChange; - // Set default values - //fFormat := ShortDateFormat; + + 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 TJDBLabeledDateTimeEdit.Destroy; begin - FDataLink.Free; - FDataLink := nil; + FreeAndNil(FDataLink); + FreeAndNil(FButton); inherited Destroy; end; procedure TJDBLabeledDateTimeEdit.EditingDone; begin inherited EditingDone; + if (not Assigned(FDataLink.Field)) or IsReadOnly then + exit; if DataSource.State in [dsEdit, dsInsert] then UpdateData(self) else @@ -352,4 +503,3 @@ end; end. - diff --git a/components/jujiboutils/src/jlabeleddateedit.pas b/components/jujiboutils/src/jlabeleddateedit.pas index d4bac9440..96fc52dff 100644 --- a/components/jujiboutils/src/jlabeleddateedit.pas +++ b/components/jujiboutils/src/jlabeleddateedit.pas @@ -22,7 +22,8 @@ interface uses Classes, SysUtils, LResources, Forms, Controls, ExtCtrls, Graphics, - Dialogs, jcontrolutils, jinputconsts; + Dialogs, Buttons, LMessages, jcontrolutils, jinputconsts, CalendarPopup, + Calendar; type @@ -32,16 +33,33 @@ type private theValue: TDateTime; fFormat: string; + FButton: TSpeedButton; + FButtonNeedsFocus: Boolean; + function GetButtonWidth: Integer; function getFormat: string; function getValue: TDateTime; procedure formatInput; + procedure SetButtonWidth(AValue: Integer); procedure setFormat(const AValue: string); procedure setValue(const AValue: TDateTime); + procedure WMSetFocus(var Message: TLMSetFocus); message LM_SETFOCUS; + procedure WMKillFocus(var Message: TLMKillFocus); message LM_KILLFOCUS; protected { Protected declarations } procedure DoEnter; override; procedure DoExit; override; + procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyPress(var Key: char); override; + procedure SetParent(AParent: TWinControl); override; + procedure DoPositionButton; virtual; + procedure CheckButtonVisible; + procedure Notification(AComponent: TComponent; Operation: TOperation); override; + 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 Loaded; override; + procedure ShowCalendar(Sender: TObject); + procedure CalendarPopupReturnDate(Sender: TObject; const ADate: TDateTime); public { Public declarations } constructor Create(TheOwner: TComponent); override; @@ -51,6 +69,8 @@ type function isNull: boolean; property DisplayFormat: string read getFormat write setFormat; property Value: TDateTime read getValue write setValue; + property Button: TSpeedButton read FButton; + property ButtonWidth : Integer read GetButtonWidth write SetButtonWidth; property Action; property Align; @@ -117,6 +137,11 @@ begin Result := fFormat; end; +function TJLabeledDateEdit.GetButtonWidth: Integer; +begin + Result:= FButton.Width; +end; + function TJLabeledDateEdit.getValue: TDateTime; begin Result := theValue; @@ -128,6 +153,11 @@ begin Text := FormatDateTime(DisplayFormat, theValue); end; +procedure TJLabeledDateEdit.SetButtonWidth(AValue: Integer); +begin + FButton.Width:=AValue; +end; + procedure TJLabeledDateEdit.setFormat(const AValue: string); begin fFormat := AValue; @@ -140,6 +170,18 @@ begin formatInput; end; +procedure TJLabeledDateEdit.WMSetFocus(var Message: TLMSetFocus); +begin + CheckButtonVisible; + inherited; +end; + +procedure TJLabeledDateEdit.WMKillFocus(var Message: TLMKillFocus); +begin + CheckButtonVisible; + inherited; +end; + procedure TJLabeledDateEdit.DoEnter; begin inherited DoEnter; @@ -167,6 +209,13 @@ begin formatInput; end; +procedure TJLabeledDateEdit.KeyDown(var Key: Word; Shift: TShiftState); +begin + inherited KeyDown(Key, Shift); + if (ssAlt in Shift) and (key = 40) then + ShowCalendar(Self); +end; + procedure TJLabeledDateEdit.KeyPress(var Key: char); begin if not (Key in ['0'..'9', #8, #9, '.', '-', '/']) then @@ -174,17 +223,110 @@ begin inherited KeyPress(Key); end; +procedure TJLabeledDateEdit.SetParent(AParent: TWinControl); +begin + inherited SetParent(AParent); + if FButton <> nil then + begin + DoPositionButton; + CheckButtonVisible; + end; +end; + +procedure TJLabeledDateEdit.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 TJLabeledDateEdit.CheckButtonVisible; +begin + If Assigned(FButton) then + FButton.Visible:=True; +end; + +procedure TJLabeledDateEdit.Notification(AComponent: TComponent; + Operation: TOperation); +begin + inherited Notification(AComponent, Operation); + if (AComponent = FButton) and (Operation = opRemove) then + FButton := nil; +end; + +procedure TJLabeledDateEdit.CMVisibleChanged(var Msg: TLMessage); +begin + inherited CMVisibleChanged(Msg); + CheckButtonVisible; +end; + +procedure TJLabeledDateEdit.CMEnabledChanged(var Msg: TLMessage); +begin + inherited CMEnabledChanged(Msg); + if (FButton<>nil) then + FButton.Enabled:=True; +end; + +procedure TJLabeledDateEdit.CMBiDiModeChanged(var Message: TLMessage); +begin + inherited; + DoPositionButton; +end; + +procedure TJLabeledDateEdit.Loaded; +begin + inherited Loaded; + DoPositionButton; + CheckButtonVisible; +end; + +procedure TJLabeledDateEdit.ShowCalendar(Sender: TObject); +var + PopupOrigin: TPoint; + ADate: TDateTime; +begin + PopupOrigin := Self.ControlToScreen(Point(0, Self.Height)); + if isNull then + ADate := now + else + ADate:= Value; + ShowCalendarPopup(PopupOrigin, ADate, [dsShowHeadings, dsShowDayNames], + @CalendarPopupReturnDate, nil); +end; + +procedure TJLabeledDateEdit.CalendarPopupReturnDate(Sender: TObject; + const ADate: TDateTime); +begin + Value:= ADate; +end; + constructor TJLabeledDateEdit.Create(TheOwner: TComponent); begin inherited Create(TheOwner); Text := ''; fFormat := ShortDateFormat; theValue := 0; + 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]; formatInput; end; destructor TJLabeledDateEdit.Destroy; begin + FreeAndNil(FButton); inherited Destroy; end; diff --git a/components/jujiboutils/src/jlabeleddatetimeedit.pas b/components/jujiboutils/src/jlabeleddatetimeedit.pas index 895439a73..3b38201e7 100644 --- a/components/jujiboutils/src/jlabeleddatetimeedit.pas +++ b/components/jujiboutils/src/jlabeleddatetimeedit.pas @@ -25,24 +25,45 @@ interface uses Classes, LResources, Controls, ExtCtrls, LCLType, Dialogs, - SysUtils, jinputconsts; + SysUtils, jinputconsts, CalendarPopup, Calendar, Buttons, LMessages; type + + { TJLabeledDateTimeEdit } + TJLabeledDateTimeEdit = class(TCustomLabeledEdit) private { Private declarations } theValue: TDateTime; fFormat: string; + FButton: TSpeedButton; + FButtonNeedsFocus: boolean; + function GetButtonWidth: integer; function getFormat: string; function getValue: TDateTime; procedure formatInput; + procedure SetButtonWidth(AValue: integer); procedure setFormat(const AValue: string); procedure setValue(const AValue: TDateTime); + procedure WMSetFocus(var Message: TLMSetFocus); message LM_SETFOCUS; + procedure WMKillFocus(var Message: TLMKillFocus); message LM_KILLFOCUS; protected { Protected declarations } procedure DoEnter; override; procedure DoExit; override; + procedure KeyDown(var Key: word; Shift: TShiftState); override; procedure KeyPress(var Key: char); override; + procedure SetParent(AParent: TWinControl); override; + procedure DoPositionButton; virtual; + procedure CheckButtonVisible; + procedure Notification(AComponent: TComponent; Operation: TOperation); override; + 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 Loaded; override; + procedure ShowCalendar(Sender: TObject); + procedure CalendarPopupReturnDate(Sender: TObject; const ADate: TDateTime); + public { Public declarations } constructor Create(TheOwner: TComponent); override; @@ -52,6 +73,8 @@ type function isNull: boolean; property DisplayFormat: string read getFormat write setFormat; property Value: TDateTime read getValue write setValue; + property Button: TSpeedButton read FButton; + property ButtonWidth: integer read GetButtonWidth write SetButtonWidth; property Action; property Align; @@ -106,7 +129,7 @@ procedure Register; implementation uses - jcontrolutils; + jcontrolutils, dateutils; procedure Register; begin @@ -114,6 +137,11 @@ begin RegisterComponents('Additional', [TJLabeledDateTimeEdit]); end; +function TJLabeledDateTimeEdit.GetButtonWidth: integer; +begin + Result := FButton.Width; +end; + function TJLabeledDateTimeEdit.getFormat: string; begin Result := fFormat; @@ -130,6 +158,11 @@ begin Text := FormatDateTime(DisplayFormat, theValue); end; +procedure TJLabeledDateTimeEdit.SetButtonWidth(AValue: integer); +begin + FButton.Width := AValue; +end; + procedure TJLabeledDateTimeEdit.setFormat(const AValue: string); begin fFormat := AValue; @@ -142,6 +175,18 @@ begin formatInput; end; +procedure TJLabeledDateTimeEdit.WMSetFocus(var Message: TLMSetFocus); +begin + CheckButtonVisible; + inherited; +end; + +procedure TJLabeledDateTimeEdit.WMKillFocus(var Message: TLMKillFocus); +begin + CheckButtonVisible; + inherited; +end; + procedure TJLabeledDateTimeEdit.DoEnter; begin inherited DoEnter; @@ -178,6 +223,13 @@ begin formatInput; end; +procedure TJLabeledDateTimeEdit.KeyDown(var Key: word; Shift: TShiftState); +begin + inherited KeyDown(Key, Shift); + if (ssAlt in Shift) and (key = 40) then + ShowCalendar(Self); +end; + procedure TJLabeledDateTimeEdit.KeyPress(var Key: char); begin if not (Key in ['0'..'9', #8, #9, '.', '-', '/', ',', ':', ' ']) then @@ -185,6 +237,95 @@ begin inherited KeyPress(Key); end; +procedure TJLabeledDateTimeEdit.SetParent(AParent: TWinControl); +begin + inherited SetParent(AParent); + if FButton <> nil then + begin + DoPositionButton; + CheckButtonVisible; + end; +end; + +procedure TJLabeledDateTimeEdit.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 TJLabeledDateTimeEdit.CheckButtonVisible; +begin + if Assigned(FButton) then + FButton.Visible := True; +end; + +procedure TJLabeledDateTimeEdit.Notification(AComponent: TComponent; + Operation: TOperation); +begin + inherited Notification(AComponent, Operation); + if (AComponent = FButton) and (Operation = opRemove) then + FButton := nil; +end; + +procedure TJLabeledDateTimeEdit.CMVisibleChanged(var Msg: TLMessage); +begin + inherited CMVisibleChanged(Msg); + CheckButtonVisible; +end; + +procedure TJLabeledDateTimeEdit.CMEnabledChanged(var Msg: TLMessage); +begin + inherited CMEnabledChanged(Msg); + if (FButton <> nil) then + FButton.Enabled := True; +end; + +procedure TJLabeledDateTimeEdit.CMBiDiModeChanged(var Message: TLMessage); +begin + inherited; + DoPositionButton; +end; + +procedure TJLabeledDateTimeEdit.Loaded; +begin + inherited Loaded; + DoPositionButton; + CheckButtonVisible; +end; + +procedure TJLabeledDateTimeEdit.ShowCalendar(Sender: TObject); +var + PopupOrigin: TPoint; + ADate: TDateTime; +begin + PopupOrigin := Self.ControlToScreen(Point(0, Self.Height)); + if isNull then + ADate := Now + else + ADate := Value; + ShowCalendarPopup(PopupOrigin, ADate, [dsShowHeadings, dsShowDayNames], + @CalendarPopupReturnDate, nil); +end; + +procedure TJLabeledDateTimeEdit.CalendarPopupReturnDate(Sender: TObject; + const ADate: TDateTime); +var + bufdate: TDateTime; +begin + if isNull then + bufdate := now + else + bufdate := Value; + Value := EncodeDateTime(YearOf(ADate), MonthOf(ADate), DayOf(ADate), + HourOf(bufdate), MinuteOf(bufdate), SecondOf(bufdate), MilliSecondOf(bufdate)); +end; + constructor TJLabeledDateTimeEdit.Create(TheOwner: TComponent); begin inherited Create(TheOwner); @@ -192,10 +333,22 @@ begin fFormat := ShortDateFormat + ' ' + ShortTimeFormat; theValue := 0; formatInput; + 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 TJLabeledDateTimeEdit.Destroy; begin + FreeAndNil(FButton); inherited Destroy; end; @@ -206,4 +359,3 @@ end; end. -