{*********************************************************} {* OVCEDCAL.PAS 4.06 *} {*********************************************************} {* ***** BEGIN LICENSE BLOCK ***** *} {* Version: MPL 1.1 *} {* *} {* The contents of this file are subject to the Mozilla Public License *} {* Version 1.1 (the "License"); you may not use this file except in *} {* compliance with the License. You may obtain a copy of the License at *} {* http://www.mozilla.org/MPL/ *} {* *} {* Software distributed under the License is distributed on an "AS IS" basis, *} {* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *} {* for the specific language governing rights and limitations under the *} {* License. *} {* *} {* The Original Code is TurboPower Orpheus *} {* *} {* The Initial Developer of the Original Code is TurboPower Software *} {* *} {* Portions created by TurboPower Software Inc. are Copyright (C)1995-2002 *} {* TurboPower Software Inc. All Rights Reserved. *} {* *} {* Contributor(s): *} {* *} {* ***** END LICENSE BLOCK ***** *} {$I OVC.INC} {$B-} {Complete Boolean Evaluation} {$I+} {Input/Output-Checking} {$P+} {Open Parameters} {$T-} {Typed @ Operator} {.W-} {Windows Stack Frame} {$X+} {Extended Syntax} unit ovcedcal; {-date edit field with popup calendar} interface uses {$IFNDEF LCL} Windows, Messages, {$ELSE} LclIntf, LMessages, LclType, MyMisc, {$ENDIF} Buttons, Classes, Controls, Forms, Graphics, Menus, StdCtrls, SysUtils, {$IFNDEF LCL} {$IFDEF VERSION4} MultiMon, {$ENDIF} {$ENDIF} OvcBase, OvcCal, OvcConst, OvcData, OvcEdPop, OvcExcpt, OvcIntl, OvcMisc, OvcEditF, OvcDate; type TOvcDateOrder = (doMDY, doDMY, doYMD); TOvcRequiredDateField = (rfYear, rfMonth, rfDay); TOvcRequiredDateFields = set of TOvcRequiredDateField; {Events} TOvcGetDateEvent = procedure(Sender : TObject; var Value : string) of object; TOvcPreParseDateEvent = procedure(Sender : TObject; var Value : string) of object; TOvcGetDateMaskEvent = procedure(Sender : TObject; var Mask : string) of object; TOvcCustomDateEdit = class(TOvcEdPopup) protected {private} {property variables} FAllowIncDec : Boolean; FCalendar : TOvcCalendar; FDate : TDateTime; FEpoch : Integer; FForceCentury : Boolean; FRequiredFields : TOvcRequiredDateFields; FTodayString : string; {event variables} FOnGetDate : TOvcGetDateEvent; FOnGetDateMask : TOvcGetDateMaskEvent; FOnPreParseDate : TOvcPreParseDateEvent; FOnSetDate : TNotifyEvent; {internal variables} DateOrder : TOvcDateOrder; HoldCursor : TCursor; PopupClosing : Boolean; WasAutoScroll : Boolean; {property methods} function GetDate : TDateTime; function GetEpoch : Integer; function GetPopupColors : TOvcCalColors; function GetPopupFont : TFont; function GetPopupHeight : Integer; function GetPopupDateFormat : TOvcDateFormat; function GetPopupDayNameWidth : TOvcDayNameWidth; function GetPopupOptions : TOvcCalDisplayOptions; function GetPopupWeekStarts : TOvcDayType; function GetPopupWidth : Integer; function GetReadOnly : Boolean; procedure SetEpoch(Value : Integer); procedure SetForceCentury(Value : Boolean); procedure SetPopupColors(Value : TOvcCalColors); procedure SetPopupFont(Value : TFont); procedure SetPopupHeight(Value : Integer); procedure SetPopupWidth(Value : Integer); procedure SetPopupDateFormat(Value : TOvcDateFormat); procedure SetPopupDayNameWidth(Value : TOvcDayNameWidth); procedure SetPopupOptions(Value : TOvcCalDisplayOptions); procedure SetPopupWeekStarts(Value : TOvcDayType); procedure SetReadOnly(Value : Boolean); {internal methods} function ParseDate(const Value : string) : string; procedure PopupDateChange(Sender : TObject; Date : TDateTime); procedure PopupKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState); procedure PopupKeyPress(Sender : TObject; var Key : Char); procedure PopupMouseDown(Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer); protected procedure DoExit; override; procedure GlyphChanged; override; procedure KeyDown(var Key : Word; Shift : TShiftState); override; procedure KeyPress(var Key : Char); override; procedure SetDate(Value : TDateTime); {protected properties} property AllowIncDec : Boolean read FAllowIncDec write FAllowIncDec; property Epoch : Integer read GetEpoch write SetEpoch; property ForceCentury : Boolean read FForceCentury write SetForceCentury; property PopupColors : TOvcCalColors read GetPopupColors write SetPopupColors; property PopupFont : TFont read GetPopupFont write SetPopupFont; property PopupHeight : Integer read GetPopupHeight write SetPopupHeight; property PopupWidth : Integer read GetPopupWidth write SetPopupWidth; property PopupDateFormat : TOvcDateFormat read GetPopupDateFormat write SetPopupDateFormat; property PopupDayNameWidth : TOvcDayNameWidth read GetPopupDayNameWidth write SetPopupDayNameWidth; property PopupOptions : TOvcCalDisplayOptions read GetPopupOptions write SetPopupOptions; property PopupWeekStarts : TOvcDayType read GetPopupWeekStarts write SetPopupWeekStarts; property ReadOnly : Boolean read GetReadOnly write SetReadOnly; property RequiredFields : TOvcRequiredDateFields read FRequiredFields write FRequiredFields; property TodayString : string read FTodayString write FTodayString; {protected events} property OnGetDate : TOvcGetDateEvent read FOnGetDate write FOnGetDate; property OnGetDateMask : TOvcGetDateMaskEvent read FOnGetDateMask write FOnGetDateMask; property OnPreParseDate : TOvcPreParseDateEvent read FOnPreParseDate write FOnPreParseDate; property OnSetDate : TNotifyEvent read FOnSetDate write FOnSetDate; public constructor Create(AOwner : TComponent); override; function DateString(const Mask : string) : string; function FormatDate(Value : TDateTime) : string; dynamic; procedure PopupClose(Sender : TObject); override; procedure PopupOpen; override; procedure SetDateText(Value : string); dynamic; {public properties} property Calendar : TOvcCalendar read FCalendar; property Date: TDateTime read GetDate write SetDate; end; TOvcDateEdit = class(TOvcCustomDateEdit) published {properties} {$IFDEF VERSION4} property Anchors; property Constraints; property DragKind; {$ENDIF} property About; property AllowIncDec; {$IFNDEF LCL} property AutoSelect; {$ENDIF} property AutoSize; property BorderStyle; property ButtonGlyph; property CharCase; property Color; property Controller; property Ctl3D; property Cursor; property DragCursor; property DragMode; property Enabled; property Epoch; property Font; property ForceCentury; {$IFNDEF LCL} property HideSelection; {$ENDIF} property LabelInfo; property ParentColor; {$IFNDEF LCL} property ParentCtl3D; {$ENDIF} property ParentFont; property ParentShowHint; property PopupAnchor; property PopupColors; property PopupDateFormat; property PopupDayNameWidth; property PopupFont; property PopupHeight; property PopupMenu; property PopupOptions; property PopupWidth; property PopupWeekStarts; property ReadOnly; property RequiredFields; property ShowButton; property ShowHint; property TabOrder; property TabStop; property TodayString; property Visible; {inherited events} property OnChange; property OnClick; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDrag; property OnEnter; property OnExit; property OnGetDate; property OnGetDateMask; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnPopupClose; property OnPopupOpen; property OnPreParseDate; property OnSetDate; property OnStartDrag; end; implementation {*** TOvcCustomDateEdit ***} constructor TOvcCustomDateEdit.Create(AOwner : TComponent); var C : array[0..1] of Char; begin inherited Create(AOwner); ControlStyle := ControlStyle - [csSetCaption]; FAllowIncDec := True; FForceCentury := False; FRequiredFields := [rfMonth, rfDay]; FTodayString := DateSeparator; {get the date order from windows} C[0] := '0'; {default} GetProfileString('intl', 'iDate', '0', C, 2); DateOrder := TOvcDateOrder(Ord(C[0])-Ord('0')); {load button glyph} {$IFNDEF LCL} FButtonGlyph.Handle := LoadBaseBitmap('ORBTNCAL'); {$ELSE} FButtonGlyph.LoadFromLazarusResource('ORBTNCAL'); {$ENDIF} FButton.Glyph.Assign(FButtonGlyph); FCalendar := TOvcCalendar.CreateEx(Self, True); FCalendar.OnChange := PopupDateChange; FCalendar.OnExit := PopupClose; FCalendar.OnKeyDown := PopupKeyDown; FCalendar.OnKeyPress := PopupKeyPress; FCalendar.OnMouseDown := PopupMouseDown; FCalendar.Visible := False; {to avoid flash at 0,0} FCalendar.BorderStyle := bsSingle; FCalendar.ParentFont := False; FCalendar.Parent := GetImmediateParentForm(Self); end; procedure TOvcCustomDateEdit.DoExit; begin try SetDateText(Text); except SetFocus; raise; end; if not PopupActive then inherited DoExit; end; function TOvcCustomDateEdit.DateString(const Mask : string) : string; begin Result := OvcIntlSup.DateToDateString(Mask, DateTimeToSTDate(Date), False); end; function TOvcCustomDateEdit.FormatDate(Value : TDateTime) : string; var DateMask : string; Mask : string; begin DateMask := OvcIntlSup.InternationalDate(FForceCentury); if Assigned(FOnGetDateMask) then begin FOnGetDateMask(Self, DateMask); {see if the date order needs to be changed} Mask := AnsiUpperCase(DateMask); if (Pos('M', Mask) > Pos('Y', Mask)) or (Pos('N', Mask) > Pos('Y', Mask)) then DateOrder := doYMD else if (Pos('M', Mask) > Pos('D', Mask)) or (Pos('N', Mask) > Pos('D', Mask)) then DateOrder := doDMY else DateOrder := doMDY; end; Result := OvcIntlSup.DateToDateString(DateMask, DateTimeToSTDate(Value), False); end; function TOvcCustomDateEdit.GetDate : TDateTime; begin SetDateText(Text); Result := FDate; end; function TOvcCustomDateEdit.GetEpoch : Integer; begin Result := FEpoch; if (csWriting in ComponentState) then Exit; if (Result = 0) and ControllerAssigned then Result := Controller.Epoch; end; function TOvcCustomDateEdit.GetPopupColors : TOvcCalColors; begin Result := FCalendar.Colors; end; function TOvcCustomDateEdit.GetPopupDateFormat : TOvcDateFormat; begin Result := FCalendar.DateFormat; end; function TOvcCustomDateEdit.GetPopupDayNameWidth : TOvcDayNameWidth; begin Result := FCalendar.DayNameWidth; end; function TOvcCustomDateEdit.GetPopupFont : TFont; begin Result := FCalendar.Font; end; function TOvcCustomDateEdit.GetPopupHeight : Integer; begin Result := FCalendar.Height; end; function TOvcCustomDateEdit.GetPopupOptions: TOvcCalDisplayOptions; begin Result := FCalendar.Options; end; function TOvcCustomDateEdit.GetPopupWeekStarts: TOvcDayType; begin Result := FCalendar.WeekStarts; end; function TOvcCustomDateEdit.GetPopupWidth : Integer; begin Result := FCalendar.Width; end; function TOvcCustomDateEdit.GetReadOnly : Boolean; begin Result := inherited ReadOnly; end; procedure TOvcCustomDateEdit.GlyphChanged; begin inherited GlyphChanged; if FButtonGlyph.Empty then {$IFNDEF LCL} FButtonGlyph.Handle := LoadBaseBitmap('ORBTNCAL'); {$ELSE} FButtonGlyph.LoadFromLazarusResource('ORBTNCAL'); {$ENDIF} end; procedure TOvcCustomDateEdit.KeyDown(var Key : Word; Shift : TShiftState); begin inherited KeyDown(Key, Shift); if ShowButton and (Key = VK_DOWN) and (ssAlt in Shift) then PopupOpen; end; procedure TOvcCustomDateEdit.KeyPress(var Key : Char); var D : Word; M : Word; Y : Word; begin inherited KeyPress(Key); if (ReadOnly) then Exit; if FAllowIncDec and (Key in ['+', '-']) then begin {accept current date} DoExit; if FDate = 0 then DecodeDate(SysUtils.Date, Y, M, D) else DecodeDate(FDate, Y, M, D); if Key = '+' then begin Inc(D); if D > DaysInMonth(M, Y, Epoch) then begin D := 1; Inc(M); if M > 12 then begin Inc(Y); M := 1; end; end; end else begin {Key = '-'} Dec(D); if D < 1 then begin Dec(M); if M < 1 then begin M := 12; Dec(Y); end; D := DaysInMonth(M, Y, Epoch); end; end; SetDate(STDateToDateTime(DMYToSTDate(D, M, Y, Epoch))); {clear} Key := #0; end; end; function TOvcCustomDateEdit.ParseDate(const Value : string) : string; var S : string; ThisYear : Word; ThisMonth : Word; ThisDay : Word; DefaultDate : TStDate; Increment : Integer; Occurrence : Integer; StartDate : TStDate; procedure DoSetDate; var I : integer; D : TStDate; DOW : TStDayType; begin D := StartDate; DOW := DayofWeek(DateTimeToStDate(SysUtils.Date)); if Pos(AnsiUppercase(Copy(LongDayNames[1],1,3)), S) > 0 then begin DOW := Sunday; end else if Pos(AnsiUppercase(Copy(LongDayNames[2],1,3)), S) > 0 then begin DOW := Monday; end else if Pos(AnsiUppercase(Copy(LongDayNames[3],1,3)), S) > 0 then begin DOW := Tuesday; end else if Pos(AnsiUppercase(Copy(LongDayNames[4],1,3)), S) > 0 then begin DOW := Wednesday; end else if Pos(AnsiUppercase(Copy(LongDayNames[5],1,3)), S) > 0 then begin DOW := Thursday; end else if Pos(AnsiUppercase(Copy(LongDayNames[6],1,3)), S) > 0 then begin DOW := Friday; end else if Pos(AnsiUppercase(Copy(LongDayNames[7],1,3)), S) > 0 then begin DOW := Saturday; end else begin if DefaultDate > 0 then begin D := DefaultDate; Occurrence := 0; end else if DefaultDate < 0 then begin Result := S; exit; end; end; I := 0; while I < Occurrence do begin D := D + Increment; if DayOfWeek(D) = DOW then begin inc(I); end; end; Result := FormatDate(StDateToDateTime(D)); end; begin {The following code provides the user the ability to enter dates using text descriptions. All descriptions assume the current date as a reference date. The following descriptions are currently supported: Next is assumed; may be abbreviated -- 1st 3 chars Next Last current day of week is assumed Last First | 1st current day of week is assumed First | 1st Second | 2nd current day of week is assumed Second | 2nd Third | 3rd current day of week is assumed Third | 3rd Fourth | 4th current day of week is assumed Fourth | 4th Final | lst current day of week is assumed Final | lst BOM | Begin returns first day of current month EOM | End returns last day of current month Yesterday returns yesterday's date Today returns today's date Tomorrow returns tomorrow's date} S := AnsiUppercase(Value); if Pos(GetOrphStr(SCCalYesterday), S) > 0 then begin Result := FormatDate(StDateToDateTime(DateTimeToStDate(SysUtils.Date) - 1)); end else if Pos(GetOrphStr(SCCalToday), S) > 0 then begin Result := FormatDate(StDateToDateTime(DateTimeToStDate(SysUtils.Date))); end else if Pos(GetOrphStr(SCCalTomorrow), S) > 0 then begin Result := FormatDate(StDateToDateTime(DateTimeToStDate(SysUtils.Date) + 1)); end else if Pos(GetOrphStr(SCCalNext), S) > 0 then begin Increment := 1; Occurrence := 1; StartDate := DateTimeToStDate(SysUtils.Date); DefaultDate := StartDate + 7; DoSetDate; end else if Pos(GetOrphStr(SCCalLast), S) > 0 then begin Increment := -1; Occurrence := 1; StartDate := DateTimeToStDate(SysUtils.Date); DefaultDate := StartDate - 7; DoSetDate; end else if Pos(GetOrphStr(SCCalPrev), S) > 0 then begin Increment := -1; Occurrence := 1; StartDate := DateTimeToStDate(SysUtils.Date); DefaultDate := StartDate - 7; DoSetDate; end else if (Pos(GetOrphStr(SCCalFirst), S) > 0) or (Pos(GetOrphStr(SCCal1st), S) > 0) then begin Increment := 1; Occurrence := 1; DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay); StartDate := DMYToStDate(1, ThisMonth, ThisYear, Epoch) - 1; DefaultDate := 0; DoSetDate; end else if (Pos(GetOrphStr(SCCalSecond), S) > 0) or (Pos(GetOrphStr(SCCal2nd), S) > 0) then begin Increment := 1; Occurrence := 2; DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay); StartDate := DMYToStDate(1, ThisMonth, ThisYear, Epoch) - 1; DefaultDate := 0; DoSetDate; end else if (Pos(GetOrphStr(SCCalThird), S) > 0) or (Pos(GetOrphStr(SCCal3rd), S) > 0) then begin Increment := 1; Occurrence := 3; DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay); StartDate := DMYToStDate(1, ThisMonth, ThisYear, Epoch) - 1; DefaultDate := 0; DoSetDate; end else if (Pos(GetOrphStr(SCCalFourth), S) > 0) or (Pos(GetOrphStr(SCCal4th), S) > 0) then begin Increment := 1; Occurrence := 4; DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay); StartDate := DMYToStDate(1, ThisMonth, ThisYear, Epoch) - 1; DefaultDate := 0; DoSetDate; end else if Pos(GetOrphStr(SCCalFinal), S) > 0 then begin Increment := -1; Occurrence := 1; DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay); StartDate := DMYToStDate(DaysInMonth(ThisMonth, ThisYear, Epoch), ThisMonth, ThisYear, Epoch) + 1; DefaultDate := 0; DoSetDate; end else if (Pos(GetOrphStr(SCCalBOM), S) > 0) or (Pos(GetOrphStr(SCCalBegin), S) > 0) then begin Increment := 0; Occurrence := 0; DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay); StartDate := DMYToStDate(1, ThisMonth, ThisYear, Epoch); DefaultDate := StartDate; DoSetDate; end else if (Pos(GetOrphStr(SCCalEOM), S) > 0) or (Pos(GetOrphStr(SCCalEnd), S) > 0) then begin Increment := 0; Occurrence := 0; DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay); StartDate := DMYToStDate(DaysInMonth(ThisMonth, ThisYear, Epoch), ThisMonth, ThisYear, Epoch); DefaultDate := StartDate; DoSetDate; end else begin Increment := 1; Occurrence := 1; StartDate := DateTimeToStDate(SysUtils.Date); DefaultDate := -1; DoSetDate; end; end; procedure TOvcCustomDateEdit.PopupClose(Sender : TObject); begin if not FCalendar.Visible then {already closed, exit} Exit; if PopupClosing then Exit; {avoid recursion} PopupClosing := True; try inherited PopupClose(Sender); if GetCapture = FCalendar.Handle then ReleaseCapture; SetFocus; {hide the Calendar} FCalendar.Hide; if FCalendar.Parent is TForm then TForm(FCalendar.Parent).AutoScroll := WasAutoScroll; Cursor := HoldCursor; {change parentage so that we control the window handle destruction} FCalendar.Parent := Self; finally PopupClosing := False; end; end; procedure TOvcCustomDateEdit.PopupKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState); var X : Integer; begin case Key of VK_TAB : begin if Shift = [ssShift] then begin PopupClose(Sender); PostMessage(Handle, WM_KeyDown, VK_TAB, Integer(ssShift)); end else if Shift = [] then begin PopupClose(Sender); PostMessage(Handle, WM_KeyDown, VK_TAB, 0); end; end; VK_UP : begin if Shift = [ssAlt] then begin PopupClose(Sender); X := SelStart; SetFocus; SelStart := X; SelLength := 0; end; end; end; end; procedure TOvcCustomDateEdit.PopupKeyPress(Sender : TObject; var Key : Char); var X : Integer; begin case Key of #13, #32, #27 : begin PopupClose(Sender); X := SelStart; SetFocus; SelStart := X; SelLength := 0; end; end; end; procedure TOvcCustomDateEdit.PopupMouseDown(Sender : TObject; Button : TMouseButton; Shift : TShiftState; X, Y : Integer); var P : TPoint; I : Integer; begin P := Point(X,Y); if not PtInRect(FCalendar.ClientRect, P) then PopUpClose(Sender); {convert to our coordinate system} P := ScreenToClient(FCalendar.ClientToScreen(P)); if PtInRect(ClientRect, P) then begin I := SelStart; SetFocus; SelStart := I; SelLength := 0; end; end; procedure TOvcCustomDateEdit.PopupOpen; var P : TPoint; R : TRect; {$IFDEF VERSION4} {$IFNDEF LCL} F : TCustomForm; MonInfo : TMonitorInfo; {$ENDIF} {$ENDIF} begin if FCalendar.Visible then {already popped up, exit} Exit; inherited PopupOpen; {force update of date} DoExit; FCalendar.Parent := GetParentForm(Self); if FCalendar.Parent is TForm then begin WasAutoScroll := TForm(FCalendar.Parent).AutoScroll; TForm(FCalendar.Parent).AutoScroll := False; end; {set 3d to be the same as our own} {$IFNDEF LCL} FCalendar.ParentCtl3D := False; {$ENDIF} FCalendar.Ctl3D := False; {determine the proper position} SystemParametersInfo(SPI_GETWORKAREA, 0, @R, 0); {$IFDEF VERSION4} {$IFNDEF LCL} F := GetParentForm(Self); if Assigned(F) then begin FillChar(MonInfo, SizeOf(MonInfo), #0); MonInfo.cbSize := SizeOf(MonInfo); GetMonitorInfo(F.Monitor.Handle, @MonInfo); R := MonInfo.rcWork; end; {$ENDIF} {$ENDIF} if FPopupAnchor = paLeft then P := ClientToScreen(Point(-3, Height-4)) else {paRight} P := ClientToScreen(Point(Width-FCalendar.Width-1, Height-2)); if not Ctl3D then begin Inc(P.X, 3); Inc(P.Y, 3); end; if P.Y + FCalendar.Height >= R.Bottom then P.Y := P.Y - FCalendar.Height - Height; if P.X + FCalendar.Width >= R.Right then P.X := R.Right - FCalendar.Width - 1; if P.X <= R.Left then P.X := R.Left + 1; MoveWindow(FCalendar.Handle, P.X, P.Y, FCalendar.Width, FCalendar.Height, False); if Text = '' then FCalendar.Date := SysUtils.Date else FCalendar.Date := FDate; HoldCursor := Cursor; Cursor := crArrow; FCalendar.Show; FCalendar.SetFocus; SetCapture(FCalendar.Handle); end; procedure TOvcCustomDateEdit.PopupDateChange(Sender : TObject; Date : TDateTime); begin {get the current value} SetDate(FCalendar.Date); Modified := True; if FCalendar.Browsing then Exit; {hide the Calendar} PopupClose(Sender); SetFocus; SelStart := Length(Text); SelLength := 0; end; procedure TOvcCustomDateEdit.SetDate(Value : TDateTime); begin FDate := Value; Modified := True; if FDate = 0 then Text := '' else Text := FormatDate(FDate); if Assigned(FOnSetDate) then FOnSetDate(Self); end; procedure TOvcCustomDateEdit.SetDateText(Value : string); var Field : Integer; I1 : Integer; I2 : Integer; Error : Integer; ThisYear : Word; ThisMonth : Word; ThisDay : Word; Year : Word; Month : Word; Day : Word; EpochYear : Integer; EpochCent : Integer; StringList : TStringList; FieldOrder : string[3]; S : string; begin if Assigned(FOnPreParseDate) then FOnPreParseDate(Self, Value); Value := ParseDate(Value); if Assigned(FOnGetDate) then FOnGetDate(Self, Value); if (Value = '') and (FRequiredFields <> []) then begin FDate := 0; Text := ''; Exit; end; if AnsiCompareText(Value, TodayString) = 0 then begin SetDate(SysUtils.Date); Text := FormatDate(FDate); end else begin DecodeDate(SysUtils.Date, ThisYear, ThisMonth, ThisDay); Value := AnsiUpperCase(Value); StringList := TStringList.Create; try {parse the string into subfields using a string list to hold the parts} I1 := 1; while (I1 <= Length(Value)) and not (Value[I1] in ['0'..'9', 'A'..'Z']) do Inc(I1); while I1 <= Length(Value) do begin I2 := I1; while (I2 <= Length(Value)) and (Value[I2] in ['0'..'9', 'A'..'Z']) do Inc(I2); StringList.Add(Copy(Value, I1, I2-I1)); while (I2 <= Length(Value)) and not (Value[I2] in ['0'..'9', 'A'..'Z']) do Inc(I2); I1 := I2; end; case DateOrder of doMDY : FieldOrder := 'MDY'; doDMY : FieldOrder := 'DMY'; doYMD : FieldOrder := 'YMD'; end; Year := 0; Month := 0; Day := 0; Error := 0; for Field := 1 to Length(FieldOrder) do begin if StringList.Count > 0 then S := StringList[0] else S := ''; case FieldOrder[Field] of 'M' : begin if (S = '') or (S[1] in ['0'..'9']) then begin {numeric month} try if S = '' then Month := 0 else Month := StrToInt(S); except Month := 0; {error converting month number} Error := SCMonthConvertError; end; if not (Month in [1..12]) then Month := 0; end else begin {one or more letters in month} Month := 0; I1 := 1; S := Copy(S, 1, 3); {error converting month name} Error := SCMonthNameConvertError; repeat if S = AnsiUpperCase(Copy(ShortMonthNames[I1], 1, Length(S))) then begin Month := I1; I1 := 13; Error := 0; end else Inc(I1); until I1 = 13; end; if Month = 0 then begin if rfMonth in FRequiredFields then {month required} Error := SCMonthRequired else Month := ThisMonth; end else if StringList.Count > 0 then StringList.Delete(0); if Error > 0 then Break; end; 'Y' : begin try if S = '' then Year := 0 else Year := StrToInt(S); except Year := 0; {error converting year} Error := SCYearConvertError; end; if (Epoch = 0) and (Year < 100) and (S <> '') then {default to current century if Epoch is zero} Year := Year + (ThisYear div 100 * 100) else if (Epoch > 0) and (Year < 100) and (S <> '') then begin {use epoch} EpochYear := Epoch mod 100; EpochCent := (Epoch div 100) * 100; if (Year < EpochYear) then Inc(Year,EpochCent+100) else Inc(Year,EpochCent); end; if Year = 0 then begin if rfYear in FRequiredFields then {year is required} Error := SCYearRequired else Year := ThisYear; end else if StringList.Count > 0 then StringList.Delete(0); if Error > 0 then Break; end; 'D' : begin try if S = '' then Day := 0 else Day := StrToInt(S); except Day := 0; {error converting day} Error := SCDayConvertError; end; if not (Day in [1..31]) then Day := 0; if Day = 0 then begin if rfDay in FRequiredFields then {day is required} Error := SCDayRequired else Day := ThisDay; end else if StringList.Count > 0 then StringList.Delete(0); if Error > 0 then Break; end; end; end; case Error of SCDayConvertError : if S = '' then raise EOvcException.Create( GetOrphStr(SCInvalidDay) + ' "' + Value + '"') else raise EOvcException.Create( GetOrphStr(SCInvalidDay) + ' "' + S + '"'); SCMonthConvertError : if S = '' then raise EOvcException.Create( GetOrphStr(SCInvalidMonth) + ' "' + Value + '"') else raise EOvcException.Create( GetOrphStr(SCInvalidMonth) + ' "' + S + '"'); SCMonthNameConvertError : if S = '' then raise EOvcException.Create( GetOrphStr(SCInvalidMonthName) + ' "' + Value + '"') else raise EOvcException.Create( GetOrphStr(SCInvalidMonthName) + ' "' + S + '"'); SCYearConvertError : if S = '' then raise EOvcException.Create( GetOrphStr(SCInvalidYear) + ' "' + Value + '"') else raise EOvcException.Create( GetOrphStr(SCInvalidYear) + ' "' + S + '"'); SCDayRequired : raise EOvcException.Create( GetOrphStr(SCDayRequired)); SCMonthRequired : raise EOvcException.Create( GetOrphStr(SCMonthRequired)); SCYearRequired : raise EOvcException.Create( GetOrphStr(SCYearRequired)); end; try SetDate(STDatetoDateTime(DMYToStDate(Day, Month, Year, Epoch))); Text := FormatDate(FDate); except raise EOvcException.Create( GetOrphStr(SCInvalidDate) + ' "' + Value + '"'); end; finally StringList.Free; end; end; end; procedure TOvcCustomDateEdit.SetEpoch(Value : Integer); begin if Value <> FEpoch then if (Value = 0) or ((Value >= MinYear) and (Value <= MaxYear)) then FEpoch := Value; end; procedure TOvcCustomDateEdit.SetForceCentury(Value : Boolean); begin if Value <> FForceCentury then begin FForceCentury := Value; SetDate(FCalendar.Date); end; end; procedure TOvcCustomDateEdit.SetPopupColors(Value : TOvcCalColors); begin FCalendar.Colors := Value; end; procedure TOvcCustomDateEdit.SetPopupDateFormat(Value : TOvcDateFormat); begin FCalendar.DateFormat := Value; end; procedure TOvcCustomDateEdit.SetPopupFont(Value : TFont); begin if Assigned(Value) then FCalendar.Font.Assign(Value); end; procedure TOvcCustomDateEdit.SetPopupHeight(Value : Integer); begin FCalendar.Height := Value; end; procedure TOvcCustomDateEdit.SetPopupDayNameWidth(Value : TOvcDayNameWidth); begin FCalendar.DayNameWidth := Value; end; procedure TOvcCustomDateEdit.SetPopupOptions(Value : TOvcCalDisplayOptions); begin FCalendar.Options := Value; end; procedure TOvcCustomDateEdit.SetPopupWidth(Value : Integer); begin FCalendar.Width := Value; end; procedure TOvcCustomDateEdit.SetPopupWeekStarts(Value : TOvcDayType); begin FCalendar.WeekStarts := Value; end; procedure TOvcCustomDateEdit.SetReadOnly(Value : Boolean); begin inherited ReadOnly := Value; FButton.Enabled := not ReadOnly; end; end.